- Timestamp:
- Mar 30, 2008, 2:22:48 PM (17 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/packages/sipb-xen-console/files/usr/bin/sipb-xen-consolefs
r357 r359 11 11 # - note: these must be returned as negatives 12 12 13 from syslog import * 14 13 15 import sipb_xen_database 14 16 … … 16 18 17 19 realpath = "/home/machines/" 18 19 def dirFromList(list):20 """21 Return a properly formatted list of items suitable to a directory listing.22 ['a', 'b', 'c'] => [('a', 0), ('b', 0), ('c', 0)]23 """24 return [(x, 0) for x in list]25 20 26 21 def getDepth(path): … … 40 35 return ['/'] 41 36 else: 37 # [1:] because otherwise you get an empty list element from the 38 # initial '/' 42 39 return path[1:].split('/') 43 40 … … 60 57 class ConsoleFS(Fuse): 61 58 """ 59 ConsoleFS creates a series of subdirectories each mirroring the same real 60 directory, except for a single file - the .k5login - which is dynamically 61 generated for each subdirectory 62 63 This filesystem only implements the getattr, getdir, read, and readlink 64 calls, beacuse this is a read-only filesystem 62 65 """ 63 66 64 67 def __init__(self, *args, **kw): 68 """Initialize the filesystem and set it to allow_other access besides 69 the user who mounts the filesystem (i.e. root) 70 """ 65 71 Fuse.__init__(self, *args, **kw) 66 72 self.lasttime = time() 67 73 self.allow_other = 1 68 print 'Init complete.' 74 75 openlog('sipb-xen-consolefs ', LOG_PID, LOG_DAEMON) 76 77 syslog(LOG_DEBUG, 'Init complete.') 69 78 70 79 def mirrorPath(self, path): 80 """Translate a virtual path to its real path counterpart""" 71 81 return realpath + "/".join(getParts(path)[1:]) 72 82 73 83 def getMachines(self): 84 """Get the list of VMs in the database, clearing the cache if it's 85 older than 15 seconds""" 74 86 if time() - self.lasttime > 15: 75 87 self.lasttime = time() … … 78 90 79 91 def getUid(self, machine_name): 92 """Calculate the UID of a machine-account, which is just machine_id+1000 93 """ 80 94 return sipb_xen_database.Machine.get_by(name=machine_name).machine_id + 1000 81 95 82 96 def getK5login(self, machine_name): 97 """Build the ACL for a machine and turn it into a .k5login file 98 """ 83 99 machine = sipb_xen_database.Machine.get_by(name=machine_name) 84 100 users = [acl.user for acl in machine.acl] … … 86 102 87 103 def userToPrinc(self, user): 104 """Convert Kerberos v4-style names to v5-style and append a default 105 realm if none is specified 106 """ 88 107 if '@' in user: 89 108 (princ, realm) = user.split('@') … … 109 128 """ 110 129 111 print "*** getattr: " + path130 syslog(LOG_DEBUG, "*** getattr: " + path) 112 131 113 132 depth = getDepth(path) … … 115 134 116 135 st = MyStat() 136 # / is a directory 117 137 if path == '/': 118 138 st.st_mode = stat.S_IFDIR | 0755 119 139 st.st_nlink = 2 140 # /foo is a directory if foo is a machine - otherwise it doesn't exist 120 141 elif depth == 1: 121 142 if parts[-1] in self.getMachines(): 122 143 st.st_mode = stat.S_IFDIR | 0755 123 144 st.st_nlink = 2 145 # Homedirs should be owned by the user whose homedir it is 124 146 st.st_uid = st.st_gid = self.getUid(parts[0]) 125 147 else: 126 148 return -errno.ENOENT 149 # Catch the .k5login file, because it's a special case 127 150 elif depth == 2 and parts[-1] == '.k5login': 128 151 st.st_mode = stat.S_IFREG | 0444 129 152 st.st_nlink = 1 130 153 st.st_size = len(self.getK5login(parts[0])) 154 # The .k5login file should be owned by the user whose homedir it is 131 155 st.st_uid = st.st_gid = self.getUid(parts[0]) 156 # For anything else, we get the mirror path and call out to the OS 132 157 else: 133 158 stats = list(os.lstat(self.mirrorPath(path))) 159 # Shadow the UID and GID from the original homedir 134 160 stats[4:6] = [self.getUid(parts[0])] * 2 135 161 return tuple(stats) 136 162 return st.toTuple() 137 163 164 # This call isn't actually used in the version of Fuse on console, but we 165 # wanted to leave it implemented to ease the transition in the future 138 166 def readdir(self, path, offset): 139 print '*** readdir', path, offset 167 """Return a generator with the listing for a directory 168 """ 169 syslog(LOG_DEBUG, '*** readdir %s %s' % (path, offset)) 140 170 for (value, zero) in self.getdir(path): 141 171 yield fuse.Direntry(value) 142 172 143 173 def getdir(self, path): 144 print '*** getdir', path 174 """Return a list of tuples of the form (item, 0) with the contents of 175 the directory path 176 177 Fuse doesn't add '.' or '..' on its own, so we have to 178 """ 179 syslog(LOG_DEBUG, '*** getdir %s' % path) 180 181 # '/' contains a directory for each machine 145 182 if path == '/': 146 contents = ['.', '..']+self.getMachines() 183 contents = self.getMachines() 184 # The directory for each machine contains the same files as the realpath 185 # but also the .k5login 186 # 187 # The list is converted to a set so that we can handle the case where 188 # there is already a .k5login in the realpath gracefully 147 189 elif getDepth(path) == 1: 148 contents = set(os.listdir(self.mirrorPath(path)) + ['.k5login', '.', '..']) 149 else: 150 contents = os.listdir(self.mirrorPath(path)) + ['.', '..'] 151 return [(i, 0) for i in contents] 152 153 def read ( self, path, length, offset ): 154 print '*** read', path, length, offset 190 contents = set(os.listdir(self.mirrorPath(path)) + ['.k5login']) 191 # If it's not the root of the homedir, just pass the call onto the OS 192 # for realpath 193 else: 194 contents = os.listdir(self.mirrorPath(path)) 195 # Format the list the way that Fuse wants it - and don't forget to add 196 # '.' and '..' 197 return [(i, 0) for i in (list(contents) + ['.', '..'])] 198 199 def read(self, path, length, offset): 200 """Read length bytes starting at offset of path. In most cases, this 201 just gets passed on to the OS 202 """ 203 syslog(LOG_DEBUG, '*** read %s %s %s' % (path, length, offset)) 155 204 156 205 parts = getParts(path) 157 206 207 # If the depth is less than 2, then either it's a directory or the file 208 # doesn't exist 209 # (realistically this doesn't appear to ever happen) 158 210 if getDepth(path) < 2: 159 211 return -errno.ENOENT 212 # If we're asking for a real .k5login file, then create it and return 213 # the snippet requested 160 214 elif parts[1:] == ['.k5login']: 161 215 if parts[0] not in self.getMachines(): … … 163 217 else: 164 218 return self.getK5login(parts[0])[offset:length + offset] 219 # Otherwise, pass the call onto the OS 220 # (note that the file will get closed when this call returns and the 221 # file descriptor goes out of scope) 165 222 else: 166 223 fname = self.mirrorPath(path) … … 171 228 f.seek(offset) 172 229 return f.read(length) 230 231 def readlink(self, path): 232 syslog(LOG_DEBUG, '*** readlink %s' % path) 233 234 # There aren't any symlinks here 235 if getDepth(path) < 2: 236 return -errno.ENOENT 237 # But there might be here 238 else: 239 return os.readlink(self.mirrorPath(path)) 173 240 174 241 if __name__ == '__main__':
Note: See TracChangeset
for help on using the changeset viewer.