posix.test 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. ;;;; posix.test --- Test suite for Guile POSIX functions. -*- scheme -*-
  2. ;;;;
  3. ;;;; Copyright 2003-2004, 2006-2007, 2010, 2012, 2015, 2017-2019, 2021-2022
  4. ;;;; Free Software Foundation, Inc.
  5. ;;;; Copyright 2021 Maxime Devos <maximedevos@telenet.be>
  6. ;;;;
  7. ;;;; This library is free software; you can redistribute it and/or
  8. ;;;; modify it under the terms of the GNU Lesser General Public
  9. ;;;; License as published by the Free Software Foundation; either
  10. ;;;; version 3 of the License, or (at your option) any later version.
  11. ;;;;
  12. ;;;; This library 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 GNU
  15. ;;;; Lesser General Public License for more details.
  16. ;;;;
  17. ;;;; You should have received a copy of the GNU Lesser General Public
  18. ;;;; License along with this library; if not, write to the Free Software
  19. ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20. (define-module (test-suite test-posix)
  21. :use-module (test-suite lib))
  22. ;; FIXME: The following exec tests are disabled since on an i386 debian with
  23. ;; glibc 2.3.2 they seem to interact badly with threads.test, the latter
  24. ;; dies with signal 32 (one of the SIGRTs). Don't know how or why, or who's
  25. ;; at fault (though it seems to happen with or without the recent memory
  26. ;; leak fix in these error cases).
  27. ;;
  28. ;; execl
  29. ;;
  30. ;; (with-test-prefix "execl"
  31. ;; (pass-if-exception "./nosuchprog" '(system-error . ".*")
  32. ;; (execl "./nosuchprog" "./nosuchprog" "some arg")))
  33. ;;
  34. ;; execlp
  35. ;;
  36. ;; (with-test-prefix "execlp"
  37. ;; (pass-if-exception "./nosuchprog" '(system-error . ".*")
  38. ;; (execlp "./nosuchprog" "./nosuchprog" "some arg")))
  39. ;;
  40. ;; execle
  41. ;;
  42. ;; (with-test-prefix "execle"
  43. ;; (pass-if-exception "./nosuchprog" '(system-error . ".*")
  44. ;; (execle "./nosuchprog" '() "./nosuchprog" "some arg"))
  45. ;; (pass-if-exception "./nosuchprog" '(system-error . ".*")
  46. ;; (execle "./nosuchprog" '("FOO=1" "BAR=2") "./nosuchprog" "some arg")))
  47. ;;
  48. ;; mkstemp
  49. ;;
  50. (with-test-prefix "mkstemp"
  51. ;; the temporary names used in the tests here are kept to 8 characters so
  52. ;; they'll work on a DOS 8.3 file system
  53. (define (string-copy str)
  54. (list->string (string->list str)))
  55. (pass-if-exception "number arg" exception:wrong-type-arg
  56. (mkstemp! 123))
  57. (pass-if "binary mode honored"
  58. (let* ((outport (mkstemp "T-XXXXXX" "wb"))
  59. (filename (port-filename outport)))
  60. (display "\n" outport)
  61. (close-port outport)
  62. (let* ((inport (open-input-file filename #:binary #t))
  63. (char1 (read-char inport))
  64. (char2 (read-char inport))
  65. (result (and (char=? char1 #\newline)
  66. (eof-object? char2))))
  67. (close-port inport)
  68. (delete-file filename)
  69. result))))
  70. ;;
  71. ;; putenv
  72. ;;
  73. (with-test-prefix "putenv"
  74. (pass-if "something"
  75. (putenv "FOO=something")
  76. (equal? "something" (getenv "FOO")))
  77. (pass-if "replacing"
  78. (putenv "FOO=one")
  79. (putenv "FOO=two")
  80. (equal? "two" (getenv "FOO")))
  81. (pass-if "empty"
  82. (putenv "FOO=")
  83. (equal? "" (getenv "FOO")))
  84. (pass-if "removing"
  85. (putenv "FOO=bar")
  86. (putenv "FOO")
  87. (not (getenv "FOO")))
  88. (pass-if "modifying string doesn't change env"
  89. (let ((s (string-copy "FOO=bar")))
  90. (putenv s)
  91. (string-set! s 5 #\x)
  92. (equal? "bar" (getenv "FOO")))))
  93. ;;
  94. ;; setenv
  95. ;;
  96. (with-test-prefix "setenv"
  97. (pass-if "something"
  98. (setenv "FOO" "something")
  99. (equal? "something" (getenv "FOO")))
  100. (pass-if "replacing"
  101. (setenv "FOO" "one")
  102. (setenv "FOO" "two")
  103. (equal? "two" (getenv "FOO")))
  104. (pass-if "empty"
  105. (setenv "FOO" "")
  106. (equal? "" (getenv "FOO")))
  107. (pass-if "removing"
  108. (setenv "FOO" "something")
  109. (setenv "FOO" #f)
  110. (not (getenv "FOO"))))
  111. ;;
  112. ;; unsetenv
  113. ;;
  114. (with-test-prefix "unsetenv"
  115. (pass-if "something"
  116. (putenv "FOO=something")
  117. (unsetenv "FOO")
  118. (not (getenv "FOO")))
  119. (pass-if "empty"
  120. (putenv "FOO=")
  121. (unsetenv "FOO")
  122. (not (getenv "FOO"))))
  123. ;;
  124. ;; ttyname
  125. ;;
  126. (with-test-prefix "ttyname"
  127. (pass-if-exception "non-tty argument" exception:system-error
  128. ;; This used to crash in 1.8.1 and earlier.
  129. (let ((file (false-if-exception
  130. (open-output-file "/dev/null"))))
  131. (if (not file)
  132. (throw 'unsupported)
  133. (ttyname file)))))
  134. ;;
  135. ;; utimes
  136. ;;
  137. (with-test-prefix "utime"
  138. (pass-if "valid argument (second resolution)"
  139. (let ((file "posix.test-utime"))
  140. (dynamic-wind
  141. (lambda ()
  142. (close-port (open-output-file file)))
  143. (lambda ()
  144. (let* ((accessed (+ (current-time) 3600))
  145. (modified (- accessed 1000)))
  146. (utime file accessed modified)
  147. (let ((info (stat file)))
  148. (and (= (stat:atime info) accessed)
  149. (= (stat:mtime info) modified)))))
  150. (lambda ()
  151. (delete-file file)))))
  152. (pass-if-equal "AT_SYMLINK_NOFOLLOW"
  153. '(1 1)
  154. (if (defined? 'AT_SYMLINK_NOFOLLOW)
  155. (let ((file "posix.test-utime"))
  156. (dynamic-wind
  157. (lambda ()
  158. (symlink "/dev/null" file))
  159. (lambda ()
  160. (utime file 1 1 0 0 AT_SYMLINK_NOFOLLOW)
  161. (let ((info (lstat file)))
  162. (list (stat:atime info) (stat:mtime info))))
  163. (lambda ()
  164. (delete-file file))))
  165. (throw 'unsupported)))
  166. (define (utime-unless-unsupported oops . arguments)
  167. (catch 'system-error
  168. (lambda ()
  169. (catch 'wrong-type-arg
  170. (lambda ()
  171. (apply utime arguments))
  172. (lambda _
  173. ;; 'futimens' is not supported on all platforms.
  174. (oops))))
  175. (lambda args
  176. ;; On some platforms, 'futimens' returns ENOSYS according to Gnulib.
  177. (if (= (system-error-errno args) ENOSYS)
  178. (oops)
  179. (apply throw args)))))
  180. (pass-if-equal "file port"
  181. '(1 1)
  182. (let ((file "posix.test-utime"))
  183. (false-if-exception (delete-file file))
  184. (close-port (open-output-file file))
  185. (define (delete)
  186. (delete-file file))
  187. (define (oops)
  188. (delete)
  189. (throw 'unsupported))
  190. (call-with-input-file file
  191. (lambda (port)
  192. (utime-unless-unsupported oops port 1 1 0 0)
  193. (define info (stat file))
  194. (delete)
  195. (list (stat:atime info) (stat:mtime info))))))
  196. ;; This causes an EBADF system error on GNU/Linux with the 5.10.46 kernel.
  197. #;
  198. (pass-if-equal "file port (port representing symbolic link)"
  199. '(1 1)
  200. (let ((file "posix.test-utime"))
  201. (unless (false-if-exception
  202. (begin (symlink "/should-be-irrelevant" file)
  203. #t))
  204. (display "cannot create symlink, a utime test skipped\n")
  205. (throw 'unresolved))
  206. (unless (and (defined? 'O_NOFOLLOW)
  207. (defined? 'O_PATH)
  208. (not (= 0 O_NOFOLLOW))
  209. (not (= 0 O_PATH)))
  210. (display "cannot open symlinks, a utime test skipped\n")
  211. (throw 'unresolved))
  212. (define (delete)
  213. (when port (close-port port))
  214. (false-if-exception (delete-file file)))
  215. (define (oops)
  216. (delete)
  217. (throw 'unsupported))
  218. (define port #f)
  219. (catch #t
  220. (lambda ()
  221. (set! port
  222. (open file (logior O_NOFOLLOW O_PATH)))
  223. (utime-unless-unsupported oops port 1 1 0 0))
  224. (lambda args
  225. (pk 'deleting file)
  226. (delete)
  227. (apply throw args)))
  228. (define info (lstat file))
  229. (delete)
  230. (list (stat:mtime info) (stat:atime info)))))
  231. ;;
  232. ;; affinity
  233. ;;
  234. (with-test-prefix "affinity"
  235. (pass-if "getaffinity"
  236. (if (defined? 'getaffinity)
  237. (> (bitvector-length (getaffinity (getpid))) 0)
  238. (throw 'unresolved)))
  239. (pass-if "setaffinity"
  240. (if (and (defined? 'setaffinity) (defined? 'getaffinity))
  241. (catch 'system-error
  242. (lambda ()
  243. (let ((mask (getaffinity (getpid))))
  244. (setaffinity (getpid) mask)
  245. (equal? mask (getaffinity (getpid)))))
  246. (lambda args
  247. ;; On some platforms such as sh4-linux-gnu, 'setaffinity'
  248. ;; returns ENOSYS.
  249. (let ((errno (system-error-errno args)))
  250. (if (= errno ENOSYS)
  251. (throw 'unresolved)
  252. (apply throw args)))))
  253. (throw 'unresolved))))
  254. ;;
  255. ;; pipe
  256. ;;
  257. (with-test-prefix "pipe"
  258. (pass-if-equal "in and out"
  259. "hi!\n"
  260. (let ((in+out (pipe)))
  261. (display "hi!\n" (cdr in+out))
  262. (close-port (cdr in+out))
  263. (let ((str (list->string (list (read-char (car in+out))
  264. (read-char (car in+out))
  265. (read-char (car in+out))
  266. (read-char (car in+out))))))
  267. (and (eof-object? (read-char (car in+out)))
  268. (begin
  269. (close-port (car in+out))
  270. str)))))
  271. (pass-if-equal "O_CLOEXEC"
  272. (list FD_CLOEXEC FD_CLOEXEC)
  273. (let* ((in+out (catch 'system-error
  274. (lambda ()
  275. (pipe O_CLOEXEC))
  276. (lambda args
  277. (if (= (system-error-errno args) ENOSYS)
  278. (throw 'unresolved)
  279. (apply throw args)))))
  280. (flags (list (fcntl (car in+out) F_GETFD)
  281. (fcntl (cdr in+out) F_GETFD))))
  282. (close-port (car in+out))
  283. (close-port (cdr in+out))
  284. flags)))
  285. ;;
  286. ;; system*
  287. ;;
  288. (with-test-prefix "system*"
  289. (pass-if "http://bugs.gnu.org/13166"
  290. ;; With Guile up to 2.0.7 included, the child process launched by
  291. ;; `system*' would remain alive after an `execvp' failure.
  292. (let ((me (getpid)))
  293. (and (not (zero? (system* "something-that-does-not-exist")))
  294. (= me (getpid)))))
  295. (pass-if-equal "exit code for nonexistent file"
  296. 127 ;aka. EX_NOTFOUND
  297. (status:exit-val (system* "something-that-does-not-exist")))
  298. (pass-if-equal "https://bugs.gnu.org/55596"
  299. 127
  300. ;; The parameterization below used to cause 'start_child' to close
  301. ;; fd 2 in the child process, which in turn would cause it to
  302. ;; segfault, leading to a wrong exit code.
  303. (parameterize ((current-output-port (current-error-port)))
  304. (status:exit-val (system* "something-that-does-not-exist")))))
  305. ;;
  306. ;; crypt
  307. ;;
  308. (with-test-prefix "crypt"
  309. (pass-if "basic usage"
  310. (if (not (defined? 'crypt))
  311. (throw 'unsupported)
  312. (string? (crypt "pass" "abcdefg"))))
  313. (pass-if "crypt invalid salt on glibc"
  314. (begin
  315. (unless (defined? 'crypt)
  316. (throw 'unsupported))
  317. (unless (string-contains %host-type "-gnu")
  318. (throw 'unresolved))
  319. (catch 'system-error
  320. (lambda ()
  321. ;; This used to deadlock on glibc while trying to throw to
  322. ;; 'system-error'. This test uses the special
  323. ;; interpretation of the salt that glibc does;
  324. ;; specifically, we pass a salt that's probably
  325. ;; syntactically invalid here. Note, whether it's invalid
  326. ;; or not is system-defined, so it's possible it just works.
  327. (string? (crypt "pass" "$X$abc")))
  328. (lambda _ #t)))))