def posix_spawnp(filename, args, fileactions=None, env=None): """Invoke posix_spawnp(3C). 'filename' is the name of the executeable file. 'args' is a sequence of arguments supplied to the newly executed program. 'fileactions' defines what actions will be performed upon the file descriptors of the spawned executable. If defined, it must be a SpawnFileAction object. 'env', the enviroment, if provided, it must be a sequence object.""" if not isinstance(filename, six.string_types): raise TypeError("filename must be a string") pid = ffi.new("pid_t *") spawn_args = [] # This essentially does force_bytes in pkg.misc, but importing pkg.misc has # a circular import issue, so we implement the conversion here. for arg in args: if six.PY3 and isinstance(arg, six.string_types): arg = arg.encode() spawn_args.append(ffi.new("char []", arg)) spawn_args.append(ffi.NULL) # Process env, if supplied by caller spawn_env = [] if env: for arg in env: try: if six.PY3 and isinstance(arg, six.string_types): arg = arg.encode() spawn_env.append(ffi.new("char []", arg)) except: # If an environment variable cannot be added for any reason, # just continue. (Most likely is UnicodeEncodeError) pass spawn_env.append(ffi.NULL) # setup file actions, if passed by caller s_action = ffi.NULL if fileactions: if not isinstance(fileactions, SpawnFileAction): raise TypeError("fileact must be a SpawnFileAction object.") s_action = fileactions.fa # Now do the actual spawn rc = lib.posix_spawnp(pid, filename.encode(), s_action, ffi.NULL, spawn_args, spawn_env) _check_error(rc) return pid[0]
def __init__(self): self.fa = ffi.new("posix_spawn_file_actions_t *") rc = lib.posix_spawn_file_actions_init(self.fa) self.fa = ffi.gc(self.fa, lib.posix_spawn_file_actions_destroy) # The file_actions routines don't set errno, so we have to create # the exception tuple by hand. _check_error(rc)
def add_close_childfds(self, start_fd, except_fd=-1): """Add to a SpawnFileAction a series of 'closes' that will close all of the fds >= startfd in the child process. A single fd may be skipped, provided that it is given as the optional except argument.""" if not isinstance(start_fd, int): raise TypeError("start_fd must be int type") if not isinstance(except_fd, int): raise TypeError("except_fd must be int type") # Set up walk_data for fdwalk. wd = ffi.new("walk_data *", [0]) wd.skip_fd = ffi.cast("int", except_fd) wd.start_fd = ffi.cast("int", start_fd) wd.fap = self.fa # Perform the walk. lib.fdwalk(walk_func, wd)