OILS / spec / builtin-process.test.sh View on Github | oils.pub

1016 lines, 522 significant
1## compare_shells: dash bash mksh zsh
2## oils_failures_allowed: 4
3## oils_cpp_failures_allowed: 5
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
8exec echo hi
9## stdout: hi
10
11#### exec builtin with redirects
12exec 1>&2
13echo '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:
22x=one
23y=two
24DONE
25## END
26
27#### exec builtin accepts --
28exec -- echo hi
29## STDOUT:
30hi
31## END
32## BUG dash status: 127
33## BUG dash stdout-json: ""
34
35#### exec -- 2>&1
36exec -- 3>&1
37echo stdout 1>&3
38## STDOUT:
39stdout
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
47f() { exit 3; }
48f
49exit 4
50## status: 3
51
52#### Exit builtin with invalid arg
53exit 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.
61exit 7 8 9
62echo 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
74err=time-$(basename $SH).txt
75{
76 time {
77 sleep 0.01
78 sleep 0.02
79 }
80} 2> $err
81
82grep --only-matching user $err
83echo result=$?
84
85# Regression: check fractional seconds
86gawk '
87BEGIN { ok = 0 }
88match( $0, /\.([0-9]+)/, m) {
89 if (m[1] > 0) { # check fractional seconds
90 ok = 1
91 }
92}
93END { if (ok) { print "non-zero" } }
94' $err
95
96## status: 0
97## STDOUT:
98user
99result=0
100non-zero
101## END
102
103# time doesn't accept a block?
104## BUG zsh STDOUT:
105result=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
114umask | grep '[0-9]\+' # check for digits
115## status: 0
116
117#### set umask in octal
118rm -f $TMP/umask-one $TMP/umask-two
119umask 0002
120echo one > $TMP/umask-one
121umask 0022
122echo two > $TMP/umask-two
123stat -c '%a' $TMP/umask-one $TMP/umask-two
124## status: 0
125## STDOUT:
126664
127644
128## END
129## stderr-json: ""
130
131#### set umask symbolically
132umask 0002 # begin in a known state for the test
133rm -f $TMP/umask-one $TMP/umask-two
134# open()s 'umask-one' with mask 0666, then subtracts 0002 -> 0664
135echo one > $TMP/umask-one
136umask g-w,o-w
137echo two > $TMP/umask-two
138stat -c '%a' $TMP/umask-one $TMP/umask-two
139## status: 0
140## STDOUT:
141664
142644
143## END
144## stderr-json: ""
145
146#### umask -p
147umask -p | grep 'umask [0-9][0-9][0-9][0-9]'
148## status: 0
149## N-I dash/mksh/zsh status: 1
150
151#### umask -S
152# current mask as symbolic
153umask -S | grep 'u=[rwx]*,g=[rwx]*,o=[rwx]*'
154## status: 0
155
156#### umask symbolic parsing
157
158umask 0000
159umask u-rw
160echo status0=$?
161umask | tail -c 4
162
163umask 0700
164umask u=r
165echo status1=$?
166umask | tail -c 4
167
168umask 0000
169umask u=r,g=w,o=x
170echo status2=$?
171umask | tail -c 4
172
173umask 0777
174umask u+r,g+w,o+x
175echo status3=$?
176umask | tail -c 4
177
178umask 0000
179umask u-r,g-w,o-x
180echo status4=$?
181umask | tail -c 4
182
183umask 0137
184umask u=,g+,o-
185echo status5=$?
186umask | tail -c 4
187
188## status: 0
189## STDOUT:
190status0=0
191600
192status1=0
193300
194status2=0
195356
196status3=0
197356
198status4=0
199421
200status5=0
201737
202## END
203
204#### umask symbolic parsing with spaces
205umask 0111
206# spaces are an error in bash
207# dash & mksh only interpret the first one
208umask u=, g+, o-
209echo status=$?
210umask | tail -c 4
211## status: 0
212## STDOUT:
213status=2
214111
215## END
216## OK bash/zsh STDOUT:
217status=1
218111
219## END
220## BUG dash/mksh STDOUT:
221status=0
222711
223## END
224
225#### umask bad symbolic input
226umask b=rwx
227## status: 1
228## OK dash status: 2
229
230#### umask octal number out of range
231umask 0022
232umask 1234567
233# osh currently treats 0o1234567 as 0o0567
234echo status=$?
235umask | tail -c 4
236## status: 0
237## STDOUT:
238status=1
239022
240## END
241## BUG mksh/zsh/dash STDOUT:
242status=0
243567
244## END
245
246#### umask allow overwriting and duplicates
247umask 0111
248umask u=rwx,u=rw,u=r,u=,g=rwx
249umask | tail -c 4
250## status: 0
251## STDOUT:
252701
253## END
254
255#### umask a is valid who
256umask 0732
257umask a=rwx
258umask | tail -c 4
259
260umask 0124
261umask a+r
262umask | tail -c 4
263
264umask 0124
265umask a-r
266umask | tail -c 4
267## status: 0
268## STDOUT:
269000
270120
271564
272## END
273
274#### umask X perm
275umask 0124
276umask a=X
277echo ret0 = $?
278umask | tail -c 4
279
280umask 0246
281umask a=X
282echo ret1 = $?
283umask | tail -c 4
284
285umask 0246
286umask a-X
287echo ret2 = $?
288umask | tail -c 4
289## status: 0
290## STDOUT:
291ret0 = 0
292666
293ret1 = 0
294777
295ret2 = 0
296246
297## END
298## BUG dash/mksh STDOUT:
299ret0 = 0
300666
301ret1 = 0
302666
303ret2 = 0
304357
305## END
306## N-I bash/zsh STDOUT:
307ret0 = 1
308124
309ret1 = 1
310246
311ret2 = 1
312246
313## END
314
315#### umask s perm
316umask 0124
317umask a-s
318echo ret0 = $?
319umask | tail -c 4
320
321umask 0124
322umask a+s
323echo ret1 = $?
324umask | tail -c 4
325
326umask 0124
327umask a=s
328echo ret2 = $?
329umask | tail -c 4
330## status: 0
331## STDOUT:
332ret0 = 0
333124
334ret1 = 0
335124
336ret2 = 0
337777
338## END
339## N-I bash/zsh STDOUT:
340ret0 = 1
341124
342ret1 = 1
343124
344ret2 = 1
345124
346## END
347
348#### umask t perm
349umask 0124
350umask a-t
351echo ret0 = $?
352umask | tail -c 4
353
354umask 0124
355umask a+t
356echo ret1 = $?
357umask | tail -c 4
358
359umask 0124
360umask a=t
361echo ret2 = $?
362umask | tail -c 4
363## status: 0
364## STDOUT:
365ret0 = 0
366124
367ret1 = 0
368124
369ret2 = 0
370777
371## END
372## N-I bash/zsh/mksh STDOUT:
373ret0 = 1
374124
375ret1 = 1
376124
377ret2 = 1
378124
379## END
380## N-I dash STDOUT:
381ret0 = 2
382124
383ret1 = 2
384124
385ret2 = 2
386124
387## END
388
389#### umask default who
390umask 0124
391umask =
392umask | tail -c 4
393
394umask 0124
395umask =rx
396echo ret = $?
397umask | tail -c 4
398
399umask 0124
400umask +
401umask | tail -c 4
402
403umask 0124
404# zsh ALSO treats this as just `umask`
405umask - >/dev/null
406umask | tail -c 4
407## status: 0
408## BUG zsh status: 1
409## STDOUT:
410777
411ret = 0
412222
413124
414124
415## END
416## BUG zsh STDOUT:
417777
418## END
419
420#### umask bare op
421umask 0124
422umask =+=
423umask | tail -c 4
424
425umask 0124
426umask +=
427umask | tail -c 4
428
429umask 0124
430umask =+rwx+rx
431umask | tail -c 4
432## status: 0
433## BUG zsh status: 1
434## STDOUT:
435777
436777
437000
438## END
439## N-I bash STDOUT:
440124
441124
442124
443## END
444## BUG zsh STDOUT:
445## END
446
447#### umask bare op -
448umask 0124
449umask -rwx
450umask | tail -c 4
451
452umask 0124
453umask -wx
454umask | tail -c 4
455
456umask 0124
457umask -=+
458umask | tail -c 4
459## status: 0
460## STDOUT:
461777
462337
463777
464## END
465## N-I dash/bash/mksh/zsh STDOUT:
466124
467124
468124
469## END
470
471#### umask permcopy
472umask 0124
473umask a=u
474umask | tail -c 4
475
476umask 0365
477umask a=g
478umask | tail -c 4
479
480umask 0124
481umask a=o
482umask | tail -c 4
483## status: 0
484## STDOUT:
485111
486666
487444
488## END
489## N-I bash/zsh STDOUT:
490124
491365
492124
493## END
494
495#### umask permcopy running value
496umask 0124
497umask a=,a=u
498umask | tail -c 4
499
500umask 0124
501umask a=
502umask a=u
503umask | tail -c 4
504## status: 0
505## STDOUT:
506111
507777
508## END
509## N-I bash/zsh STDOUT:
510124
511777
512## END
513
514#### umask sequential actions
515umask 0124
516umask u+r+w+x
517umask | tail -c 4
518
519umask 0124
520umask a+r+w+x,o-w
521umask | tail -c 4
522
523umask 0124
524umask a+x+wr-r
525umask | tail -c 4
526## status: 0
527## STDOUT:
528024
529002
530444
531## END
532## N-I bash/zsh STDOUT:
533124
534124
535124
536## END
537
538
539#### ulimit with no flags is like -f
540
541ulimit > no-flags.txt
542echo status=$?
543
544ulimit -f > f.txt
545echo status=$?
546
547diff -u no-flags.txt f.txt
548echo diff=$?
549
550# Print everything
551# ulimit -a
552
553## STDOUT:
554status=0
555status=0
556diff=0
557## END
558
559
560#### ulimit too many args
561
562ulimit 1 2
563if test $? -ne 0; then
564 echo pass
565else
566 echo fail
567fi
568
569#ulimit -f
570
571## STDOUT:
572pass
573## END
574
575## BUG bash/zsh STDOUT:
576fail
577## END
578
579
580#### ulimit negative flag
581
582ulimit -f
583
584# interpreted as a flag
585ulimit -f -42
586if test $? -ne 0; then
587 echo pass
588else
589 echo fail
590fi
591
592## STDOUT:
593unlimited
594pass
595## END
596
597#### ulimit negative arg
598
599ulimit -f
600
601# an arg
602ulimit -f -- -42
603if test $? -ne 0; then
604 echo pass
605else
606 echo fail
607fi
608
609## STDOUT:
610unlimited
611pass
612## END
613
614## BUG mksh STDOUT:
615unlimited
616fail
617## END
618
619
620#### ulimit -a doesn't take arg
621case $SH in bash) exit ;; esac
622
623ulimit -a 42
624if test $? -ne 0; then
625 echo 'failure that was expected'
626fi
627
628## STDOUT:
629failure that was expected
630## END
631## BUG bash STDOUT:
632## END
633
634
635#### ulimit doesn't accept multiple flags - reduce confusion between shells
636
637# - bash, zsh, busybox ash accept multiple "commands", which requires custom
638# flag parsing, like
639
640# ulimit -f 999 -n
641# ulimit -f 999 -n 888
642#
643# - dash and mksh accept a single ARG
644#
645# we want to make it clear we're like the latter
646
647# can't print all and -f
648ulimit -f -a >/dev/null
649echo status=$?
650
651ulimit -f -n >/dev/null
652echo status=$?
653
654ulimit -f -n 999 >/dev/null
655echo status=$?
656
657## STDOUT:
658status=2
659status=2
660status=2
661## END
662
663## BUG dash/bash/mksh STDOUT:
664status=0
665status=0
666status=0
667## END
668
669# zsh is better - it checks that -a and -f are exclusive
670
671## BUG zsh STDOUT:
672status=1
673status=0
674status=0
675## END
676
677
678#### YSH readability: ulimit --all the same as ulimit -a
679
680case $SH in bash|dash|mksh|zsh) exit ;; esac
681
682ulimit -a > short.txt
683ulimit --all > long.txt
684
685wc -l short.txt long.txt
686
687diff -u short.txt long.txt
688echo status=$?
689
690## STDOUT:
691 8 short.txt
692 8 long.txt
693 16 total
694status=0
695## END
696
697## N-I bash/dash/mksh/zsh STDOUT:
698## END
699
700#### ulimit accepts 'unlimited'
701
702for arg in zz unlimited; do
703 echo " arg $arg"
704 ulimit -f
705 echo status=$?
706 ulimit -f $arg
707 if test $? -ne 0; then
708 echo 'FAILED'
709 fi
710 echo
711done
712## STDOUT:
713 arg zz
714unlimited
715status=0
716FAILED
717
718 arg unlimited
719unlimited
720status=0
721
722## END
723
724
725#### ulimit of 2**32, 2**31 (int overflow)
726
727echo -n 'one '; ulimit -f
728
729
730ulimit -f $(( 1 << 32 ))
731
732echo -n 'two '; ulimit -f
733
734
735# mksh fails because it overflows signed int, turning into negative number
736ulimit -f $(( 1 << 31 ))
737
738echo -n 'three '; ulimit -f
739
740## STDOUT:
741one unlimited
742two 4294967296
743three 2147483648
744## END
745## BUG mksh STDOUT:
746one unlimited
747two 1
748three 1
749## END
750
751
752#### ulimit that is 64 bits
753
754# no 64-bit integers
755case $SH in mksh) exit ;; esac
756
757echo -n 'before '; ulimit -f
758
759# 1 << 63 overflows signed int
760
761# 512 is 1 << 9, so make it 62-9 = 53 bits
762
763lim=$(( 1 << 53 ))
764#echo $lim
765
766# bash says this is out of range
767ulimit -f $lim
768
769echo -n 'after '; ulimit -f
770
771## STDOUT:
772before unlimited
773after 9007199254740992
774## END
775
776## BUG mksh STDOUT:
777## END
778
779
780#### arg that would overflow 64 bits is detected
781
782# no 64-bit integers
783case $SH in mksh) exit ;; esac
784
785echo -n 'before '; ulimit -f
786
787# 1 << 63 overflows signed int
788
789lim=$(( (1 << 62) + 1 ))
790#echo lim=$lim
791
792# bash detects that this is out of range
793# so does osh-cpp, but not osh-cpython
794
795ulimit -f $lim
796echo -n 'after '; ulimit -f
797
798## STDOUT:
799before unlimited
800after unlimited
801## END
802
803## BUG dash/zsh STDOUT:
804before unlimited
805after 1
806## END
807
808## BUG mksh STDOUT:
809## END
810
811
812#### ulimit -f 1 prevents files larger 512 bytes
813trap - XFSZ # don't handle this
814
815rm -f err.txt
816touch err.txt
817
818bytes() {
819 local n=$1
820 local st=0
821 for i in $(seq $n); do
822 echo -n x
823 st=$?
824 if test $st -ne 0; then
825 echo "ERROR: echo failed with status $st" >> err.txt
826 fi
827 done
828}
829
830ulimit -f 1
831
832bytes 512 > ok.txt
833echo 512 status=$?
834
835bytes 513 > too-big.txt
836echo 513 status=$?
837echo
838
839wc --bytes ok.txt too-big.txt
840echo
841
842cat err.txt
843
844## status: -25
845## STDOUT:
846512 status=0
847## END
848
849## OK disabledosh status: 0
850## OK disabledosh STDOUT:
851512 status=0
852513 status=0
853
854 512 ok.txt
855 512 too-big.txt
8561024 total
857
858ERROR: echo failed with status 1
859## END
860
861## BUG bash status: 0
862## BUG bash STDOUT:
863512 status=0
864513 status=0
865
866 512 ok.txt
867 513 too-big.txt
8681025 total
869
870## END
871
872#### write big file with ulimit
873
874# I think this will test write() errors, rather than the final flush() error
875# (which is currently skipped by C++
876
877{ echo 'ulimit -f 1'
878 # More than 8 KiB may cause a flush()
879 python2 -c 'print("echo " + "X"*9000 + " >out.txt")'
880 echo 'echo inner=$?'
881} > big.sh
882
883$SH big.sh
884echo outer=$?
885
886## STDOUT:
887outer=153
888## END
889
890# not sure why this is different
891## OK osh STDOUT:
892inner=1
893outer=0
894## END
895
896
897#### ulimit -S for soft limit (default), -H for hard limit
898case $SH in dash|zsh) exit ;; esac
899
900# Note: ulimit -n -S 1111 is OK in osh/dash/mksh, but not bash/zsh
901# Mus be ulimit -S -n 1111
902
903show_state() {
904 local msg=$1
905 echo "$msg"
906 echo -n ' '; ulimit -S -t
907 echo -n ' '; ulimit -H -t
908 echo
909}
910
911show_state 'init'
912
913ulimit -S -t 123456
914show_state '-S'
915
916ulimit -H -t 123457
917show_state '-H'
918
919ulimit -t 123455
920show_state 'no flag'
921
922echo 'GET'
923
924ulimit -S -t 123454
925echo -n ' '; ulimit -t
926echo -n ' '; ulimit -S -t
927echo -n ' '; ulimit -H -t
928
929## STDOUT:
930init
931 unlimited
932 unlimited
933
934-S
935 123456
936 unlimited
937
938-H
939 123456
940 123457
941
942no flag
943 123455
944 123455
945
946GET
947 123454
948 123454
949 123455
950## END
951
952## BUG dash/zsh STDOUT:
953## END
954
955#### Changing resource limit is denied
956
957# Not sure why these don't work
958case $SH in dash|mksh) exit ;; esac
959
960
961flag=-t
962
963ulimit -S -H $flag 100
964echo both=$?
965
966ulimit -S $flag 90
967echo soft=$?
968
969ulimit -S $flag 95
970echo soft=$?
971
972ulimit -S $flag 105
973if test $? -ne 0; then
974 echo soft OK
975else
976 echo soft fail
977fi
978
979ulimit -H $flag 200
980if test $? -ne 0; then
981 echo hard OK
982else
983 echo hard fail
984fi
985
986## STDOUT:
987both=0
988soft=0
989soft=0
990soft OK
991hard OK
992## END
993
994## BUG dash/mksh STDOUT:
995## END
996
997#### ulimit -n limits file descriptors
998
999# OSH bug
1000# https://oilshell.zulipchat.com/#narrow/channel/502349-osh/topic/alpine.20build.20failures.20-.20make.20-.20ulimit.20-n.2064/with/519691301
1001
1002$SH -c 'ulimit -n 64; echo hi >out'
1003echo status=$?
1004
1005$SH -c 'ulimit -n 0; echo hi >out'
1006echo status=$?
1007
1008## STDOUT:
1009status=0
1010status=1
1011## END
1012
1013## OK dash STDOUT:
1014status=0
1015status=2
1016## END