xref: /qemu/scripts/qmp/qom-fuse (revision abff1abf)
1#!/usr/bin/env python3
2##
3# QEMU Object Model test tools
4#
5# Copyright IBM, Corp. 2012
6#
7# Authors:
8#  Anthony Liguori   <aliguori@us.ibm.com>
9#
10# This work is licensed under the terms of the GNU GPL, version 2 or later.  See
11# the COPYING file in the top-level directory.
12##
13
14import fuse, stat
15from fuse import Fuse
16import os, posix
17from errno import *
18
19sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python'))
20from qemu.qmp import QEMUMonitorProtocol
21
22fuse.fuse_python_api = (0, 2)
23
24class QOMFS(Fuse):
25    def __init__(self, qmp, *args, **kwds):
26        Fuse.__init__(self, *args, **kwds)
27        self.qmp = qmp
28        self.qmp.connect()
29        self.ino_map = {}
30        self.ino_count = 1
31
32    def get_ino(self, path):
33        if path in self.ino_map:
34            return self.ino_map[path]
35        self.ino_map[path] = self.ino_count
36        self.ino_count += 1
37        return self.ino_map[path]
38
39    def is_object(self, path):
40        try:
41            items = self.qmp.command('qom-list', path=path)
42            return True
43        except:
44            return False
45
46    def is_property(self, path):
47        try:
48            path, prop = path.rsplit('/', 1)
49            for item in self.qmp.command('qom-list', path=path):
50                if item['name'] == prop:
51                    return True
52            return False
53        except:
54            return False
55
56    def is_link(self, path):
57        try:
58            path, prop = path.rsplit('/', 1)
59            for item in self.qmp.command('qom-list', path=path):
60                if item['name'] == prop:
61                    if item['type'].startswith('link<'):
62                        return True
63                    return False
64            return False
65        except:
66            return False
67
68    def read(self, path, length, offset):
69        if not self.is_property(path):
70            return -ENOENT
71
72        path, prop = path.rsplit('/', 1)
73        try:
74            data = str(self.qmp.command('qom-get', path=path, property=prop))
75            data += '\n' # make values shell friendly
76        except:
77            return -EPERM
78
79        if offset > len(data):
80            return ''
81
82        return str(data[offset:][:length])
83
84    def readlink(self, path):
85        if not self.is_link(path):
86            return False
87        path, prop = path.rsplit('/', 1)
88        prefix = '/'.join(['..'] * (len(path.split('/')) - 1))
89        return prefix + str(self.qmp.command('qom-get', path=path,
90                                             property=prop))
91
92    def getattr(self, path):
93        if self.is_link(path):
94            value = posix.stat_result((0o755 | stat.S_IFLNK,
95                                       self.get_ino(path),
96                                       0,
97                                       2,
98                                       1000,
99                                       1000,
100                                       4096,
101                                       0,
102                                       0,
103                                       0))
104        elif self.is_object(path):
105            value = posix.stat_result((0o755 | stat.S_IFDIR,
106                                       self.get_ino(path),
107                                       0,
108                                       2,
109                                       1000,
110                                       1000,
111                                       4096,
112                                       0,
113                                       0,
114                                       0))
115        elif self.is_property(path):
116            value = posix.stat_result((0o644 | stat.S_IFREG,
117                                       self.get_ino(path),
118                                       0,
119                                       1,
120                                       1000,
121                                       1000,
122                                       4096,
123                                       0,
124                                       0,
125                                       0))
126        else:
127            value = -ENOENT
128        return value
129
130    def readdir(self, path, offset):
131        yield fuse.Direntry('.')
132        yield fuse.Direntry('..')
133        for item in self.qmp.command('qom-list', path=path):
134            yield fuse.Direntry(str(item['name']))
135
136if __name__ == '__main__':
137    import sys, os
138
139    fs = QOMFS(QEMUMonitorProtocol(os.environ['QMP_SOCKET']))
140    fs.main(sys.argv)
141