Esempio n. 1
0
            trg_fd = [0, 1, 2]

        # wax all open descriptors that weren't requested be left open.
        for x in range(0, max_fd_limit):
            if x not in trg_fd:
                try:
                    os.close(x)
                except SystemExit, e:
                    raise
                except:
                    pass

    # note this order must be preserved- can't change gid/groups if you change uid first.
        if selinux_capable and selinux_context:
            import selinux
            selinux.setexec(selinux_context)
        if gid:
            os.setgid(gid)
        if groups:
            os.setgroups(groups)
        if uid:
            os.setuid(uid)
        if umask:
            os.umask(umask)

        try:
            #print "execing", myc, myargs
            if func_call:
                # either use a passed in func for interpretting the results, or return if no exception.
                # note the passed in list, and dict are expanded.
                if len(mycommand) == 4:
Esempio n. 2
0
def spawn(mycommand,env={},raw_exit_code=False,opt_name=None,fd_pipes=None,returnpid=False,\
	 uid=None,gid=None,groups=None,umask=None,logfile=None,path_lookup=True,\
	 selinux_context=None, raise_signals=False, func_call=False):
	"""base fork/execve function.
	mycommand is the desired command- if you need a command to execute in a bash/sandbox/fakeroot
	environment, use the appropriate spawn call.  This is a straight fork/exec code path.
	Can either have a tuple, or a string passed in.  If uid/gid/groups/umask specified, it changes
	the forked process to said value.  If path_lookup is on, a non-absolute command will be converted
	to an absolute command, otherwise it returns None.

	selinux_context is the desired context, dependant on selinux being available.
	opt_name controls the name the processor goes by.
	fd_pipes controls which file descriptor numbers are left open in the forked process- it's a dict of
	current fd's raw fd #, desired #.

	func_call is a boolean for specifying to execute a python function- use spawn_func instead.
	raise_signals is questionable.	Basically throw an exception if signal'd.  No exception is thrown
	if raw_input is on.

	logfile overloads the specified fd's to write to a tee process which logs to logfile
	returnpid returns the relevant pids (a list, including the logging process if logfile is on).

	non-returnpid calls to spawn will block till the process has exited, returning the exitcode/signal
	raw_exit_code controls whether the actual waitpid result is returned, or intrepretted."""


	myc=''
	if not func_call:
		if type(mycommand)==bytes:
			mycommand=mycommand.split()
		myc = mycommand[0]
		if not os.access(myc, os.X_OK):
			if not path_lookup:
				return None
			myc = find_binary(myc)
			if myc == None:
				return None
	mypid=[]
	if logfile:
		pr,pw=os.pipe()
		mypid.extend(spawn(('tee','-i','-a',logfile),returnpid=True,fd_pipes={0:pr,1:1,2:2}))
		retval=os.waitpid(mypid[-1],os.WNOHANG)[1]
		if retval != 0:
			# he's dead jim.
			if raw_exit_code:
				return retval
			return process_exit_code(retval)

		if fd_pipes == None:
			fd_pipes={}
			fd_pipes[0] = 0
		fd_pipes[1]=pw
		fd_pipes[2]=pw

	if not opt_name:
		opt_name = mycommand[0]
	myargs=[opt_name]
	myargs.extend(mycommand[1:])
	global spawned_pids
	mypid.append(os.fork())
	if mypid[-1] != 0:
		#log the bugger.
		spawned_pids.extend(mypid)

	if mypid[-1] == 0:
		if func_call:
			spawned_pids = []

		# this may look ugly, but basically it moves file descriptors around to ensure no
		# handles that are needed are accidentally closed during the final dup2 calls.
		trg_fd=[]
		if type(fd_pipes)==dict:
			src_fd=[]
			k=list(fd_pipes.keys())
			k.sort()

			#build list of which fds will be where, and where they are at currently
			for x in k:
				trg_fd.append(x)
				src_fd.append(fd_pipes[x])

			# run through said list dup'ing descriptors so that they won't be waxed
			# by other dup calls.
			for x in range(0,len(trg_fd)):
				if trg_fd[x] == src_fd[x]:
					continue
				if trg_fd[x] in src_fd[x+1:]:
					new=os.dup2(trg_fd[x],max(src_fd) + 1)
					os.close(trg_fd[x])
					try:
						while True:
							src_fd[s.index(trg_fd[x])]=new
					except SystemExit as e:
						raise
					except:
						pass

			# transfer the fds to their final pre-exec position.
			for x in range(0,len(trg_fd)):
				if trg_fd[x] != src_fd[x]:
					os.dup2(src_fd[x], trg_fd[x])
		else:
			trg_fd=[0,1,2]

		# wax all open descriptors that weren't requested be left open.
		for x in range(0,max_fd_limit):
			if x not in trg_fd:
				try:
					os.close(x)
				except SystemExit as e:
					raise
				except:
					pass

		# note this order must be preserved- can't change gid/groups if you change uid first.
		if selinux_capable and selinux_context:
			import selinux
			selinux.setexec(selinux_context)
		if gid:
			os.setgid(gid)
		if groups:
			os.setgroups(groups)
		if uid:
			os.setuid(uid)
		if umask:
			os.umask(umask)

		try:
			#print "execing", myc, myargs
			if func_call:
				# either use a passed in func for interpretting the results, or return if no exception.
				# note the passed in list, and dict are expanded.
				if len(mycommand) == 4:
					os._exit(mycommand[3](mycommand[0](*mycommand[1],**mycommand[2])))
				try:
					mycommand[0](*mycommand[1],**mycommand[2])
				except Exception as e:
					print("caught exception",e," in forked func",mycommand[0])
				sys.exit(0)

			#os.execvp(myc,myargs)
			os.execve(myc,myargs,env)
		except SystemExit as e:
			raise
		except Exception as e:
			if not func_call:
				raise MetroError(str(e)+":\n   "+myc+" "+string.join(myargs))
			print("func call failed")

		# If the execve fails, we need to report it, and exit
		# *carefully* --- report error here
		os._exit(1)
		sys.exit(1)
		return # should never get reached

	# if we were logging, kill the pipes.
	if logfile:
		os.close(pr)
		os.close(pw)

	if returnpid:
		return mypid

	# loop through pids (typically one, unless logging), either waiting on their death, or waxing them
	# if the main pid (mycommand) returned badly.
	while len(mypid):
		try:
			retval=os.waitpid(mypid[-1],0)[1]
		except KeyboardInterrupt:
			print("Keyboard interrupt detected, aborting script...")
			os.kill(mypid[-1],signal.SIGINT)
			continue
		if retval != 0:
			cleanup(mypid[0:-1],block_exceptions=False)
			# at this point we've killed all other kid pids generated via this call.
			# return now.
			if raw_exit_code:
				return retval
			return process_exit_code(retval,throw_signals=raise_signals)
		else:
			mypid.pop(-1)
	cleanup(mypid)
	return 0
Esempio n. 3
0
			trg_fd=[0,1,2]

		# wax all open descriptors that weren't requested be left open.
		for x in range(0,max_fd_limit):
			if x not in trg_fd:
				try:
					os.close(x)
                                except SystemExit, e:
                                        raise
                                except:
                                        pass

                # note this order must be preserved- can't change gid/groups if you change uid first.
                if selinux_capable and selinux_context:
                        import selinux
                        selinux.setexec(selinux_context)
                if gid:
                        os.setgid(gid)
                if groups:
                        os.setgroups(groups)
                if uid:
                        os.setuid(uid)
                if umask:
                        os.umask(umask)
                else:
                        os.umask(022)

                try:
                        #msg("execing", myc, myargs)
                        if func_call:
                                # either use a passed in func for interpretting the results, or return if no exception.