1 ## compare_shells: dash bash mksh zsh
2 ## oils_failures_allowed: 2
3 ## oils_cpp_failures_allowed: 3
4 # case #24 with ulimit -f 1 is different under C++ for some reason - could be due to the python2
5 # intepreter and SIGXFSZ
6
7 #### exec builtin
8 exec echo hi
9 ## stdout: hi
10
11 #### exec builtin with redirects
12 exec 1>&2
13 echo 'to stderr'
14 ## stdout-json: ""
15 ## stderr: to stderr
16
17 #### exec builtin with here doc
18 # This has in a separate file because both code and data can be read from
19 # stdin.
20 $SH $REPO_ROOT/spec/bin/builtins-exec-here-doc-helper.sh
21 ## STDOUT:
22 x=one
23 y=two
24 DONE
25 ## END
26
27 #### exec builtin accepts --
28 exec -- echo hi
29 ## STDOUT:
30 hi
31 ## END
32 ## BUG dash status: 127
33 ## BUG dash stdout-json: ""
34
35 #### exec -- 2>&1
36 exec -- 3>&1
37 echo stdout 1>&3
38 ## STDOUT:
39 stdout
40 ## END
41 ## BUG dash status: 127
42 ## BUG dash stdout-json: ""
43 ## BUG mksh status: -11
44 ## BUG mksh stdout-json: ""
45
46 #### Exit out of function
47 f() { exit 3; }
48 f
49 exit 4
50 ## status: 3
51
52 #### Exit builtin with invalid arg
53 exit invalid
54 # Rationale: runtime errors are 1
55 ## status: 1
56 ## OK dash/bash status: 2
57 ## BUG zsh status: 0
58
59 #### Exit builtin with too many args
60 # This is a parse error in OSH.
61 exit 7 8 9
62 echo status=$?
63 ## status: 2
64 ## stdout-json: ""
65 ## BUG bash/zsh status: 0
66 ## BUG bash/zsh stdout: status=1
67 ## BUG dash status: 7
68 ## BUG dash stdout-json: ""
69 ## OK mksh status: 1
70 ## OK mksh stdout-json: ""
71
72 #### time with brace group argument
73
74 err=time-$(basename $SH).txt
75 {
76 time {
77 sleep 0.01
78 sleep 0.02
79 }
80 } 2> $err
81
82 grep --only-matching user $err
83 echo result=$?
84
85 # Regression: check fractional seconds
86 gawk '
87 BEGIN { ok = 0 }
88 match( $0, /\.([0-9]+)/, m) {
89 if (m[1] > 0) { # check fractional seconds
90 ok = 1
91 }
92 }
93 END { if (ok) { print "non-zero" } }
94 ' $err
95
96 ## status: 0
97 ## STDOUT:
98 user
99 result=0
100 non-zero
101 ## END
102
103 # time doesn't accept a block?
104 ## BUG zsh STDOUT:
105 result=1
106 ## END
107
108 # dash doesn't have time keyword
109 ## N-I dash status: 2
110 ## N-I dash stdout-json: ""
111
112
113 #### get umask
114 umask | grep '[0-9]\+' # check for digits
115 ## status: 0
116
117 #### set umask in octal
118 rm -f $TMP/umask-one $TMP/umask-two
119 umask 0002
120 echo one > $TMP/umask-one
121 umask 0022
122 echo two > $TMP/umask-two
123 stat -c '%a' $TMP/umask-one $TMP/umask-two
124 ## status: 0
125 ## STDOUT:
126 664
127 644
128 ## END
129 ## stderr-json: ""
130
131 #### set umask symbolically
132 umask 0002 # begin in a known state for the test
133 rm -f $TMP/umask-one $TMP/umask-two
134 echo one > $TMP/umask-one
135 umask g-w,o-w
136 echo two > $TMP/umask-two
137 stat -c '%a' $TMP/umask-one $TMP/umask-two
138 ## status: 0
139 ## STDOUT:
140 664
141 644
142 ## END
143 ## stderr-json: ""
144
145 #### ulimit with no flags is like -f
146
147 ulimit > no-flags.txt
148 echo status=$?
149
150 ulimit -f > f.txt
151 echo status=$?
152
153 diff -u no-flags.txt f.txt
154 echo diff=$?
155
156 # Print everything
157 # ulimit -a
158
159 ## STDOUT:
160 status=0
161 status=0
162 diff=0
163 ## END
164
165
166 #### ulimit too many args
167
168 ulimit 1 2
169 if test $? -ne 0; then
170 echo pass
171 else
172 echo fail
173 fi
174
175 #ulimit -f
176
177 ## STDOUT:
178 pass
179 ## END
180
181 ## BUG bash/zsh STDOUT:
182 fail
183 ## END
184
185
186 #### ulimit negative flag
187
188 ulimit -f
189
190 # interpreted as a flag
191 ulimit -f -42
192 if test $? -ne 0; then
193 echo pass
194 else
195 echo fail
196 fi
197
198 ## STDOUT:
199 unlimited
200 pass
201 ## END
202
203 #### ulimit negative arg
204
205 ulimit -f
206
207 # an arg
208 ulimit -f -- -42
209 if test $? -ne 0; then
210 echo pass
211 else
212 echo fail
213 fi
214
215 ## STDOUT:
216 unlimited
217 pass
218 ## END
219
220 ## BUG mksh STDOUT:
221 unlimited
222 fail
223 ## END
224
225
226 #### ulimit -a doesn't take arg
227 case $SH in bash) exit ;; esac
228
229 ulimit -a 42
230 if test $? -ne 0; then
231 echo 'failure that was expected'
232 fi
233
234 ## STDOUT:
235 failure that was expected
236 ## END
237 ## BUG bash STDOUT:
238 ## END
239
240
241 #### ulimit doesn't accept multiple flags - reduce confusion between shells
242
243 # - bash, zsh, busybox ash accept multiple "commands", which requires custom
244 # flag parsing, like
245
246 # ulimit -f 999 -n
247 # ulimit -f 999 -n 888
248 #
249 # - dash and mksh accept a single ARG
250 #
251 # we want to make it clear we're like the latter
252
253 # can't print all and -f
254 ulimit -f -a >/dev/null
255 echo status=$?
256
257 ulimit -f -n >/dev/null
258 echo status=$?
259
260 ulimit -f -n 999 >/dev/null
261 echo status=$?
262
263 ## STDOUT:
264 status=2
265 status=2
266 status=2
267 ## END
268
269 ## BUG dash/bash/mksh STDOUT:
270 status=0
271 status=0
272 status=0
273 ## END
274
275 # zsh is better - it checks that -a and -f are exclusive
276
277 ## BUG zsh STDOUT:
278 status=1
279 status=0
280 status=0
281 ## END
282
283
284 #### YSH readability: ulimit --all the same as ulimit -a
285
286 case $SH in bash|dash|mksh|zsh) exit ;; esac
287
288 ulimit -a > short.txt
289 ulimit --all > long.txt
290
291 wc -l short.txt long.txt
292
293 diff -u short.txt long.txt
294 echo status=$?
295
296 ## STDOUT:
297 8 short.txt
298 8 long.txt
299 16 total
300 status=0
301 ## END
302
303 ## N-I bash/dash/mksh/zsh STDOUT:
304 ## END
305
306 #### ulimit accepts 'unlimited'
307
308 for arg in zz unlimited; do
309 echo " arg $arg"
310 ulimit -f
311 echo status=$?
312 ulimit -f $arg
313 if test $? -ne 0; then
314 echo 'FAILED'
315 fi
316 echo
317 done
318 ## STDOUT:
319 arg zz
320 unlimited
321 status=0
322 FAILED
323
324 arg unlimited
325 unlimited
326 status=0
327
328 ## END
329
330
331 #### ulimit of 2**32, 2**31 (int overflow)
332
333 echo -n 'one '; ulimit -f
334
335
336 ulimit -f $(( 1 << 32 ))
337
338 echo -n 'two '; ulimit -f
339
340
341 # mksh fails because it overflows signed int, turning into negative number
342 ulimit -f $(( 1 << 31 ))
343
344 echo -n 'three '; ulimit -f
345
346 ## STDOUT:
347 one unlimited
348 two 4294967296
349 three 2147483648
350 ## END
351 ## BUG mksh STDOUT:
352 one unlimited
353 two 1
354 three 1
355 ## END
356
357
358 #### ulimit that is 64 bits
359
360 # no 64-bit integers
361 case $SH in mksh) exit ;; esac
362
363 echo -n 'before '; ulimit -f
364
365 # 1 << 63 overflows signed int
366
367 # 512 is 1 << 9, so make it 62-9 = 53 bits
368
369 lim=$(( 1 << 53 ))
370 #echo $lim
371
372 # bash says this is out of range
373 ulimit -f $lim
374
375 echo -n 'after '; ulimit -f
376
377 ## STDOUT:
378 before unlimited
379 after 9007199254740992
380 ## END
381
382 ## BUG mksh STDOUT:
383 ## END
384
385
386 #### arg that would overflow 64 bits is detected
387
388 # no 64-bit integers
389 case $SH in mksh) exit ;; esac
390
391 echo -n 'before '; ulimit -f
392
393 # 1 << 63 overflows signed int
394
395 lim=$(( (1 << 62) + 1 ))
396 #echo lim=$lim
397
398 # bash detects that this is out of range
399 # so does osh-cpp, but not osh-cpython
400
401 ulimit -f $lim
402 echo -n 'after '; ulimit -f
403
404 ## STDOUT:
405 before unlimited
406 after unlimited
407 ## END
408
409 ## BUG dash/zsh STDOUT:
410 before unlimited
411 after 1
412 ## END
413
414 ## BUG mksh STDOUT:
415 ## END
416
417
418 #### ulimit -f 1 prevents files larger 512 bytes
419 trap - XFSZ # don't handle this
420
421 rm -f err.txt
422 touch err.txt
423
424 bytes() {
425 local n=$1
426 local st=0
427 for i in $(seq $n); do
428 echo -n x
429 st=$?
430 if test $st -ne 0; then
431 echo "ERROR: echo failed with status $st" >> err.txt
432 fi
433 done
434 }
435
436 ulimit -f 1
437
438 bytes 512 > ok.txt
439 echo 512 status=$?
440
441 bytes 513 > too-big.txt
442 echo 513 status=$?
443 echo
444
445 wc --bytes ok.txt too-big.txt
446 echo
447
448 cat err.txt
449
450 ## status: -25
451 ## STDOUT:
452 512 status=0
453 ## END
454
455 ## OK disabledosh status: 0
456 ## OK disabledosh STDOUT:
457 512 status=0
458 513 status=0
459
460 512 ok.txt
461 512 too-big.txt
462 1024 total
463
464 ERROR: echo failed with status 1
465 ## END
466
467 ## BUG bash status: 0
468 ## BUG bash STDOUT:
469 512 status=0
470 513 status=0
471
472 512 ok.txt
473 513 too-big.txt
474 1025 total
475
476 ## END
477
478 #### write big file with ulimit
479
480 # I think this will test write() errors, rather than the final flush() error
481 # (which is currently skipped by C++
482
483 { echo 'ulimit -f 1'
484 # More than 8 KiB may cause a flush()
485 python2 -c 'print("echo " + "X"*9000 + " >out.txt")'
486 echo 'echo inner=$?'
487 } > big.sh
488
489 $SH big.sh
490 echo outer=$?
491
492 ## STDOUT:
493 outer=153
494 ## END
495
496 # not sure why this is different
497 ## OK osh STDOUT:
498 inner=1
499 outer=0
500 ## END
501
502
503 #### ulimit -S for soft limit (default), -H for hard limit
504 case $SH in dash|zsh) exit ;; esac
505
506 # Note: ulimit -n -S 1111 is OK in osh/dash/mksh, but not bash/zsh
507 # Mus be ulimit -S -n 1111
508
509 show_state() {
510 local msg=$1
511 echo "$msg"
512 echo -n ' '; ulimit -S -t
513 echo -n ' '; ulimit -H -t
514 echo
515 }
516
517 show_state 'init'
518
519 ulimit -S -t 123456
520 show_state '-S'
521
522 ulimit -H -t 123457
523 show_state '-H'
524
525 ulimit -t 123455
526 show_state 'no flag'
527
528 echo 'GET'
529
530 ulimit -S -t 123454
531 echo -n ' '; ulimit -t
532 echo -n ' '; ulimit -S -t
533 echo -n ' '; ulimit -H -t
534
535 ## STDOUT:
536 init
537 unlimited
538 unlimited
539
540 -S
541 123456
542 unlimited
543
544 -H
545 123456
546 123457
547
548 no flag
549 123455
550 123455
551
552 GET
553 123454
554 123454
555 123455
556 ## END
557
558 ## BUG dash/zsh STDOUT:
559 ## END
560
561 #### Changing resource limit is denied
562
563 # Not sure why these don't work
564 case $SH in dash|mksh) exit ;; esac
565
566
567 flag=-t
568
569 ulimit -S -H $flag 100
570 echo both=$?
571
572 ulimit -S $flag 90
573 echo soft=$?
574
575 ulimit -S $flag 95
576 echo soft=$?
577
578 ulimit -S $flag 105
579 if test $? -ne 0; then
580 echo soft OK
581 else
582 echo soft fail
583 fi
584
585 ulimit -H $flag 200
586 if test $? -ne 0; then
587 echo hard OK
588 else
589 echo hard fail
590 fi
591
592 ## STDOUT:
593 both=0
594 soft=0
595 soft=0
596 soft OK
597 hard OK
598 ## END
599
600 ## BUG dash/mksh STDOUT:
601 ## END
602
603 #### ulimit -n limits file descriptors
604
605 # OSH bug
606 # https://oilshell.zulipchat.com/#narrow/channel/502349-osh/topic/alpine.20build.20failures.20-.20make.20-.20ulimit.20-n.2064/with/519691301
607
608 $SH -c 'ulimit -n 64; echo hi >out'
609 echo status=$?
610
611 $SH -c 'ulimit -n 0; echo hi >out'
612 echo status=$?
613
614 ## STDOUT:
615 status=0
616 status=1
617 ## END
618
619 ## OK dash STDOUT:
620 status=0
621 status=2
622 ## END