PageRenderTime 54ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/pypy/module/posix/interp_posix.py

https://bitbucket.org/pypy/pypy/
Python | 1346 lines | 1155 code | 80 blank | 111 comment | 131 complexity | 52330aa0b878fc43bc5a6a79eee64359 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. import os
  2. import sys
  3. from rpython.rlib import rposix, rposix_stat
  4. from rpython.rlib import objectmodel, rurandom
  5. from rpython.rlib.objectmodel import specialize
  6. from rpython.rlib.rarithmetic import r_longlong, intmask, r_uint
  7. from rpython.rlib.unroll import unrolling_iterable
  8. from pypy.interpreter.gateway import unwrap_spec
  9. from pypy.interpreter.error import (
  10. OperationError, oefmt, wrap_oserror, wrap_oserror2)
  11. from pypy.interpreter.executioncontext import ExecutionContext
  12. from pypy.module.sys.interp_encoding import getfilesystemencoding
  13. _WIN32 = sys.platform == 'win32'
  14. if _WIN32:
  15. from rpython.rlib.rwin32 import _MAX_ENV
  16. c_int = "c_int"
  17. # CPython 2.7 semantics used to be too messy, differing on 32-bit vs
  18. # 64-bit, but this was cleaned up in recent 2.7.x. Now, any function
  19. # taking a uid_t or gid_t accepts numbers in range(-1, 2**32) as an
  20. # r_uint, with -1 being equivalent to 2**32-1. Any function that
  21. # returns a uid_t or gid_t returns either an int or a long, depending
  22. # on whether it fits or not, but always positive.
  23. c_uid_t = 'c_uid_t'
  24. c_gid_t = 'c_uid_t'
  25. def wrap_uid(space, uid):
  26. if uid <= r_uint(sys.maxint):
  27. return space.wrap(intmask(uid))
  28. else:
  29. return space.wrap(uid) # an unsigned number
  30. wrap_gid = wrap_uid
  31. def fsencode_w(space, w_obj):
  32. if space.isinstance_w(w_obj, space.w_unicode):
  33. w_obj = space.call_method(w_obj, 'encode',
  34. getfilesystemencoding(space))
  35. return space.str0_w(w_obj)
  36. class FileEncoder(object):
  37. is_unicode = True
  38. def __init__(self, space, w_obj):
  39. self.space = space
  40. self.w_obj = w_obj
  41. def as_bytes(self):
  42. return fsencode_w(self.space, self.w_obj)
  43. def as_unicode(self):
  44. return self.space.unicode0_w(self.w_obj)
  45. class FileDecoder(object):
  46. is_unicode = False
  47. def __init__(self, space, w_obj):
  48. self.space = space
  49. self.w_obj = w_obj
  50. def as_bytes(self):
  51. return self.space.str0_w(self.w_obj)
  52. def as_unicode(self):
  53. space = self.space
  54. w_unicode = space.call_method(self.w_obj, 'decode',
  55. getfilesystemencoding(space))
  56. return space.unicode0_w(w_unicode)
  57. @specialize.memo()
  58. def dispatch_filename(func, tag=0):
  59. def dispatch(space, w_fname, *args):
  60. if space.isinstance_w(w_fname, space.w_unicode):
  61. fname = FileEncoder(space, w_fname)
  62. return func(fname, *args)
  63. else:
  64. fname = space.str0_w(w_fname)
  65. return func(fname, *args)
  66. return dispatch
  67. @specialize.memo()
  68. def dispatch_filename_2(func):
  69. def dispatch(space, w_fname1, w_fname2, *args):
  70. if space.isinstance_w(w_fname1, space.w_unicode):
  71. fname1 = FileEncoder(space, w_fname1)
  72. if space.isinstance_w(w_fname2, space.w_unicode):
  73. fname2 = FileEncoder(space, w_fname2)
  74. return func(fname1, fname2, *args)
  75. else:
  76. fname2 = FileDecoder(space, w_fname2)
  77. return func(fname1, fname2, *args)
  78. else:
  79. fname1 = FileDecoder(space, w_fname1)
  80. if space.isinstance_w(w_fname2, space.w_unicode):
  81. fname2 = FileEncoder(space, w_fname2)
  82. return func(fname1, fname2, *args)
  83. else:
  84. fname2 = FileDecoder(space, w_fname2)
  85. return func(fname1, fname2, *args)
  86. return dispatch
  87. @unwrap_spec(flag=c_int, mode=c_int)
  88. def open(space, w_fname, flag, mode=0777):
  89. """Open a file (for low level IO).
  90. Return a file descriptor (a small integer)."""
  91. try:
  92. fd = dispatch_filename(rposix.open)(
  93. space, w_fname, flag, mode)
  94. except OSError as e:
  95. raise wrap_oserror2(space, e, w_fname)
  96. return space.wrap(fd)
  97. @unwrap_spec(fd=c_int, pos=r_longlong, how=c_int)
  98. def lseek(space, fd, pos, how):
  99. """Set the current position of a file descriptor. Return the new position.
  100. If how == 0, 'pos' is relative to the start of the file; if how == 1, to the
  101. current position; if how == 2, to the end."""
  102. try:
  103. pos = os.lseek(fd, pos, how)
  104. except OSError as e:
  105. raise wrap_oserror(space, e)
  106. else:
  107. return space.wrap(pos)
  108. @unwrap_spec(fd=c_int)
  109. def isatty(space, fd):
  110. """Return True if 'fd' is an open file descriptor connected to the
  111. slave end of a terminal."""
  112. try:
  113. res = os.isatty(fd)
  114. except OSError as e:
  115. raise wrap_oserror(space, e)
  116. else:
  117. return space.wrap(res)
  118. @unwrap_spec(fd=c_int, buffersize=int)
  119. def read(space, fd, buffersize):
  120. """Read data from a file descriptor."""
  121. try:
  122. s = os.read(fd, buffersize)
  123. except OSError as e:
  124. raise wrap_oserror(space, e)
  125. else:
  126. return space.wrap(s)
  127. @unwrap_spec(fd=c_int)
  128. def write(space, fd, w_data):
  129. """Write a string to a file descriptor. Return the number of bytes
  130. actually written, which may be smaller than len(data)."""
  131. data = space.getarg_w('s*', w_data)
  132. try:
  133. res = os.write(fd, data.as_str())
  134. except OSError as e:
  135. raise wrap_oserror(space, e)
  136. else:
  137. return space.wrap(res)
  138. @unwrap_spec(fd=c_int)
  139. def close(space, fd):
  140. """Close a file descriptor (for low level IO)."""
  141. try:
  142. os.close(fd)
  143. except OSError as e:
  144. raise wrap_oserror(space, e)
  145. @unwrap_spec(fd_low=c_int, fd_high=c_int)
  146. def closerange(fd_low, fd_high):
  147. """Closes all file descriptors in [fd_low, fd_high), ignoring errors."""
  148. rposix.closerange(fd_low, fd_high)
  149. @unwrap_spec(fd=c_int, length=r_longlong)
  150. def ftruncate(space, fd, length):
  151. """Truncate a file to a specified length."""
  152. try:
  153. os.ftruncate(fd, length)
  154. except IOError as e:
  155. if not objectmodel.we_are_translated():
  156. # Python 2.6 raises an IOError here. Let's not repeat that mistake.
  157. w_error = space.call_function(space.w_OSError, space.wrap(e.errno),
  158. space.wrap(e.strerror),
  159. space.wrap(e.filename))
  160. raise OperationError(space.w_OSError, w_error)
  161. raise AssertionError
  162. except OSError as e:
  163. raise wrap_oserror(space, e)
  164. def fsync(space, w_fd):
  165. """Force write of file with filedescriptor to disk."""
  166. fd = space.c_filedescriptor_w(w_fd)
  167. try:
  168. os.fsync(fd)
  169. except OSError as e:
  170. raise wrap_oserror(space, e)
  171. def fdatasync(space, w_fd):
  172. """Force write of file with filedescriptor to disk.
  173. Does not force update of metadata."""
  174. fd = space.c_filedescriptor_w(w_fd)
  175. try:
  176. os.fdatasync(fd)
  177. except OSError as e:
  178. raise wrap_oserror(space, e)
  179. def fchdir(space, w_fd):
  180. """Change to the directory of the given file descriptor. fildes must be
  181. opened on a directory, not a file."""
  182. fd = space.c_filedescriptor_w(w_fd)
  183. try:
  184. os.fchdir(fd)
  185. except OSError as e:
  186. raise wrap_oserror(space, e)
  187. # ____________________________________________________________
  188. STAT_FIELDS = unrolling_iterable(enumerate(rposix_stat.STAT_FIELDS))
  189. STATVFS_FIELDS = unrolling_iterable(enumerate(rposix_stat.STATVFS_FIELDS))
  190. def build_stat_result(space, st):
  191. FIELDS = STAT_FIELDS # also when not translating at all
  192. lst = [None] * rposix_stat.N_INDEXABLE_FIELDS
  193. w_keywords = space.newdict()
  194. stat_float_times = space.fromcache(StatState).stat_float_times
  195. for i, (name, TYPE) in FIELDS:
  196. value = getattr(st, name)
  197. if name in ('st_atime', 'st_mtime', 'st_ctime'):
  198. value = int(value) # rounded to an integer for indexed access
  199. w_value = space.wrap(value)
  200. if i < rposix_stat.N_INDEXABLE_FIELDS:
  201. lst[i] = w_value
  202. else:
  203. space.setitem(w_keywords, space.wrap(name), w_value)
  204. # non-rounded values for name-based access
  205. if stat_float_times:
  206. space.setitem(w_keywords,
  207. space.wrap('st_atime'), space.wrap(st.st_atime))
  208. space.setitem(w_keywords,
  209. space.wrap('st_mtime'), space.wrap(st.st_mtime))
  210. space.setitem(w_keywords,
  211. space.wrap('st_ctime'), space.wrap(st.st_ctime))
  212. else:
  213. space.setitem(w_keywords,
  214. space.wrap('st_atime'), space.wrap(int(st.st_atime)))
  215. space.setitem(w_keywords,
  216. space.wrap('st_mtime'), space.wrap(int(st.st_mtime)))
  217. space.setitem(w_keywords,
  218. space.wrap('st_ctime'), space.wrap(int(st.st_ctime)))
  219. w_tuple = space.newtuple(lst)
  220. w_stat_result = space.getattr(space.getbuiltinmodule(os.name),
  221. space.wrap('stat_result'))
  222. return space.call_function(w_stat_result, w_tuple, w_keywords)
  223. def build_statvfs_result(space, st):
  224. vals_w = [None] * len(rposix_stat.STATVFS_FIELDS)
  225. for i, (name, _) in STATVFS_FIELDS:
  226. vals_w[i] = space.wrap(getattr(st, name))
  227. w_tuple = space.newtuple(vals_w)
  228. w_statvfs_result = space.getattr(space.getbuiltinmodule(os.name), space.wrap('statvfs_result'))
  229. return space.call_function(w_statvfs_result, w_tuple)
  230. @unwrap_spec(fd=c_int)
  231. def fstat(space, fd):
  232. """Perform a stat system call on the file referenced to by an open
  233. file descriptor."""
  234. try:
  235. st = rposix_stat.fstat(fd)
  236. except OSError as e:
  237. raise wrap_oserror(space, e)
  238. else:
  239. return build_stat_result(space, st)
  240. def stat(space, w_path):
  241. """Perform a stat system call on the given path. Return an object
  242. with (at least) the following attributes:
  243. st_mode
  244. st_ino
  245. st_dev
  246. st_nlink
  247. st_uid
  248. st_gid
  249. st_size
  250. st_atime
  251. st_mtime
  252. st_ctime
  253. """
  254. try:
  255. st = dispatch_filename(rposix_stat.stat)(space, w_path)
  256. except OSError as e:
  257. raise wrap_oserror2(space, e, w_path)
  258. else:
  259. return build_stat_result(space, st)
  260. def lstat(space, w_path):
  261. "Like stat(path), but do not follow symbolic links."
  262. try:
  263. st = dispatch_filename(rposix_stat.lstat)(space, w_path)
  264. except OSError as e:
  265. raise wrap_oserror2(space, e, w_path)
  266. else:
  267. return build_stat_result(space, st)
  268. class StatState(object):
  269. def __init__(self, space):
  270. self.stat_float_times = True
  271. def stat_float_times(space, w_value=None):
  272. """stat_float_times([newval]) -> oldval
  273. Determine whether os.[lf]stat represents time stamps as float objects.
  274. If newval is True, future calls to stat() return floats, if it is False,
  275. future calls return ints.
  276. If newval is omitted, return the current setting.
  277. """
  278. state = space.fromcache(StatState)
  279. if w_value is None:
  280. return space.wrap(state.stat_float_times)
  281. else:
  282. state.stat_float_times = space.bool_w(w_value)
  283. @unwrap_spec(fd=c_int)
  284. def fstatvfs(space, fd):
  285. try:
  286. st = rposix_stat.fstatvfs(fd)
  287. except OSError as e:
  288. raise wrap_oserror(space, e)
  289. else:
  290. return build_statvfs_result(space, st)
  291. def statvfs(space, w_path):
  292. try:
  293. st = dispatch_filename(rposix_stat.statvfs)(space, w_path)
  294. except OSError as e:
  295. raise wrap_oserror2(space, e, w_path)
  296. else:
  297. return build_statvfs_result(space, st)
  298. @unwrap_spec(fd=c_int)
  299. def dup(space, fd):
  300. """Create a copy of the file descriptor. Return the new file
  301. descriptor."""
  302. try:
  303. newfd = os.dup(fd)
  304. except OSError as e:
  305. raise wrap_oserror(space, e)
  306. else:
  307. return space.wrap(newfd)
  308. @unwrap_spec(old_fd=c_int, new_fd=c_int)
  309. def dup2(space, old_fd, new_fd):
  310. """Duplicate a file descriptor."""
  311. try:
  312. os.dup2(old_fd, new_fd)
  313. except OSError as e:
  314. raise wrap_oserror(space, e)
  315. @unwrap_spec(mode=c_int)
  316. def access(space, w_path, mode):
  317. """
  318. access(path, mode) -> 1 if granted, 0 otherwise
  319. Use the real uid/gid to test for access to a path. Note that most
  320. operations will use the effective uid/gid, therefore this routine can
  321. be used in a suid/sgid environment to test if the invoking user has the
  322. specified access to the path. The mode argument can be F_OK to test
  323. existence, or the inclusive-OR of R_OK, W_OK, and X_OK.
  324. """
  325. try:
  326. ok = dispatch_filename(rposix.access)(space, w_path, mode)
  327. except OSError as e:
  328. raise wrap_oserror2(space, e, w_path)
  329. else:
  330. return space.wrap(ok)
  331. def times(space):
  332. """
  333. times() -> (utime, stime, cutime, cstime, elapsed_time)
  334. Return a tuple of floating point numbers indicating process times.
  335. """
  336. try:
  337. times = os.times()
  338. except OSError as e:
  339. raise wrap_oserror(space, e)
  340. else:
  341. return space.newtuple([space.wrap(times[0]),
  342. space.wrap(times[1]),
  343. space.wrap(times[2]),
  344. space.wrap(times[3]),
  345. space.wrap(times[4])])
  346. @unwrap_spec(cmd='str0')
  347. def system(space, cmd):
  348. """Execute the command (a string) in a subshell."""
  349. try:
  350. rc = os.system(cmd)
  351. except OSError as e:
  352. raise wrap_oserror(space, e)
  353. else:
  354. return space.wrap(rc)
  355. def unlink(space, w_path):
  356. """Remove a file (same as remove(path))."""
  357. try:
  358. dispatch_filename(rposix.unlink)(space, w_path)
  359. except OSError as e:
  360. raise wrap_oserror2(space, e, w_path)
  361. def remove(space, w_path):
  362. """Remove a file (same as unlink(path))."""
  363. try:
  364. dispatch_filename(rposix.unlink)(space, w_path)
  365. except OSError as e:
  366. raise wrap_oserror2(space, e, w_path)
  367. def _getfullpathname(space, w_path):
  368. """helper for ntpath.abspath """
  369. try:
  370. if space.isinstance_w(w_path, space.w_unicode):
  371. path = FileEncoder(space, w_path)
  372. fullpath = rposix.getfullpathname(path)
  373. w_fullpath = space.wrap(fullpath)
  374. else:
  375. path = space.str0_w(w_path)
  376. fullpath = rposix.getfullpathname(path)
  377. w_fullpath = space.wrap(fullpath)
  378. except OSError as e:
  379. raise wrap_oserror2(space, e, w_path)
  380. else:
  381. return w_fullpath
  382. def getcwd(space):
  383. """Return the current working directory."""
  384. try:
  385. cur = os.getcwd()
  386. except OSError as e:
  387. raise wrap_oserror(space, e)
  388. else:
  389. return space.wrap(cur)
  390. if _WIN32:
  391. def getcwdu(space):
  392. """Return the current working directory as a unicode string."""
  393. try:
  394. cur = os.getcwdu()
  395. except OSError as e:
  396. raise wrap_oserror(space, e)
  397. else:
  398. return space.wrap(cur)
  399. else:
  400. def getcwdu(space):
  401. """Return the current working directory as a unicode string."""
  402. w_filesystemencoding = getfilesystemencoding(space)
  403. return space.call_method(getcwd(space), 'decode',
  404. w_filesystemencoding)
  405. def chdir(space, w_path):
  406. """Change the current working directory to the specified path."""
  407. try:
  408. dispatch_filename(rposix.chdir)(space, w_path)
  409. except OSError as e:
  410. raise wrap_oserror2(space, e, w_path)
  411. @unwrap_spec(mode=c_int)
  412. def mkdir(space, w_path, mode=0777):
  413. """Create a directory."""
  414. try:
  415. dispatch_filename(rposix.mkdir)(space, w_path, mode)
  416. except OSError as e:
  417. raise wrap_oserror2(space, e, w_path)
  418. def rmdir(space, w_path):
  419. """Remove a directory."""
  420. try:
  421. dispatch_filename(rposix.rmdir)(space, w_path)
  422. except OSError as e:
  423. raise wrap_oserror2(space, e, w_path)
  424. @unwrap_spec(errno=c_int)
  425. def strerror(space, errno):
  426. """Translate an error code to a message string."""
  427. try:
  428. text = os.strerror(errno)
  429. except ValueError:
  430. raise oefmt(space.w_ValueError, "strerror() argument out of range")
  431. return space.wrap(text)
  432. def getlogin(space):
  433. """Return the currently logged in user."""
  434. try:
  435. cur = os.getlogin()
  436. except OSError as e:
  437. raise wrap_oserror(space, e)
  438. else:
  439. return space.wrap(cur)
  440. # ____________________________________________________________
  441. def getstatfields(space):
  442. # for app_posix.py: export the list of 'st_xxx' names that we know
  443. # about at RPython level
  444. return space.newlist([space.wrap(name) for _, (name, _) in STAT_FIELDS])
  445. class State:
  446. def __init__(self, space):
  447. self.space = space
  448. self.w_environ = space.newdict()
  449. self.random_context = rurandom.init_urandom()
  450. def startup(self, space):
  451. _convertenviron(space, self.w_environ)
  452. def _freeze_(self):
  453. # don't capture the environment in the translated pypy
  454. self.space.call_method(self.w_environ, 'clear')
  455. # also reset random_context to a fresh new context (empty so far,
  456. # to be filled at run-time by rurandom.urandom())
  457. self.random_context = rurandom.init_urandom()
  458. return True
  459. def get(space):
  460. return space.fromcache(State)
  461. def _convertenviron(space, w_env):
  462. space.call_method(w_env, 'clear')
  463. for key, value in os.environ.items():
  464. space.setitem(w_env, space.wrap(key), space.wrap(value))
  465. @unwrap_spec(name='str0', value='str0')
  466. def putenv(space, name, value):
  467. """Change or add an environment variable."""
  468. if _WIN32 and len(name) > _MAX_ENV:
  469. raise oefmt(space.w_ValueError,
  470. "the environment variable is longer than %d bytes",
  471. _MAX_ENV)
  472. if _WIN32 and not objectmodel.we_are_translated() and value == '':
  473. # special case: on Windows, _putenv("NAME=") really means that
  474. # we want to delete NAME. So that's what the os.environ[name]=''
  475. # below will do after translation. But before translation, it
  476. # will cache the environment value '' instead of <missing> and
  477. # then return that. We need to avoid that.
  478. del os.environ[name]
  479. return
  480. try:
  481. os.environ[name] = value
  482. except OSError as e:
  483. raise wrap_oserror(space, e)
  484. @unwrap_spec(name='str0')
  485. def unsetenv(space, name):
  486. """Delete an environment variable."""
  487. try:
  488. del os.environ[name]
  489. except KeyError:
  490. pass
  491. except OSError as e:
  492. raise wrap_oserror(space, e)
  493. def listdir(space, w_dirname):
  494. """Return a list containing the names of the entries in the directory.
  495. \tpath: path of directory to list
  496. The list is in arbitrary order. It does not include the special
  497. entries '.' and '..' even if they are present in the directory."""
  498. try:
  499. if space.isinstance_w(w_dirname, space.w_unicode):
  500. dirname = FileEncoder(space, w_dirname)
  501. result = rposix.listdir(dirname)
  502. w_fs_encoding = getfilesystemencoding(space)
  503. len_result = len(result)
  504. result_w = [None] * len_result
  505. for i in range(len_result):
  506. w_bytes = space.wrap(result[i])
  507. try:
  508. result_w[i] = space.call_method(w_bytes,
  509. "decode", w_fs_encoding)
  510. except OperationError as e:
  511. # fall back to the original byte string
  512. result_w[i] = w_bytes
  513. return space.newlist(result_w)
  514. else:
  515. dirname = space.str0_w(w_dirname)
  516. result = rposix.listdir(dirname)
  517. # The list comprehension is a workaround for an obscure translation
  518. # bug.
  519. return space.newlist_bytes([x for x in result])
  520. except OSError as e:
  521. raise wrap_oserror2(space, e, w_dirname)
  522. def pipe(space):
  523. "Create a pipe. Returns (read_end, write_end)."
  524. try:
  525. fd1, fd2 = os.pipe()
  526. except OSError as e:
  527. raise wrap_oserror(space, e)
  528. return space.newtuple([space.wrap(fd1), space.wrap(fd2)])
  529. @unwrap_spec(mode=c_int)
  530. def chmod(space, w_path, mode):
  531. "Change the access permissions of a file."
  532. try:
  533. dispatch_filename(rposix.chmod)(space, w_path, mode)
  534. except OSError as e:
  535. raise wrap_oserror2(space, e, w_path)
  536. @unwrap_spec(mode=c_int)
  537. def fchmod(space, w_fd, mode):
  538. """Change the access permissions of the file given by file
  539. descriptor fd."""
  540. fd = space.c_filedescriptor_w(w_fd)
  541. try:
  542. os.fchmod(fd, mode)
  543. except OSError as e:
  544. raise wrap_oserror(space, e)
  545. def rename(space, w_old, w_new):
  546. "Rename a file or directory."
  547. try:
  548. dispatch_filename_2(rposix.rename)(space, w_old, w_new)
  549. except OSError as e:
  550. raise wrap_oserror(space, e)
  551. @unwrap_spec(mode=c_int)
  552. def mkfifo(space, w_filename, mode=0666):
  553. """Create a FIFO (a POSIX named pipe)."""
  554. try:
  555. dispatch_filename(rposix.mkfifo)(space, w_filename, mode)
  556. except OSError as e:
  557. raise wrap_oserror2(space, e, w_filename)
  558. @unwrap_spec(mode=c_int, device=c_int)
  559. def mknod(space, w_filename, mode=0600, device=0):
  560. """Create a filesystem node (file, device special file or named pipe)
  561. named filename. mode specifies both the permissions to use and the
  562. type of node to be created, being combined (bitwise OR) with one of
  563. S_IFREG, S_IFCHR, S_IFBLK, and S_IFIFO. For S_IFCHR and S_IFBLK,
  564. device defines the newly created device special file (probably using
  565. os.makedev()), otherwise it is ignored."""
  566. try:
  567. dispatch_filename(rposix.mknod)(space, w_filename, mode, device)
  568. except OSError as e:
  569. raise wrap_oserror2(space, e, w_filename)
  570. @unwrap_spec(mask=c_int)
  571. def umask(space, mask):
  572. "Set the current numeric umask and return the previous umask."
  573. prevmask = os.umask(mask)
  574. return space.wrap(prevmask)
  575. def getpid(space):
  576. "Return the current process id."
  577. try:
  578. pid = os.getpid()
  579. except OSError as e:
  580. raise wrap_oserror(space, e)
  581. return space.wrap(pid)
  582. @unwrap_spec(pid=c_int, sig=c_int)
  583. def kill(space, pid, sig):
  584. "Kill a process with a signal."
  585. try:
  586. rposix.kill(pid, sig)
  587. except OSError as e:
  588. raise wrap_oserror(space, e)
  589. @unwrap_spec(pgid=c_int, sig=c_int)
  590. def killpg(space, pgid, sig):
  591. "Kill a process group with a signal."
  592. try:
  593. os.killpg(pgid, sig)
  594. except OSError as e:
  595. raise wrap_oserror(space, e)
  596. def abort(space):
  597. """Abort the interpreter immediately. This 'dumps core' or otherwise fails
  598. in the hardest way possible on the hosting operating system."""
  599. import signal
  600. rposix.kill(os.getpid(), signal.SIGABRT)
  601. @unwrap_spec(src='str0', dst='str0')
  602. def link(space, src, dst):
  603. "Create a hard link to a file."
  604. try:
  605. os.link(src, dst)
  606. except OSError as e:
  607. raise wrap_oserror(space, e)
  608. def symlink(space, w_src, w_dst):
  609. "Create a symbolic link pointing to src named dst."
  610. try:
  611. dispatch_filename_2(rposix.symlink)(space, w_src, w_dst)
  612. except OSError as e:
  613. raise wrap_oserror(space, e)
  614. @unwrap_spec(path='str0')
  615. def readlink(space, path):
  616. "Return a string representing the path to which the symbolic link points."
  617. try:
  618. result = os.readlink(path)
  619. except OSError as e:
  620. raise wrap_oserror(space, e, path)
  621. return space.wrap(result)
  622. before_fork_hooks = []
  623. after_fork_child_hooks = []
  624. after_fork_parent_hooks = []
  625. @specialize.memo()
  626. def get_fork_hooks(where):
  627. if where == 'before':
  628. return before_fork_hooks
  629. elif where == 'child':
  630. return after_fork_child_hooks
  631. elif where == 'parent':
  632. return after_fork_parent_hooks
  633. else:
  634. assert False, "Unknown fork hook"
  635. def add_fork_hook(where, hook):
  636. "NOT_RPYTHON"
  637. get_fork_hooks(where).append(hook)
  638. add_fork_hook('child', ExecutionContext._mark_thread_disappeared)
  639. @specialize.arg(0)
  640. def run_fork_hooks(where, space):
  641. for hook in get_fork_hooks(where):
  642. hook(space)
  643. def _run_forking_function(space, kind):
  644. run_fork_hooks('before', space)
  645. try:
  646. if kind == "F":
  647. pid = os.fork()
  648. master_fd = -1
  649. elif kind == "P":
  650. pid, master_fd = os.forkpty()
  651. else:
  652. raise AssertionError
  653. except OSError as e:
  654. try:
  655. run_fork_hooks('parent', space)
  656. except:
  657. # Don't clobber the OSError if the fork failed
  658. pass
  659. raise wrap_oserror(space, e)
  660. if pid == 0:
  661. run_fork_hooks('child', space)
  662. else:
  663. run_fork_hooks('parent', space)
  664. return pid, master_fd
  665. def fork(space):
  666. pid, irrelevant = _run_forking_function(space, "F")
  667. return space.wrap(pid)
  668. def openpty(space):
  669. "Open a pseudo-terminal, returning open fd's for both master and slave end."
  670. try:
  671. master_fd, slave_fd = os.openpty()
  672. except OSError as e:
  673. raise wrap_oserror(space, e)
  674. return space.newtuple([space.wrap(master_fd), space.wrap(slave_fd)])
  675. def forkpty(space):
  676. pid, master_fd = _run_forking_function(space, "P")
  677. return space.newtuple([space.wrap(pid),
  678. space.wrap(master_fd)])
  679. @unwrap_spec(pid=c_int, options=c_int)
  680. def waitpid(space, pid, options):
  681. """ waitpid(pid, options) -> (pid, status)
  682. Wait for completion of a given child process.
  683. """
  684. try:
  685. pid, status = os.waitpid(pid, options)
  686. except OSError as e:
  687. raise wrap_oserror(space, e)
  688. return space.newtuple([space.wrap(pid), space.wrap(status)])
  689. @unwrap_spec(status=c_int)
  690. def _exit(space, status):
  691. os._exit(status)
  692. def execv(space, w_command, w_args):
  693. """ execv(path, args)
  694. Execute an executable path with arguments, replacing current process.
  695. path: path of executable file
  696. args: iterable of strings
  697. """
  698. execve(space, w_command, w_args, None)
  699. def _env2interp(space, w_env):
  700. env = {}
  701. w_keys = space.call_method(w_env, 'keys')
  702. for w_key in space.unpackiterable(w_keys):
  703. w_value = space.getitem(w_env, w_key)
  704. env[space.str0_w(w_key)] = space.str0_w(w_value)
  705. return env
  706. def execve(space, w_command, w_args, w_env):
  707. """ execve(path, args, env)
  708. Execute a path with arguments and environment, replacing current process.
  709. path: path of executable file
  710. args: iterable of arguments
  711. env: dictionary of strings mapping to strings
  712. """
  713. command = fsencode_w(space, w_command)
  714. try:
  715. args_w = space.unpackiterable(w_args)
  716. if len(args_w) < 1:
  717. raise oefmt(space.w_ValueError,
  718. "execv() must have at least one argument")
  719. args = [fsencode_w(space, w_arg) for w_arg in args_w]
  720. except OperationError as e:
  721. if not e.match(space, space.w_TypeError):
  722. raise
  723. raise oefmt(space.w_TypeError,
  724. "execv() arg 2 must be an iterable of strings")
  725. #
  726. if w_env is None: # when called via execv() above
  727. try:
  728. os.execv(command, args)
  729. except OSError as e:
  730. raise wrap_oserror(space, e)
  731. else:
  732. env = _env2interp(space, w_env)
  733. try:
  734. os.execve(command, args, env)
  735. except OSError as e:
  736. raise wrap_oserror(space, e)
  737. @unwrap_spec(mode=int, path='str0')
  738. def spawnv(space, mode, path, w_args):
  739. args = [space.str0_w(w_arg) for w_arg in space.unpackiterable(w_args)]
  740. try:
  741. ret = os.spawnv(mode, path, args)
  742. except OSError as e:
  743. raise wrap_oserror(space, e)
  744. return space.wrap(ret)
  745. @unwrap_spec(mode=int, path='str0')
  746. def spawnve(space, mode, path, w_args, w_env):
  747. args = [space.str0_w(w_arg) for w_arg in space.unpackiterable(w_args)]
  748. env = _env2interp(space, w_env)
  749. try:
  750. ret = os.spawnve(mode, path, args, env)
  751. except OSError as e:
  752. raise wrap_oserror(space, e)
  753. return space.wrap(ret)
  754. def utime(space, w_path, w_tuple):
  755. """ utime(path, (atime, mtime))
  756. utime(path, None)
  757. Set the access and modified time of the file to the given values. If the
  758. second form is used, set the access and modified times to the current time.
  759. """
  760. if space.is_w(w_tuple, space.w_None):
  761. try:
  762. dispatch_filename(rposix.utime, 1)(space, w_path, None)
  763. return
  764. except OSError as e:
  765. raise wrap_oserror2(space, e, w_path)
  766. try:
  767. msg = "utime() arg 2 must be a tuple (atime, mtime) or None"
  768. args_w = space.fixedview(w_tuple)
  769. if len(args_w) != 2:
  770. raise oefmt(space.w_TypeError, msg)
  771. actime = space.float_w(args_w[0], allow_conversion=False)
  772. modtime = space.float_w(args_w[1], allow_conversion=False)
  773. dispatch_filename(rposix.utime, 2)(space, w_path, (actime, modtime))
  774. except OSError as e:
  775. raise wrap_oserror2(space, e, w_path)
  776. except OperationError as e:
  777. if not e.match(space, space.w_TypeError):
  778. raise
  779. raise oefmt(space.w_TypeError, msg)
  780. def uname(space):
  781. """ uname() -> (sysname, nodename, release, version, machine)
  782. Return a tuple identifying the current operating system.
  783. """
  784. try:
  785. r = os.uname()
  786. except OSError as e:
  787. raise wrap_oserror(space, e)
  788. l_w = [space.wrap(i) for i in [r[0], r[1], r[2], r[3], r[4]]]
  789. return space.newtuple(l_w)
  790. def getuid(space):
  791. """ getuid() -> uid
  792. Return the current process's user id.
  793. """
  794. return wrap_uid(space, os.getuid())
  795. @unwrap_spec(arg=c_uid_t)
  796. def setuid(space, arg):
  797. """ setuid(uid)
  798. Set the current process's user id.
  799. """
  800. try:
  801. os.setuid(arg)
  802. except OSError as e:
  803. raise wrap_oserror(space, e)
  804. @unwrap_spec(arg=c_uid_t)
  805. def seteuid(space, arg):
  806. """ seteuid(uid)
  807. Set the current process's effective user id.
  808. """
  809. try:
  810. os.seteuid(arg)
  811. except OSError as e:
  812. raise wrap_oserror(space, e)
  813. @unwrap_spec(arg=c_gid_t)
  814. def setgid(space, arg):
  815. """ setgid(gid)
  816. Set the current process's group id.
  817. """
  818. try:
  819. os.setgid(arg)
  820. except OSError as e:
  821. raise wrap_oserror(space, e)
  822. @unwrap_spec(arg=c_gid_t)
  823. def setegid(space, arg):
  824. """ setegid(gid)
  825. Set the current process's effective group id.
  826. """
  827. try:
  828. os.setegid(arg)
  829. except OSError as e:
  830. raise wrap_oserror(space, e)
  831. @unwrap_spec(path='str0')
  832. def chroot(space, path):
  833. """ chroot(path)
  834. Change root directory to path.
  835. """
  836. try:
  837. os.chroot(path)
  838. except OSError as e:
  839. raise wrap_oserror(space, e, path)
  840. return space.w_None
  841. def getgid(space):
  842. """ getgid() -> gid
  843. Return the current process's group id.
  844. """
  845. return wrap_gid(space, os.getgid())
  846. def getegid(space):
  847. """ getegid() -> gid
  848. Return the current process's effective group id.
  849. """
  850. return wrap_gid(space, os.getegid())
  851. def geteuid(space):
  852. """ geteuid() -> euid
  853. Return the current process's effective user id.
  854. """
  855. return wrap_uid(space, os.geteuid())
  856. def getgroups(space):
  857. """ getgroups() -> list of group IDs
  858. Return list of supplemental group IDs for the process.
  859. """
  860. try:
  861. list = os.getgroups()
  862. except OSError as e:
  863. raise wrap_oserror(space, e)
  864. return space.newlist([wrap_gid(space, e) for e in list])
  865. def setgroups(space, w_list):
  866. """ setgroups(list)
  867. Set the groups of the current process to list.
  868. """
  869. list = []
  870. for w_gid in space.unpackiterable(w_list):
  871. list.append(space.c_uid_t_w(w_gid))
  872. try:
  873. os.setgroups(list[:])
  874. except OSError as e:
  875. raise wrap_oserror(space, e)
  876. @unwrap_spec(username=str, gid=c_gid_t)
  877. def initgroups(space, username, gid):
  878. """ initgroups(username, gid) -> None
  879. Call the system initgroups() to initialize the group access list with all of
  880. the groups of which the specified username is a member, plus the specified
  881. group id.
  882. """
  883. try:
  884. os.initgroups(username, gid)
  885. except OSError as e:
  886. raise wrap_oserror(space, e)
  887. def getpgrp(space):
  888. """ getpgrp() -> pgrp
  889. Return the current process group id.
  890. """
  891. return space.wrap(os.getpgrp())
  892. def setpgrp(space):
  893. """ setpgrp()
  894. Make this process a session leader.
  895. """
  896. try:
  897. os.setpgrp()
  898. except OSError as e:
  899. raise wrap_oserror(space, e)
  900. return space.w_None
  901. def getppid(space):
  902. """ getppid() -> ppid
  903. Return the parent's process id.
  904. """
  905. return space.wrap(os.getppid())
  906. @unwrap_spec(pid=c_int)
  907. def getpgid(space, pid):
  908. """ getpgid(pid) -> pgid
  909. Call the system call getpgid().
  910. """
  911. try:
  912. pgid = os.getpgid(pid)
  913. except OSError as e:
  914. raise wrap_oserror(space, e)
  915. return space.wrap(pgid)
  916. @unwrap_spec(pid=c_int, pgrp=c_int)
  917. def setpgid(space, pid, pgrp):
  918. """ setpgid(pid, pgrp)
  919. Call the system call setpgid().
  920. """
  921. try:
  922. os.setpgid(pid, pgrp)
  923. except OSError as e:
  924. raise wrap_oserror(space, e)
  925. return space.w_None
  926. @unwrap_spec(ruid=c_uid_t, euid=c_uid_t)
  927. def setreuid(space, ruid, euid):
  928. """ setreuid(ruid, euid)
  929. Set the current process's real and effective user ids.
  930. """
  931. try:
  932. os.setreuid(ruid, euid)
  933. except OSError as e:
  934. raise wrap_oserror(space, e)
  935. @unwrap_spec(rgid=c_gid_t, egid=c_gid_t)
  936. def setregid(space, rgid, egid):
  937. """ setregid(rgid, egid)
  938. Set the current process's real and effective group ids.
  939. """
  940. try:
  941. os.setregid(rgid, egid)
  942. except OSError as e:
  943. raise wrap_oserror(space, e)
  944. @unwrap_spec(pid=c_int)
  945. def getsid(space, pid):
  946. """ getsid(pid) -> sid
  947. Call the system call getsid().
  948. """
  949. try:
  950. sid = os.getsid(pid)
  951. except OSError as e:
  952. raise wrap_oserror(space, e)
  953. return space.wrap(sid)
  954. def setsid(space):
  955. """ setsid()
  956. Call the system call setsid().
  957. """
  958. try:
  959. os.setsid()
  960. except OSError as e:
  961. raise wrap_oserror(space, e)
  962. return space.w_None
  963. @unwrap_spec(fd=c_int)
  964. def tcgetpgrp(space, fd):
  965. """ tcgetpgrp(fd) -> pgid
  966. Return the process group associated with the terminal given by a fd.
  967. """
  968. try:
  969. pgid = os.tcgetpgrp(fd)
  970. except OSError as e:
  971. raise wrap_oserror(space, e)
  972. return space.wrap(pgid)
  973. @unwrap_spec(fd=c_int, pgid=c_int)
  974. def tcsetpgrp(space, fd, pgid):
  975. """ tcsetpgrp(fd, pgid)
  976. Set the process group associated with the terminal given by a fd.
  977. """
  978. try:
  979. os.tcsetpgrp(fd, pgid)
  980. except OSError as e:
  981. raise wrap_oserror(space, e)
  982. def getresuid(space):
  983. """ getresuid() -> (ruid, euid, suid)
  984. Get tuple of the current process's real, effective, and saved user ids.
  985. """
  986. try:
  987. (ruid, euid, suid) = os.getresuid()
  988. except OSError as e:
  989. raise wrap_oserror(space, e)
  990. return space.newtuple([wrap_uid(space, ruid),
  991. wrap_uid(space, euid),
  992. wrap_uid(space, suid)])
  993. def getresgid(space):
  994. """ getresgid() -> (rgid, egid, sgid)
  995. Get tuple of the current process's real, effective, and saved group ids.
  996. """
  997. try:
  998. (rgid, egid, sgid) = os.getresgid()
  999. except OSError as e:
  1000. raise wrap_oserror(space, e)
  1001. return space.newtuple([wrap_gid(space, rgid),
  1002. wrap_gid(space, egid),
  1003. wrap_gid(space, sgid)])
  1004. @unwrap_spec(ruid=c_uid_t, euid=c_uid_t, suid=c_uid_t)
  1005. def setresuid(space, ruid, euid, suid):
  1006. """ setresuid(ruid, euid, suid)
  1007. Set the current process's real, effective, and saved user ids.
  1008. """
  1009. try:
  1010. os.setresuid(ruid, euid, suid)
  1011. except OSError as e:
  1012. raise wrap_oserror(space, e)
  1013. @unwrap_spec(rgid=c_gid_t, egid=c_gid_t, sgid=c_gid_t)
  1014. def setresgid(space, rgid, egid, sgid):
  1015. """ setresgid(rgid, egid, sgid)
  1016. Set the current process's real, effective, and saved group ids.
  1017. """
  1018. try:
  1019. os.setresgid(rgid, egid, sgid)
  1020. except OSError as e:
  1021. raise wrap_oserror(space, e)
  1022. def declare_new_w_star(name):
  1023. if name in ('WEXITSTATUS', 'WSTOPSIG', 'WTERMSIG'):
  1024. @unwrap_spec(status=c_int)
  1025. def WSTAR(space, status):
  1026. return space.wrap(getattr(os, name)(status))
  1027. else:
  1028. @unwrap_spec(status=c_int)
  1029. def WSTAR(space, status):
  1030. return space.newbool(getattr(os, name)(status))
  1031. WSTAR.__doc__ = getattr(os, name).__doc__
  1032. WSTAR.func_name = name
  1033. return WSTAR
  1034. for name in rposix.WAIT_MACROS:
  1035. if hasattr(os, name):
  1036. func = declare_new_w_star(name)
  1037. globals()[name] = func
  1038. @unwrap_spec(fd=c_int)
  1039. def ttyname(space, fd):
  1040. try:
  1041. return space.wrap(os.ttyname(fd))
  1042. except OSError as e:
  1043. raise wrap_oserror(space, e)
  1044. def confname_w(space, w_name, namespace):
  1045. # XXX slightly non-nice, reuses the sysconf of the underlying os module
  1046. if space.isinstance_w(w_name, space.w_basestring):
  1047. try:
  1048. num = namespace[space.str_w(w_name)]
  1049. except KeyError:
  1050. raise oefmt(space.w_ValueError, "unrecognized configuration name")
  1051. else:
  1052. num = space.int_w(w_name)
  1053. return num
  1054. def sysconf(space, w_name):
  1055. num = confname_w(space, w_name, os.sysconf_names)
  1056. try:
  1057. res = os.sysconf(num)
  1058. except OSError as e:
  1059. raise wrap_oserror(space, e)
  1060. return space.wrap(res)
  1061. @unwrap_spec(fd=c_int)
  1062. def fpathconf(space, fd, w_name):
  1063. num = confname_w(space, w_name, os.pathconf_names)
  1064. try:
  1065. res = os.fpathconf(fd, num)
  1066. except OSError as e:
  1067. raise wrap_oserror(space, e)
  1068. return space.wrap(res)
  1069. @unwrap_spec(path='str0')
  1070. def pathconf(space, path, w_name):
  1071. num = confname_w(space, w_name, os.pathconf_names)
  1072. try:
  1073. res = os.pathconf(path, num)
  1074. except OSError as e:
  1075. raise wrap_oserror(space, e)
  1076. return space.wrap(res)
  1077. def confstr(space, w_name):
  1078. num = confname_w(space, w_name, os.confstr_names)
  1079. try:
  1080. res = os.confstr(num)
  1081. except OSError as e:
  1082. raise wrap_oserror(space, e)
  1083. return space.wrap(res)
  1084. @unwrap_spec(path='str0', uid=c_uid_t, gid=c_gid_t)
  1085. def chown(space, path, uid, gid):
  1086. """Change the owner and group id of path to the numeric uid and gid."""
  1087. try:
  1088. os.chown(path, uid, gid)
  1089. except OSError as e:
  1090. raise wrap_oserror(space, e, path)
  1091. @unwrap_spec(path='str0', uid=c_uid_t, gid=c_gid_t)
  1092. def lchown(space, path, uid, gid):
  1093. """Change the owner and group id of path to the numeric uid and gid.
  1094. This function will not follow symbolic links."""
  1095. try:
  1096. os.lchown(path, uid, gid)
  1097. except OSError as e:
  1098. raise wrap_oserror(space, e, path)
  1099. @unwrap_spec(uid=c_uid_t, gid=c_gid_t)
  1100. def fchown(space, w_fd, uid, gid):
  1101. """Change the owner and group id of the file given by file descriptor
  1102. fd to the numeric uid and gid."""
  1103. fd = space.c_filedescriptor_w(w_fd)
  1104. try:
  1105. os.fchown(fd, uid, gid)
  1106. except OSError as e:
  1107. raise wrap_oserror(space, e)
  1108. def getloadavg(space):
  1109. try:
  1110. load = os.getloadavg()
  1111. except OSError:
  1112. raise oefmt(space.w_OSError, "Load averages are unobtainable")
  1113. return space.newtuple([space.wrap(load[0]),
  1114. space.wrap(load[1]),
  1115. space.wrap(load[2])])
  1116. @unwrap_spec(major=c_int, minor=c_int)
  1117. def makedev(space, major, minor):
  1118. result = os.makedev(major, minor)
  1119. return space.wrap(result)
  1120. @unwrap_spec(device="c_uint")
  1121. def major(space, device):
  1122. result = os.major(intmask(device))
  1123. return space.wrap(result)
  1124. @unwrap_spec(device="c_uint")
  1125. def minor(space, device):
  1126. result = os.minor(intmask(device))
  1127. return space.wrap(result)
  1128. @unwrap_spec(inc=c_int)
  1129. def nice(space, inc):
  1130. "Decrease the priority of process by inc and return the new priority."
  1131. try:
  1132. res = os.nice(inc)
  1133. except OSError as e:
  1134. raise wrap_oserror(space, e)
  1135. return space.wrap(res)
  1136. @unwrap_spec(n=int)
  1137. def urandom(space, n):
  1138. """urandom(n) -> str
  1139. Return a string of n random bytes suitable for cryptographic use.
  1140. """
  1141. context = get(space).random_context
  1142. try:
  1143. return space.wrap(rurandom.urandom(context, n))
  1144. except OSError as e:
  1145. raise wrap_oserror(space, e)
  1146. def ctermid(space):
  1147. """ctermid() -> string
  1148. Return the name of the controlling terminal for this process.
  1149. """
  1150. return space.wrap(os.ctermid())