import lind_test_server from lind_fs_constants import * lind_test_server._blank_fs_init() # Let's add a few directories to the system and see if it works... lind_test_server.mkdir_syscall('/bar',S_IRWXA) lind_test_server.mkdir_syscall('/bar/baz',S_IRWXA) lind_test_server.mkdir_syscall('/bar/bap',0) # Create a new file... fd = lind_test_server.open_syscall('/bar/bam',O_CREAT,0) lind_test_server.close_syscall(fd) # Read the root directory... rootfd = lind_test_server.open_syscall('/',0,0) val = lind_test_server.getdents_syscall(rootfd, 100) assert (val==[(3, 'bar', DT_DIR, 24), (1, '..', DT_DIR, 24),\ (1, '.', DT_DIR, 24)]), "Found: %s"%(str(val)) # Read the /bar directory... barfd = lind_test_server.open_syscall('/bar',0,0) # The buffer size is given small, only few entries are read. val = lind_test_server.getdents_syscall(barfd, 80) assert (val == [(6, 'bam', DT_REG, 24), (4, 'baz', DT_DIR, 24),\ (5, 'bap', DT_DIR, 24)]), "Found: %s"%(str(val)) # Again call on the same FD, should continue parsing the /bar directory. val = lind_test_server.getdents_syscall(barfd, 80)
def generate_fs(syscalls, home_env=None): """ <Purpose> This is the only public function of this module. It takes a list of Syscall objects as an argument and generates a Lind fs based on the information gathered from these system calls. <Arguments> syscalls: A list of Syscall objects, representing system calls parsed from a trace file. home_env: The HOME environment variable extracted from the traced execve sytem call. <Exceptions> None <Side Effects> Generates a set of files that make up the Lind file system. <Returns> None """ # load an initial lind file system. lind_test_server._blank_fs_init() # Keep track of all the file paths dealt with and make a note of whether the # file was added to the lind fs or not. Example: {"filename.txt":True, # "filename2.txt":False} where True indicates the file was added into the lind # fs and False means the file was seen but wasn't added to the lind fs. We # keep track of all the paths met so far for two reasons. Firstly, we want to # construct the INITIAL file system state, so we only deal with the first # occurence of each path. For example consider the following sequence of # traced system calls example: # # 11443 open("test.txt", O_RDONLY) = -1 ENOENT (No such file or directory) # ... # 11443 open("test.txt", O_RDONLY) = 3 # # In this example when the "test.txt" path is met for the first time, the file # does not exist (indicated by: -1 ENOENT). Subsequently, the "test.txt" path # is met again and in this case the file does exist. In this case we do NOT # want to include the "test.txt" file in the lind fs, because the initial file # system state did not include this file, even though the file is eventually # created. # # The second reason we keep track of all the paths met and whether they were # added in the lind fs is to confirm whether the lind fs was constructed # successfully. seen_paths = {} # a list of system calls that include a filepath in their arguments. We only # care about these system calls so only the actions representing of these # system calls will be examined. syscalls_with_path = ['open', 'creat', 'statfs', 'access', 'stat', 'link', 'unlink', 'chdir', 'rmdir', 'mkdir'] for action in actions: # the general format of an action is the following: # (syscall_name, (arguments tuple), (return tuple)) # # Example successful syscall action: # ('open_syscall', ('syscalls.txt', ['O_RDONLY', 'O_CREAT'], # ['S_IWUSR', 'S_IRUSR', 'S_IWGRP', 'S_IRGRP', 'S_IROTH']), # (3, None)) # # Example unsuccessful syscall actions: # ('access_syscall', ('/etc/ld.so.nohwcap', ['F_OK']), # (-1, 'ENOENT')) # ('mkdir_syscall', ('syscalls_dir', ['S_IRWXU', 'S_IRWXG', # 'S_IXOTH', 'S_IROTH']), (-1, 'EEXIST')) syscall_name, syscall_parameters, syscall_result = action if DEBUG: print "Action:", action # each syscall name should end with _syscall if not syscall_name.endswith("_syscall"): raise Exception("Unexpected name of system call '" + syscall_name + "'") # remove the _syscall part from the syscall name syscall_name = syscall_name[:syscall_name.find("_syscall")] if syscall_name in syscalls_with_path: # TODO: I should consider O_CREAT O_EXECL and O_TRUNC flags. # check if the system call is open and whether it includes the O_CREAT # flag. If it does, set the o_creat flag to True, otherwise set it to # False. The o_creat flag will be used when trying to add a file, to # indicate how to handle the case the actual file is missing. # Specifically, when trying to add a file into the lind fs that does not # exist in the local fs, an exception will be raised, unless the o_creat # flag is set to True, in which case a warning will be printed instead. o_creat = False if syscall_name == "open": open_flags = action[1][1] if "O_CREAT" in open_flags: o_creat = True # Similarly, if the system call is creat, set the o_creat flag to True if syscall_name == "creat": o_creat = True # get the file path from the action path = action[1][0] # We want the initial file system state. So deal only with the earliest # syscall pertaining to a path. if path not in seen_paths: # if the syscall was successful, copy file/dir into the lind fs. if syscall_result != (-1, 'ENOENT'): path, path_added = _copy_path_into_lind(path, home_path, o_creat) # remember this path was seen and whether it was added to the lind fs. seen_paths[path] = path_added else: # remember this path was seen but not added to the lind fs. seen_paths[path] = False # the link syscall contains a second path. if syscall_name == 'link': # ('link_syscall', ('syscalls.txt', 'syscalls.link'), (0, None)) path2 = action[1][1] if path2 not in seen_paths: # if we got an exists error, the file must have been there # already, so we add it in the lind fs. if syscall_result == (-1, 'EEXIST'): path2, path_added = _copy_path_into_lind(path2, home_path, o_creat) # remember this path was seen and whether it was added to the lind fs. seen_paths[path2] = path_added else: # remember this path was seen but not added to the lind fs. seen_paths[path2] = False """ TODO: Can add support for symlink here. Slightly more tricky due to return part and error messages. """ # change the home directory and the lind current directory so that future # references to relative paths will be handled correctly. if syscall_name == 'chdir': home_path = os.path.join(home_path, path) home_path = os.path.normpath(home_path) lind_test_server.chdir_syscall(home_path) if DEBUG: print print "Seen Paths" print seen_paths # all actions are now read. Let's confirm that lind fs is as expected. all_lind_paths = list_all_lind_paths() if DEBUG: print print "Lind Paths" print all_lind_paths for seen_path in seen_paths: # convert to lind absolute path. abs_seen_path = seen_path if not abs_seen_path.startswith("/"): abs_seen_path = "/" + abs_seen_path abs_seen_path = os.path.normpath(abs_seen_path) # skip the root if abs_seen_path == "/": continue if seen_paths[seen_path]: # the file should be in lind fs. if abs_seen_path not in all_lind_paths: raise Exception("Expected file '" + abs_seen_path + "' not found in Lind fs") else: # file should not be in lind fs. if abs_seen_path in all_lind_paths: raise Exception("Unexpected file '" + abs_seen_path + "' in Lind fs")
def main(): # I can be imported as a module too!!! if len(sys.argv)==1: print_usage() return command = sys.argv[1] args = sys.argv[2:] #help : print this message #usage : print this message if command == 'help' or command == 'usage': print_usage() #cp root file1 [file2...] : copies files from the root into the lindfs. For # example, cp bar /etc/passwd /bin/ls will copy # bar/etc/passwd, bar/bin/ls as /etc/passwd, /bin/ls elif command == 'cp': lind_test_server.load_fs() if len(args)<2: print 'Too few arguments to cp. Must specify root and at least one file' return root = args[0] for filetocp in args[1:]: cp_into_lind(filetocp, rootpath=root) #find [startingpath] : print the names of all files / paths in the fs # This is much like 'find /' elif command == 'find': lind_test_server.load_fs() if len(args)>1: print 'Too many arguments to find. Takes an optional path' return elif len(args) == 0: startingpath = '/' elif len(args)==1: startingpath = args[0] allpathlist = list_all_lind_paths(startingdir=startingpath) # want to print this more cleanly than as a list for thispath in allpathlist: print thispath #format : make a new blank fs, removing the current one. elif command == 'format': lind_test_server._blank_fs_init() #deltree dirname : delete a directory and all it contains elif command == 'deltree': lind_test_server.load_fs() if len(args)!= 1: print 'deltree takes exactly one argument, the dir to remove' return print 'Unimplemented...' #rm file1 [file2...] : delete a file elif command == 'rm': lind_test_server.load_fs() if len(args) == 0: print 'rm takes one or more arguments' return for filename in args: lind_test_server.unlink_syscall(filename) #mkdir dir1 [dir2...] : create a directory elif command == 'mkdir': lind_test_server.load_fs() if len(args) == 0: print 'mkdir takes one or more arguments' return for dirname in args: lind_test_server.mkdir_syscall(dirname,S_IRWXA) #rmdir dir1 [dir2...] : delete a directory elif command == 'rmdir': lind_test_server.load_fs() if len(args) == 0: print 'rmdir takes one or more arguments' return for dirname in args: lind_test_server.rmdir_syscall(dirname) # OTHERWISE? else: print "ERROR: command unknown" print print_usage() return
def main(): # I can be imported as a module too!!! if len(sys.argv)==1: print_usage() return command = sys.argv[1] args = sys.argv[2:] #help : print this message #usage : print this message if command == 'help' or command == 'usage': print_usage() #cp root file1 [file2...] : copies files from the root into the lindfs. For # example, cp bar /etc/passwd /bin/ls will copy # bar/etc/passwd, bar/bin/ls as /etc/passwd, /bin/ls elif command == 'cp': lind_test_server.load_fs() if len(args)<2: print 'Too few arguments to cp. Must specify root and at least one file' return root = args[0] for filetocp in args[1:]: cp_dir_into_lind(filetocp, rootpath=root) #update root file1 [file2...] : copies files from the root into the lindfs if they are different. For # example, cp bar /etc/passwd /bin/ls will copy # bar/etc/passwd, bar/bin/ls as /etc/passwd, /bin/ls elif command == 'update': lind_test_server.load_fs() if len(args)<2: print 'Too few arguments to update. Must specify root and at least one file' return root = args[0] for filetoup in args[1:]: update_dir_into_lind(filetoup, rootpath=root) #find [startingpath] : print the names of all files / paths in the fs # This is much like 'find /' elif command == 'find': lind_test_server.load_fs() if len(args)>1: print 'Too many arguments to find. Takes an optional path' return elif len(args) == 0: startingpath = '/' elif len(args)==1: startingpath = args[0] allpathlist = list_all_lind_paths(startingdir=startingpath) # want to print this more cleanly than as a list #for thispath in allpathlist: # print thispath #format : make a new blank fs, removing the current one. elif command == 'format': lind_test_server._blank_fs_init() #deltree dirname : delete a directory and all it contains elif command == 'deltree': lind_test_server.load_fs() if len(args)!= 1: print 'deltree takes exactly one argument, the dir to remove' return deltree_lind(args[0]) #rm file1 [file2...] : delete a file elif command == 'rm': lind_test_server.load_fs() if len(args) == 0: print 'rm takes one or more arguments' return for filename in args: lind_test_server.unlink_syscall(filename) #mkdir dir1 [dir2...] : create a directory elif command == 'mkdir': lind_test_server.load_fs() if len(args) == 0: print 'mkdir takes one or more arguments' return for dirname in args: lind_test_server.mkdir_syscall(dirname,S_IRWXA) #rmdir dir1 [dir2...] : delete a directory elif command == 'rmdir': lind_test_server.load_fs() if len(args) == 0: print 'rmdir takes one or more arguments' return for dirname in args: lind_test_server.rmdir_syscall(dirname) # OTHERWISE? else: print "ERROR: command unknown" print print_usage() return
def generate_fs(actions, trace_path): # Relative paths found in actions are related to this HOME_PATH. It is initially # set to an empty string which ultimately translates to the current directory. home_path = '' # read the trace and examine the execve syscall to see if the HOME environment # variable is set to somewhere else. This usually happens when running # benchmarks. The reason to do this is because actions referring to files # using relative paths, might refere to these files relative to the HOME # variable defined in the execve syscall. fh = open(trace_path, "r") # the execve syscall is the first action of the trace file execve_line = fh.readline() fh.close() # If the 'HOME' variable is defined in the execve line, the HOME_PATH # variable will be set to the path of 'HOME'. if execve_line.find("execve(") != -1: execve_parts = execve_line.split(", ") # the parameter of the HOME variable in the execve syscall has this format: # "HOME=/home/savvas/tests/" including the double quotes. for part in execve_parts: if part.startswith("\"HOME="): part = part.strip("\"") assert (part.startswith("HOME=")) home_path = part[part.find("HOME=") + 5:] # load an initial lind file system. lind_test_server._blank_fs_init() # Keep track of all the file paths dealt with and make a note of whether the # file was added to the lind fs or not. Example: {"filename.txt":True, # "filename2.txt":False} where True indicates the file was added into the lind # fs and False means the file was seen but wasn't added to the lind fs. We # keep track of all the paths met so far for two reasons. Firstly, we want to # construct the INITIAL file system state, so we only deal with the first # occurence of each path. For example consider the following sequence of # traced system calls example: # # 11443 open("test.txt", O_RDONLY) = -1 ENOENT (No such file or directory) # ... # 11443 open("test.txt", O_RDONLY) = 3 # # In this example when the "test.txt" path is met for the first time, the file # does not exist (indicated by: -1 ENOENT). Subsequently, the "test.txt" path # is met again and in this case the file does exist. In this case we do NOT # want to include the "test.txt" file in the lind fs, because the initial file # system state did not include this file, even though the file is eventually # created. # # The second reason we keep track of all the paths met and whether they were # added in the lind fs is to confirm whether the lind fs was constructed # successfully. seen_paths = {} # a list of system calls that include a filepath in their arguments. We only # care about these system calls so only the actions representing of these # system calls will be examined. syscalls_with_path = [ 'open', 'creat', 'statfs', 'access', 'stat', 'link', 'unlink', 'chdir', 'rmdir', 'mkdir' ] for action in actions: # the general format of an action is the following: # (syscall_name, (arguments tuple), (return tuple)) # # Example successful syscall action: # ('open_syscall', ('syscalls.txt', ['O_RDONLY', 'O_CREAT'], # ['S_IWUSR', 'S_IRUSR', 'S_IWGRP', 'S_IRGRP', 'S_IROTH']), # (3, None)) # # Example unsuccessful syscall actions: # ('access_syscall', ('/etc/ld.so.nohwcap', ['F_OK']), # (-1, 'ENOENT')) # ('mkdir_syscall', ('syscalls_dir', ['S_IRWXU', 'S_IRWXG', # 'S_IXOTH', 'S_IROTH']), (-1, 'EEXIST')) syscall_name, syscall_parameters, syscall_result = action if DEBUG: print "Action:", action # each syscall name should end with _syscall if not syscall_name.endswith("_syscall"): raise Exception("Unexpected name of system call '" + syscall_name + "'") # remove the _syscall part from the syscall name syscall_name = syscall_name[:syscall_name.find("_syscall")] if syscall_name in syscalls_with_path: # TODO: I should consider O_CREAT O_EXECL and O_TRUNC flags. # check if the system call is open and whether it includes the O_CREAT # flag. If it does, set the o_creat flag to True, otherwise set it to # False. The o_creat flag will be used when trying to add a file, to # indicate how to handle the case the actual file is missing. # Specifically, when trying to add a file into the lind fs that does not # exist in the local fs, an exception will be raised, unless the o_creat # flag is set to True, in which case a warning will be printed instead. o_creat = False if syscall_name == "open": open_flags = action[1][1] if "O_CREAT" in open_flags: o_creat = True # Similarly, if the system call is creat, set the o_creat flag to True if syscall_name == "creat": o_creat = True # get the file path from the action path = action[1][0] # We want the initial file system state. So deal only with the earliest # syscall pertaining to a path. if path not in seen_paths: # if the syscall was successful, copy file/dir into the lind fs. if syscall_result != (-1, 'ENOENT'): path, path_added = _copy_path_into_lind( path, home_path, o_creat) # remember this path was seen and whether it was added to the lind fs. seen_paths[path] = path_added else: # remember this path was seen but not added to the lind fs. seen_paths[path] = False # the link syscall contains a second path. if syscall_name == 'link': # ('link_syscall', ('syscalls.txt', 'syscalls.link'), (0, None)) path2 = action[1][1] if path2 not in seen_paths: # if we got an exists error, the file must have been there # already, so we add it in the lind fs. if syscall_result == (-1, 'EEXIST'): path2, path_added = _copy_path_into_lind( path2, home_path, o_creat) # remember this path was seen and whether it was added to the lind fs. seen_paths[path2] = path_added else: # remember this path was seen but not added to the lind fs. seen_paths[path2] = False """ TODO: Can add support for symlink here. Slightly more tricky due to return part and error messages. """ # change the home directory and the lind current directory so that future # references to relative paths will be handled correctly. if syscall_name == 'chdir': home_path = os.path.join(home_path, path) home_path = os.path.normpath(home_path) lind_test_server.chdir_syscall(home_path) if DEBUG: print print "Seen Paths" print seen_paths # all actions are now read. Let's confirm that lind fs is as expected. all_lind_paths = list_all_lind_paths() if DEBUG: print print "Lind Paths" print all_lind_paths for seen_path in seen_paths: # convert to lind absolute path. abs_seen_path = seen_path if not abs_seen_path.startswith("/"): abs_seen_path = "/" + abs_seen_path abs_seen_path = os.path.normpath(abs_seen_path) # skip the root if abs_seen_path == "/": continue if seen_paths[seen_path]: # the file should be in lind fs. if abs_seen_path not in all_lind_paths: raise Exception("Expected file '" + abs_seen_path + "' not found in Lind fs") else: # file should not be in lind fs. if abs_seen_path in all_lind_paths: raise Exception("Unexpected file '" + abs_seen_path + "' in Lind fs")
def wipe_cmd(): """wipe this file system""" cd_cmd("/") # cd so we dont get stuck in a non existant file post wipe! lind_test_server._blank_fs_init() print "Filesystem wiped"