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