]>
git.ipfire.org Git - pakfire.git/blob - pakfire/chroot.py
2 ###############################################################################
4 # Pakfire - The IPFire package management system #
5 # Copyright (C) 2011 Pakfire development team #
7 # This program is free software: you can redistribute it and/or modify #
8 # it under the terms of the GNU General Public License as published by #
9 # the Free Software Foundation, either version 3 of the License, or #
10 # (at your option) any later version. #
12 # This program is distributed in the hope that it will be useful, #
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
15 # GNU General Public License for more details. #
17 # You should have received a copy of the GNU General Public License #
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
20 ###############################################################################
31 _libc
= ctypes
.cdll
.LoadLibrary(None)
32 _libc
.personality
.argtypes
= [ctypes
.c_ulong
]
33 _libc
.personality
.restype
= ctypes
.c_int
35 def logOutput(fds
, logger
, returnOutput
=1, start
=0, timeout
=0):
39 # set all fds to nonblocking
41 flags
= fcntl
.fcntl(fd
, fcntl
.F_GETFL
)
43 fcntl
.fcntl(fd
, fcntl
.F_SETFL
, flags| os
.O_NONBLOCK
)
47 if (time
.time() - start
)>timeout
and timeout
!=0:
51 i_rdy
,o_rdy
,e_rdy
= select
.select(fds
,[],[],1)
53 # slurp as much input as is ready
58 if logger
is not None:
59 lines
= input.split("\n")
61 lines
[0] = tail
+ lines
[0]
62 # we may not have all of the last line
65 if line
== '': continue
67 for h
in logger
.handlers
:
71 if tail
and logger
is not None:
76 def do(command
, shell
=False, chrootPath
=None, cwd
=None, timeout
=0, raiseExc
=True, returnOutput
=0, personality
=None, logger
=None, env
=None, *args
, **kargs
):
77 # Save the output of command
80 # Save time when command was started
83 # Create preexecution thingy for command
84 preexec
= ChildPreExec(personality
, chrootPath
, cwd
)
87 logger
.debug("Executing command: %s in %s" % (command
, chrootPath
or "/"))
92 # Create new child process
93 child
= subprocess
.Popen(
96 bufsize
=0, close_fds
=True,
97 stdin
=open("/dev/null", "r"),
98 stdout
=subprocess
.PIPE
,
99 stderr
=subprocess
.PIPE
,
100 preexec_fn
= preexec
,
104 # use select() to poll for output so we dont block
105 output
= logOutput([child
.stdout
, child
.stderr
], logger
, returnOutput
, start
, timeout
)
108 # kill children if they aren't done
109 if child
and child
.returncode
is None:
110 os
.killpg(child
.pid
, 9)
113 os
.waitpid(child
.pid
, 0)
118 # wait until child is done, kill it if it passes timeout
120 while child
.poll() is None:
121 if (time
.time() - start
) > timeout
and timeout
!= 0:
123 os
.killpg(child
.pid
, 15)
124 if (time
.time() - start
) > (timeout
+1) and timeout
!= 0:
126 os
.killpg(child
.pid
, 9)
129 raise commandTimeoutExpired
, ("Timeout(%s) expired for command:\n # %s\n%s" % (timeout
, command
, output
))
132 logger
.debug("Child returncode was: %s" % str(child
.returncode
))
134 if raiseExc
and child
.returncode
:
136 raise Error
, ("Command failed: \n # %s\n%s" % (command
, output
), child
.returncode
)
138 raise Error
, ("Command failed. See logs for output.\n # %s" % (command
,), child
.returncode
)
142 class ChildPreExec(object):
143 def __init__(self
, personality
, chrootPath
, cwd
):
144 self
._personality
= personality
145 self
.chrootPath
= chrootPath
149 def personality(self
):
151 Return personality value if supported.
152 Otherwise return None.
154 # taken from sys/personality.h
161 return personality_defs
[self
._personality
]
165 def __call__(self
, *args
, **kargs
):
166 # Set a new process group
169 # Set new personality if we got one.
171 res
= _libc
.personality(self
.personality
)
173 raise OSError, "Could not set personality"
175 # Change into new root.
177 os
.chdir(self
.chrootPath
)
178 os
.chroot(self
.chrootPath
)
182 if not os
.path
.exists(self
.cwd
):
183 os
.makedirs(self
.cwd
)