source: baculafs/trunk/baculafs.py@ 780

Last change on this file since 780 was 780, checked in by joergs, on Jul 25, 2009 at 2:19:24 AM

improved logging

  • Property svn:executable set to *
File size: 6.0 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3
4import logging
5import fuse
6import stat
7import errno
8import os
9import pexpect
10import sys
11
12fuse.fuse_python_api = (0, 2)
13
14###### bconsole
15################
16
17LOG_FILENAME = '/tmp/baculafs.log'
18#LOG_BCONSOLE = '/tmp/bconsole.log'
19LOG_BCONSOLE_DUMP = '/tmp/bconsole.out'
20
21
22#BACULA_CMD = 'strace -f -o /tmp/bconsole.strace /usr/sbin/bconsole -n'
23BACULA_CMD = '/usr/sbin/bconsole -n'
24# .clients
25# 5: ting-fd
26BACULA_CLIENT='5'
27
28BCONSOLE_CMD_PROMPT='\*'
29BCONSOLE_SELECT_PROMPT='Select item:.*'
30BCONSOLE_RESTORE_PROMPT='\$ '
31
32
33class Bconsole:
34
35 def __init__(self, client=BACULA_CLIENT):
36 #logging.debug('BC init')
37 self.bconsole = pexpect.spawn( BACULA_CMD, logfile=file(LOG_BCONSOLE_DUMP, 'w'), timeout=10 )
38 self.bconsole.setecho( False )
39 self.bconsole.expect( BCONSOLE_CMD_PROMPT )
40 self.bconsole.sendline( 'restore' )
41 #self.bconsole.expect( BCONSOLE_SELECT_PROMPT )
42 self.bconsole.sendline( "5" )
43 #self.bconsole.expect( BCONSOLE_SELECT_PROMPT )
44 self.bconsole.sendline( BACULA_CLIENT )
45 self.bconsole.expect( BCONSOLE_RESTORE_PROMPT )
46 #logging.debug( "BC alive: " + str(self.bconsole.isalive()) )
47 #logging.debug('BC init done')
48
49
50 def ls(self, path):
51
52 path = path + "/"
53 logging.debug( "(" + path + ")" )
54
55 self.bconsole.sendline( 'cd ' + path )
56 #self.bconsole.expect( BCONSOLE_RESTORE_PROMPT, timeout=10 )
57 #self.bconsole.sendline( 'pwd' )
58
59 index = self.bconsole.expect( ["cwd is: " + path + "[/]?", BCONSOLE_RESTORE_PROMPT, pexpect.EOF, pexpect.TIMEOUT ] )
60 logging.debug( "cd result: " + str(index) )
61
62 if index == 0:
63 # path ok, now wait for prompt
64 self.bconsole.expect( BCONSOLE_RESTORE_PROMPT )
65 elif index == 1:
66 #print "wrong path"
67 return
68 elif index == 2:
69 print "error EOF"
70 raise
71 elif index == 3:
72 print "error TIMEOUT"
73 return
74
75 self.bconsole.sendline( 'ls' )
76 self.bconsole.expect( BCONSOLE_RESTORE_PROMPT )
77 lines = self.bconsole.before.splitlines()
78 #logging.debug( str(lines) )
79 return lines
80
81###############
82
83class BaculaFS(fuse.Fuse):
84
85 TYPE_NONE = 0
86 TYPE_FILE = 1
87 TYPE_DIR = 2
88
89 files = { '': {'type': TYPE_DIR} }
90
91 def __init__(self, *args, **kw):
92 logging.debug('init')
93 #self.console = Bconsole()
94 fuse.Fuse.__init__(self, *args, **kw)
95 #logging.debug('init finished')
96
97 def _getdir(self, path):
98
99 # TODO: may cause problems with filenames that ends with "/"
100 path = path.rstrip( '/' )
101 logging.debug( '"' + path + '"' )
102
103 if (path in self.files):
104 #logging.debug( "(" + path + ")=" + str(self.files[path]) )
105 if self.files[path]['type'] == self.TYPE_FILE:
106 logging.debug( '"' + path + '"=file (cached)' )
107 return self.files[path]
108 elif ((self.files[path]['type'] == self.TYPE_DIR) and ('files' in self.files[path])):
109 logging.debug( '"' + path + '"=dir (cached)' )
110 return self.files[path]
111
112 try:
113 files = Bconsole().ls(path)
114 #logging.debug( " files: " + str( files ) )
115
116 # setting initial empty directory. Add entires later in this function
117 self.files[path] = { 'type': self.TYPE_DIR, 'dirs': [ ".", ".." ], 'files': [] }
118 for i in files:
119 if i.endswith('/'):
120 # we expect a directory
121 # TODO: error with filesnames, that ends with '/'
122 i = i.rstrip( '/' )
123 self.files[path]['dirs'].append(i)
124 if not (i in self.files):
125 self.files[path + "/" + i] = { 'type': self.TYPE_DIR }
126 else:
127 self.files[path]['files'].append(i)
128 self.files[path + "/" + i] = { 'type': self.TYPE_FILE }
129
130 except Exception as e:
131 logging.exception(e)
132 logging.error( "no access to path " + path )
133 self.files[path] = { 'type': TYPE_NONE }
134 logging.debug( '"' + path + '"=' + str( self.files[path] ) )
135 return self.files[path]
136
137
138
139 # TODO: only works after readdir for the directory (eg. ls)
140 def getattr(self, path):
141
142 # TODO: may cause problems with filenames that ends with "/"
143 path = path.rstrip( '/' )
144 logging.debug( '"' + path + '"' )
145
146 file = self.files[path]
147 st = fuse.Stat()
148
149 #file = self._getdir( path )
150
151 if file['type'] == self.TYPE_FILE:
152 st.st_mode = stat.S_IFREG | 0444
153 st.st_nlink = 1
154 st.st_size = 0
155 elif file['type'] == self.TYPE_DIR:
156 st.st_mode = stat.S_IFDIR | 0755
157 if 'dirs' in file:
158 st.st_nlink = len(file['dirs'])
159 else:
160 st.st_nlink = 2
161 else:
162 return -errno.ENOENT
163 return st
164
165
166
167 def readdir(self, path, offset):
168 logging.debug( '"' + path + '", offset=' + str(offset) + ')' )
169
170 dir = self._getdir( path )
171
172 #logging.debug( " readdir: type: " + str( dir['type'] ) )
173 #logging.debug( " readdir: dirs: " + str( dir['dirs'] ) )
174 #logging.debug( " readdir: file: " + str( dir['files'] ) )
175
176 if dir['type'] != self.TYPE_DIR:
177 return -errno.ENOENT
178 else:
179 return [fuse.Direntry(f) for f in dir['files'] + dir['dirs']]
180
181 #def open( self, path, flags ):
182 #logging.debug( "open " + path )
183 #return -errno.ENOENT
184
185 #def read( self, path, length, offset):
186 #logging.debug( "read " + path )
187 #return -errno.ENOENT
188
189if __name__ == "__main__":
190 # initialize logging
191 logging.basicConfig(filename=LOG_FILENAME,level=logging.DEBUG,format="%(asctime)s %(process)5d(%(threadName)s) %(levelname)-7s %(funcName)s( %(message)s )")
192
193 fs = BaculaFS()
194 fs.parse()
195 fs.main()
Note: See TracBrowser for help on using the repository browser.