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 16from errno import * 17import os 18import posix 19import stat 20import sys 21 22import fuse 23from fuse import FUSE, FuseOSError, Operations 24 25 26sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python')) 27from qemu.qmp import QEMUMonitorProtocol 28 29 30fuse.fuse_python_api = (0, 2) 31 32class QOMFS(Operations): 33 def __init__(self, qmp): 34 self.qmp = qmp 35 self.qmp.connect() 36 self.ino_map = {} 37 self.ino_count = 1 38 39 def get_ino(self, path): 40 if path in self.ino_map: 41 return self.ino_map[path] 42 self.ino_map[path] = self.ino_count 43 self.ino_count += 1 44 return self.ino_map[path] 45 46 def is_object(self, path): 47 try: 48 items = self.qmp.command('qom-list', path=path) 49 return True 50 except: 51 return False 52 53 def is_property(self, path): 54 path, prop = path.rsplit('/', 1) 55 if path == '': 56 path = '/' 57 try: 58 for item in self.qmp.command('qom-list', path=path): 59 if item['name'] == prop: 60 return True 61 return False 62 except: 63 return False 64 65 def is_link(self, path): 66 path, prop = path.rsplit('/', 1) 67 if path == '': 68 path = '/' 69 try: 70 for item in self.qmp.command('qom-list', path=path): 71 if item['name'] == prop: 72 if item['type'].startswith('link<'): 73 return True 74 return False 75 return False 76 except: 77 return False 78 79 def read(self, path, length, offset, fh): 80 if not self.is_property(path): 81 return -ENOENT 82 83 path, prop = path.rsplit('/', 1) 84 if path == '': 85 path = '/' 86 try: 87 data = self.qmp.command('qom-get', path=path, property=prop) 88 data += '\n' # make values shell friendly 89 except: 90 raise FuseOSError(EPERM) 91 92 if offset > len(data): 93 return '' 94 95 return bytes(data[offset:][:length], encoding='utf-8') 96 97 def readlink(self, path): 98 if not self.is_link(path): 99 return False 100 path, prop = path.rsplit('/', 1) 101 prefix = '/'.join(['..'] * (len(path.split('/')) - 1)) 102 return prefix + str(self.qmp.command('qom-get', path=path, 103 property=prop)) 104 105 def getattr(self, path, fh=None): 106 if self.is_link(path): 107 value = { 'st_mode': 0o755 | stat.S_IFLNK, 108 'st_ino': self.get_ino(path), 109 'st_dev': 0, 110 'st_nlink': 2, 111 'st_uid': 1000, 112 'st_gid': 1000, 113 'st_size': 4096, 114 'st_atime': 0, 115 'st_mtime': 0, 116 'st_ctime': 0 } 117 elif self.is_object(path): 118 value = { 'st_mode': 0o755 | stat.S_IFDIR, 119 'st_ino': self.get_ino(path), 120 'st_dev': 0, 121 'st_nlink': 2, 122 'st_uid': 1000, 123 'st_gid': 1000, 124 'st_size': 4096, 125 'st_atime': 0, 126 'st_mtime': 0, 127 'st_ctime': 0 } 128 elif self.is_property(path): 129 value = { 'st_mode': 0o644 | stat.S_IFREG, 130 'st_ino': self.get_ino(path), 131 'st_dev': 0, 132 'st_nlink': 1, 133 'st_uid': 1000, 134 'st_gid': 1000, 135 'st_size': 4096, 136 'st_atime': 0, 137 'st_mtime': 0, 138 'st_ctime': 0 } 139 else: 140 raise FuseOSError(ENOENT) 141 return value 142 143 def readdir(self, path, fh): 144 yield '.' 145 yield '..' 146 for item in self.qmp.command('qom-list', path=path): 147 yield str(item['name']) 148 149if __name__ == '__main__': 150 import os 151 152 fuse = FUSE(QOMFS(QEMUMonitorProtocol(os.environ['QMP_SOCKET'])), 153 sys.argv[1], foreground=True) 154