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 path, prop = path.rsplit('/', 1) 49 if path == '': 50 path = '/' 51 try: 52 for item in self.qmp.command('qom-list', path=path): 53 if item['name'] == prop: 54 return True 55 return False 56 except: 57 return False 58 59 def is_link(self, path): 60 path, prop = path.rsplit('/', 1) 61 if path == '': 62 path = '/' 63 try: 64 for item in self.qmp.command('qom-list', path=path): 65 if item['name'] == prop: 66 if item['type'].startswith('link<'): 67 return True 68 return False 69 return False 70 except: 71 return False 72 73 def read(self, path, length, offset, fh): 74 if not self.is_property(path): 75 return -ENOENT 76 77 path, prop = path.rsplit('/', 1) 78 if path == '': 79 path = '/' 80 try: 81 data = self.qmp.command('qom-get', path=path, property=prop) 82 data += '\n' # make values shell friendly 83 except: 84 raise FuseOSError(EPERM) 85 86 if offset > len(data): 87 return '' 88 89 return bytes(data[offset:][:length], encoding='utf-8') 90 91 def readlink(self, path): 92 if not self.is_link(path): 93 return False 94 path, prop = path.rsplit('/', 1) 95 prefix = '/'.join(['..'] * (len(path.split('/')) - 1)) 96 return prefix + str(self.qmp.command('qom-get', path=path, 97 property=prop)) 98 99 def getattr(self, path, fh=None): 100 if self.is_link(path): 101 value = { 'st_mode': 0o755 | stat.S_IFLNK, 102 'st_ino': self.get_ino(path), 103 'st_dev': 0, 104 'st_nlink': 2, 105 'st_uid': 1000, 106 'st_gid': 1000, 107 'st_size': 4096, 108 'st_atime': 0, 109 'st_mtime': 0, 110 'st_ctime': 0 } 111 elif self.is_object(path): 112 value = { 'st_mode': 0o755 | stat.S_IFDIR, 113 'st_ino': self.get_ino(path), 114 'st_dev': 0, 115 'st_nlink': 2, 116 'st_uid': 1000, 117 'st_gid': 1000, 118 'st_size': 4096, 119 'st_atime': 0, 120 'st_mtime': 0, 121 'st_ctime': 0 } 122 elif self.is_property(path): 123 value = { 'st_mode': 0o644 | stat.S_IFREG, 124 'st_ino': self.get_ino(path), 125 'st_dev': 0, 126 'st_nlink': 1, 127 'st_uid': 1000, 128 'st_gid': 1000, 129 'st_size': 4096, 130 'st_atime': 0, 131 'st_mtime': 0, 132 'st_ctime': 0 } 133 else: 134 raise FuseOSError(ENOENT) 135 return value 136 137 def readdir(self, path, fh): 138 yield '.' 139 yield '..' 140 for item in self.qmp.command('qom-list', path=path): 141 yield str(item['name']) 142 143if __name__ == '__main__': 144 import os 145 146 fuse = FUSE(QOMFS(QEMUMonitorProtocol(os.environ['QMP_SOCKET'])), 147 sys.argv[1], foreground=True) 148