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