5a7117bb1621b1dcf3b8ab32efc36506c5897ebf
[mmh] / test / mhmail / test-mhmail
1 #!/bin/sh
2 ######################################################
3 #
4 # Test mhmail
5 #
6 ######################################################
7
8 set -e
9
10 if test -z "${MH_OBJ_DIR}"; then
11     srcdir=`dirname $0`/../..
12     MH_OBJ_DIR=`cd $srcdir && pwd`; export MH_OBJ_DIR
13 fi
14
15 . "${srcdir}/test/post/test-post-common.sh"
16
17 # Customize test_post () for use with mhmail.
18 # $1 is expected output file, provided by caller
19 # $2 is mhmail switches, except for -body
20 # $3 of -b signifies use -body switch, | signifies provide body on stdin
21 # $4 contains message body.  When using stdin, can contain printf(1) format
22 #    specifiers.
23 test_mhmail ()
24 {
25     "${MH_OBJ_DIR}/test/fakesmtp" "$actual" $localport &
26     pid="$!"
27
28     # The server doesn't always come up fast enough, so sleep and
29     # retry a few times if it fails...
30     status=1
31     for i in 0 1 2 3 4 5 6 7 8 9; do
32         if [ $3 = '|' ]; then
33           if printf "$4" | mhmail recipient@example.com $2 \
34              -server 127.0.0.1 -port $localport; then
35               status=0
36               break
37           fi
38         else
39           if mhmail recipient@example.com $2 -body "$4" \
40              -server 127.0.0.1 -port $localport; then
41               status=0
42               break
43           fi
44         fi
45         sleep 1
46     done
47     [ $status -eq 0 ] || exit 1
48
49     wait ${pid}
50
51     #
52     # It's hard to calculate the exact Date: header post is going to
53     # use, so we'll just use sed to remove the actual date so we can easily
54     # compare it against our "correct" output.  And same for
55     # Message-ID.
56     #
57
58     sed -e 's/^Date:.*/Date:/' \
59         -e 's/^Resent-Date:.*/Resent-Date:/' \
60         -e 's/^Message-ID:.*/Message-ID:/' \
61         -e 's/^Content-ID:.*/Content-ID:/' "$actual" > "$actual".nodate
62     rm -f "$actual"
63
64     check "$actual".nodate "$1"
65 }
66
67 expected=$MH_TEST_DIR/test-mhmail$$.expected
68 expected_err=$MH_TEST_DIR/test-mhmail$$.expected_err
69 actual=$MH_TEST_DIR/test-mhmail$$.actual
70 actual_err=$MH_TEST_DIR/test-mhmail$$.actual_err
71
72
73 # check -help
74 # Verified behavior consistent with compiled sendmail.
75 cat >$expected <<EOF
76 Usage: mhmail [-t(o)] addrs ... [switches]
77   switches are:
78   -at(tach) file [-at(tach) file] ...
79   -b(ody) text
80   -c(c) addrs ...
81   -f(rom) addr
82   -hea(derfield) name:value [-hea(derfield) name:value] ...
83   -su(bject) text
84   -r(esent)
85   -pr(ofile)
86   -se(nd)
87   -nose(nd)
88   -v(ersion)
89   -hel(p)
90   and all post(8)/send(1) switches
91   mhmail with no arguments is equivalent to inc
92 EOF
93
94 mhmail -help >$actual 2>&1
95 check $expected $actual
96
97
98 # check -version
99 # Verified same behavior as compiled mhmail.
100 case `mhmail -v` in
101   mhmail\ --*) ;;
102   *           ) echo "$0: mhmail -v generated unexpected output" 1>&2
103                 failed=`expr ${failed:-0} + 1`;;
104 esac
105
106 # check for missing argument to switches that require them
107 for switch in attach body cc from headerfield subject to; do
108   run_test "mhmail recipient -$switch" \
109            "mhmail: missing argument to -$switch"
110 done
111 for switch in attach body cc from headerfield subject to; do
112   run_test "mhmail recipient -$switch -nosend" \
113            "mhmail: missing argument to -$switch"
114 done
115 for switch in attach body cc from headerfield subject to; do
116   run_test "mhmail recipient -$switch -server 127.0.0.1" \
117            "mhmail: missing argument to -$switch"
118 done
119
120
121 # check with no switches
122 # That will just run inc, which we don't want to do anything,
123 # so tell inc to just display its version.
124 # Verified same behavior as compiled mhmail.
125 printf "inc: -version\n" >> $MH
126 case `mhmail` in
127   inc\ --*) ;;
128   *           ) echo "$0: mhmail generated unexpected output" 1>&2
129                 failed=`expr ${failed:-0} + 1`;;
130 esac
131
132
133 # check -nosend
134 # Not supported by compiled mhmail.
135 mhmail -nosend recipient@example.com -from sender@localhost \
136   -server 127.0.0.1 -port $localport -body '' >"$actual" 2>"$actual_err"
137
138 tmpfil=`head -1 $actual | sed -e 's/://'`
139
140 cat > "$expected" <<EOF
141 To: recipient@example.com
142 From: sender@localhost
143
144
145 EOF
146
147 cat > "$expected_err" <<EOF
148 EOF
149
150 check "$expected" "$actual"
151 check "$expected_err" "$actual_err"
152 [ ${failed:-0} -eq 0 ] || exit ${failed:-0}
153
154
155 # check -send
156 # Not supported by compiled mhmail.
157 cat > "$expected" <<EOF
158 EHLO nosuchhost.example.com
159 MAIL FROM:<sender@localhost>
160 RCPT TO:<recipient@example.com>
161 DATA
162 To: recipient@example.com
163 From: sender@localhost
164 Date:
165
166 message
167 .
168 QUIT
169 EOF
170
171 test_mhmail "$expected" "-from sender@localhost -nosend -send" '|' message
172 [ ${failed:-0} -eq 0 ] || exit ${failed:-0}
173
174
175 # check -from
176 # Verified same behavior as compiled mhmail.
177 cat > "$expected" <<EOF
178 EHLO nosuchhost.example.com
179 MAIL FROM:<sender@localhost>
180 RCPT TO:<recipient@example.com>
181 DATA
182 To: recipient@example.com
183 From: sender@localhost
184 Date:
185
186 message
187 .
188 QUIT
189 EOF
190
191 test_mhmail "$expected" "-from sender@localhost" '|' message
192 [ ${failed:-0} -eq 0 ] || exit ${failed:-0}
193
194
195 # check -from and -body
196 # Verified same behavior as compiled mhmail.
197 cat > "$expected" <<EOF
198 EHLO nosuchhost.example.com
199 MAIL FROM:<sender@localhost>
200 RCPT TO:<recipient@example.com>
201 DATA
202 To: recipient@example.com
203 From: sender@localhost
204 Date:
205
206 body
207 .
208 QUIT
209 EOF
210
211 test_mhmail "$expected" "-from sender@localhost" -b body
212 [ ${failed:-0} -eq 0 ] || exit ${failed:-0}
213
214
215 # check -from and -cc
216 # Verified same behavior as compiled mhmail.
217 cat > "$expected" <<EOF
218 EHLO nosuchhost.example.com
219 MAIL FROM:<sender@localhost>
220 RCPT TO:<recipient@example.com>
221 RCPT TO:<recipient2@example.com>
222 DATA
223 To: recipient@example.com
224 Cc: recipient2@example.com
225 From: sender@localhost
226 Date:
227
228 message
229 .
230 QUIT
231 EOF
232
233 test_mhmail "$expected" \
234     "-from sender@localhost -cc recipient2@example.com" '|' message
235 [ ${failed:-0} -eq 0 ] || exit ${failed:-0}
236
237
238 # check -from and multiple -cc addresses
239 # Verified same behavior as compiled mhmail.
240 cat > "$expected" <<EOF
241 EHLO nosuchhost.example.com
242 MAIL FROM:<sender@localhost>
243 RCPT TO:<recipient@example.com>
244 RCPT TO:<recipient2@example.com>
245 RCPT TO:<recipient3@example.com>
246 RCPT TO:<recipient4@example.com>
247 DATA
248 To: recipient@example.com
249 Cc: recipient2@example.com, recipient3@example.com,
250     recipient4@example.com
251 From: sender@localhost
252 Date:
253
254 message
255 .
256 QUIT
257 EOF
258
259 test_mhmail "$expected" \
260     '-from sender@localhost -cc recipient2@example.com recipient3@example.com '\
261 'recipient4@example.com' '|' message
262 [ ${failed:-0} -eq 0 ] || exit ${failed:-0}
263
264
265 # check -from and -subject
266 # Verified same behavior as compiled mhmail.
267 cat > "$expected" <<EOF
268 EHLO nosuchhost.example.com
269 MAIL FROM:<sender@localhost>
270 RCPT TO:<recipient@example.com>
271 DATA
272 To: recipient@example.com
273 Subject: Test
274 From: sender@localhost
275 Date:
276
277 message
278 .
279 QUIT
280 EOF
281
282 test_mhmail "$expected" '-from sender@localhost -subject Test' '|' message
283 [ ${failed:-0} -eq 0 ] || exit ${failed:-0}
284
285
286 # check -from and -profile
287 # Show that -profile causes mhmail to 1) read the profile and
288 # 2) use send(1) by added a send switch to the profile and
289 # verifying that it gets used.
290 # Not supported by compiled mhmail.
291 printf "send: -msgid\n" >> $MH
292
293 cat > "$expected" <<EOF
294 EHLO nosuchhost.example.com
295 MAIL FROM:<sender@localhost>
296 RCPT TO:<recipient@example.com>
297 DATA
298 To: recipient@example.com
299 From: sender@localhost
300 Date:
301 Message-ID:
302
303 message
304 .
305 QUIT
306 EOF
307
308 test_mhmail "$expected" '-from sender@localhost -profile' '|' message
309 [ ${failed:-0} -eq 0 ] || exit ${failed:-0}
310
311
312 # check repeated -from and -subject switches
313 # Verified same behavior as compiled mhmail.
314 cat > "$expected" <<EOF
315 EHLO nosuchhost.example.com
316 MAIL FROM:<sender2@localhost>
317 RCPT TO:<recipient@example.com>
318 DATA
319 To: recipient@example.com
320 Subject: Subject2
321 From: sender2@localhost
322 Date:
323
324 message
325 .
326 QUIT
327 EOF
328
329 test_mhmail "$expected" '-from sender@localhost -from sender2@localhost '\
330 '-subject Subject1 -subject Subject2' -b message
331 [ ${failed:-0} -eq 0 ] || exit ${failed:-0}
332
333 # check repeated -body switches
334 # Verified same behavior as compiled mhmail.
335 cat > "$expected" <<EOF
336 EHLO nosuchhost.example.com
337 MAIL FROM:<sender@localhost>
338 RCPT TO:<recipient@example.com>
339 DATA
340 To: recipient@example.com
341 From: sender@localhost
342 Date:
343
344 body2
345 .
346 QUIT
347 EOF
348
349 test_mhmail "$expected" "-from sender@localhost -body body1" -b body2
350 [ ${failed:-0} -eq 0 ] || exit ${failed:-0}
351
352
353 # check multiple -cc switches
354 # Verified same behavior as compiled mhmail.
355 cat > "$expected" <<EOF
356 EHLO nosuchhost.example.com
357 MAIL FROM:<sender@localhost>
358 RCPT TO:<recipient@example.com>
359 RCPT TO:<cc1@example.com>
360 RCPT TO:<cc2@example.com>
361 DATA
362 To: recipient@example.com
363 Cc: cc1@example.com, cc2@example.com
364 From: sender@localhost
365 Date:
366
367 message
368 .
369 QUIT
370 EOF
371
372 test_mhmail "$expected" \
373   '-from sender@localhost -cc cc1@example.com -cc cc2@example.com' -b message
374 [ ${failed:-0} -eq 0 ] || exit ${failed:-0}
375
376
377 # check separated -cc arguments
378 # Verified same behavior as compiled mhmail.
379 cat > "$expected" <<EOF
380 EHLO nosuchhost.example.com
381 MAIL FROM:<sender@localhost>
382 RCPT TO:<recipient@example.com>
383 RCPT TO:<cc1@example.com>
384 RCPT TO:<cc2@example.com>
385 DATA
386 To: recipient@example.com
387 Cc: cc1@example.com, cc2@example.com
388 Subject: Test
389 From: sender@localhost
390 Date:
391
392 message
393 .
394 QUIT
395 EOF
396
397 test_mhmail "$expected" \
398   '-from sender@localhost -cc cc1@example.com -subject Test cc2@example.com' \
399   -b message
400 [ ${failed:-0} -eq 0 ] || exit ${failed:-0}
401
402
403 # check -cc switch followed by -to switch
404 # Verified same behavior as compiled mhmail.
405 cat > "$expected" <<EOF
406 EHLO nosuchhost.example.com
407 MAIL FROM:<sender@localhost>
408 RCPT TO:<recipient@example.com>
409 RCPT TO:<recipient2@example.com>
410 RCPT TO:<cc1@example.com>
411 DATA
412 To: recipient@example.com, recipient2@example.com
413 Cc: cc1@example.com
414 Subject: Test
415 From: sender@localhost
416 Date:
417
418 message
419 .
420 QUIT
421 EOF
422
423 test_mhmail "$expected" \
424   "-from sender@localhost -cc cc1@example.com -subject Test \
425    -to recipient2@example.com" \
426   -b message
427 [ ${failed:-0} -eq 0 ] || exit ${failed:-0}
428
429
430 # check with no newline on stdin
431 # Shows different behavior than compiled mhmail, which was silent in this case.
432 cat > "$expected" <<EOF
433 EOF
434
435 cat > "$expected_err" <<EOF
436 mhmail: empty message not sent, use -body '' to force.
437 EOF
438
439 set +e
440 printf '' | mhmail recipient@example.com -server 127.0.0.1 -port $localport \
441   >"$actual" 2>"$actual_err"
442 set -e
443
444 check "$expected" "$actual"
445 check "$expected_err" "$actual_err"
446 [ ${failed:-0} -eq 0 ] || exit ${failed:-0}
447
448
449 # check with one newline on stdin
450 # Verified same behavior as compiled mhmail.
451 cat > "$expected" <<EOF
452 EHLO nosuchhost.example.com
453 MAIL FROM:<sender@localhost>
454 RCPT TO:<recipient@example.com>
455 DATA
456 To: recipient@example.com
457 From: sender@localhost
458 Date:
459
460
461 .
462 QUIT
463 EOF
464
465 test_mhmail "$expected" '-from sender@localhost' '|' '\n'
466 [ ${failed:-0} -eq 0 ] || exit ${failed:-0}
467
468
469 # check with multiple newlines on stdin
470 # Verified same behavior as compiled mhmail.
471 cat > "$expected" <<EOF
472 EHLO nosuchhost.example.com
473 MAIL FROM:<sender@localhost>
474 RCPT TO:<recipient@example.com>
475 DATA
476 To: recipient@example.com
477 From: sender@localhost
478 Date:
479
480
481
482
483 .
484 QUIT
485 EOF
486
487 test_mhmail "$expected" '-from sender@localhost' '|' '\n\n\n'
488 [ ${failed:-0} -eq 0 ] || exit ${failed:-0}
489
490
491 # check with text and no trailing newline on stdin
492 # Verified same behavior as compiled mhmail.
493 cat > "$expected" <<EOF
494 EHLO nosuchhost.example.com
495 MAIL FROM:<sender@localhost>
496 RCPT TO:<recipient@example.com>
497 DATA
498 To: recipient@example.com
499 From: sender@localhost
500 Date:
501
502 no newline in input
503 .
504 QUIT
505 EOF
506
507 test_mhmail "$expected" '-from sender@localhost' '|' 'no newline in input'
508 [ ${failed:-0} -eq 0 ] || exit ${failed:-0}
509
510
511 # check with text and multiple trailing blank lines on stdin
512 # Verified same behavior as compiled mhmail.
513 cat > "$expected" <<EOF
514 EHLO nosuchhost.example.com
515 MAIL FROM:<sender@localhost>
516 RCPT TO:<recipient@example.com>
517 DATA
518 To: recipient@example.com
519 From: sender@localhost
520 Date:
521
522 here's some text
523
524
525 .
526 QUIT
527 EOF
528
529 test_mhmail "$expected" '-from sender@localhost' '|' "here's some text\n\n\n"
530 [ ${failed:-0} -eq 0 ] || exit ${failed:-0}
531
532
533 # check with no newline to -body
534 # Verified same behavior as compiled mhmail.
535 cat > "$expected" <<EOF
536 EHLO nosuchhost.example.com
537 MAIL FROM:<sender@localhost>
538 RCPT TO:<recipient@example.com>
539 DATA
540 To: recipient@example.com
541 From: sender@localhost
542 Date:
543
544
545 .
546 QUIT
547 EOF
548
549 test_mhmail "$expected" '-from sender@localhost' -b ''
550 [ ${failed:-0} -eq 0 ] || exit ${failed:-0}
551
552
553 # check with one newline to -body
554 # Shows different behavior than compiled mhmail, which suppressed the newline.
555 cat > "$expected" <<EOF
556 EHLO nosuchhost.example.com
557 MAIL FROM:<sender@localhost>
558 RCPT TO:<recipient@example.com>
559 DATA
560 To: recipient@example.com
561 From: sender@localhost
562 Date:
563
564
565
566 .
567 QUIT
568 EOF
569
570 test_mhmail "$expected" '-from sender@localhost' -b '
571 '
572 [ ${failed:-0} -eq 0 ] || exit ${failed:-0}
573
574
575 # check with multiple newlines to -body
576 # Shows different behavior than compiled mhmail, which suppressed one
577 #   of the newlines.
578 cat > "$expected" <<EOF
579 EHLO nosuchhost.example.com
580 MAIL FROM:<sender@localhost>
581 RCPT TO:<recipient@example.com>
582 DATA
583 To: recipient@example.com
584 From: sender@localhost
585 Date:
586
587
588
589
590
591 .
592 QUIT
593 EOF
594
595 test_mhmail "$expected" '-from sender@localhost' -b '
596
597
598 '
599 [ ${failed:-0} -eq 0 ] || exit ${failed:-0}
600
601
602 # check with text and no trailing newline to -body
603 # Verified same behavior as compiled mhmail.
604 cat > "$expected" <<EOF
605 EHLO nosuchhost.example.com
606 MAIL FROM:<sender@localhost>
607 RCPT TO:<recipient@example.com>
608 DATA
609 To: recipient@example.com
610 From: sender@localhost
611 Date:
612
613 no newline in input
614 .
615 QUIT
616 EOF
617
618 test_mhmail "$expected" '-from sender@localhost' -b 'no newline in input'
619 [ ${failed:-0} -eq 0 ] || exit ${failed:-0}
620
621
622 # check with text and multiple trailing blank lines to -body
623 # Shows different behavior than compiled mhmail, which suppressed one
624 #   of the newlines.
625 cat > "$expected" <<EOF
626 EHLO nosuchhost.example.com
627 MAIL FROM:<sender@localhost>
628 RCPT TO:<recipient@example.com>
629 DATA
630 To: recipient@example.com
631 From: sender@localhost
632 Date:
633
634 here's some text
635
636
637 .
638 QUIT
639 EOF
640
641 test_mhmail "$expected" '-from sender@localhost' -b "here's some text
642
643 "
644 [ ${failed:-0} -eq 0 ] || exit ${failed:-0}
645
646
647 # check -resent
648 # Verified same behavior as compiled mhmail.
649 cat > "$expected" <<EOF
650 EHLO nosuchhost.example.com
651 MAIL FROM:<orig_recipient@example.com>
652 RCPT TO:<recipient@example.com>
653 DATA
654 Resent-To: recipient@example.com
655 Resent-From: orig_recipient@example.com
656 To: recipient@example.com
657 From: sender@localhost
658 Date:
659 Resent-Date:
660
661 please resend this message, 1
662 .
663 QUIT
664 EOF
665
666 test_mhmail "$expected" '-from orig_recipient@example.com -resent' \
667   -b 'To: recipient@example.com
668 From: sender@localhost
669 Date: Sat Jun 16 18:35:15 -0500
670
671 please resend this message, 1'
672
673 [ ${failed:-0} -eq 0 ] || exit ${failed:-0}
674
675 # check -resent -profile, using stdin
676 # Not supported by compiled mhmail.
677 cat > "$expected" <<EOF
678 EHLO nosuchhost.example.com
679 MAIL FROM:<orig_recipient@example.com>
680 RCPT TO:<recipient@example.com>
681 DATA
682 To: recipient@example.com
683 From: sender@localhost
684 Date:
685 Resent-To: recipient@example.com
686 Resent-From: orig_recipient@example.com
687 Resent-Date:
688
689 please resend this message, 2
690 .
691 QUIT
692 EOF
693
694 test_mhmail "$expected" \
695   '-from orig_recipient@example.com -resent -profile -nomsgid' \
696   '|' 'To: recipient@example.com
697 From: sender@localhost
698 Date: Sat Jun 16 18:35:15 -0500
699
700 please resend this message, 2'
701
702 [ ${failed:-0} -eq 0 ] || exit ${failed:-0}
703
704
705 # check -resent -profile, using -b
706 # Not supported by compiled mhmail.
707 cat > "$expected" <<EOF
708 EHLO nosuchhost.example.com
709 MAIL FROM:<orig_recipient@example.com>
710 RCPT TO:<recipient@example.com>
711 DATA
712 To: recipient@example.com
713 From: sender@localhost
714 Date:
715 Resent-To: recipient@example.com
716 Resent-From: orig_recipient@example.com
717 Resent-Date:
718
719 please resend this message, 3
720 .
721 QUIT
722 EOF
723
724 test_mhmail "$expected" \
725   '-from orig_recipient@example.com -resent -profile -nomsgid' \
726   -b 'To: recipient@example.com
727 From: sender@localhost
728 Date: Sat Jun 16 18:35:15 -0500
729
730 please resend this message, 3'
731
732 [ ${failed:-0} -eq 0 ] || exit ${failed:-0}
733
734
735 # check -headerfield.
736 # Not supported by compiled mhmail.
737 cat > "$expected" <<EOF
738 EHLO nosuchhost.example.com
739 MAIL FROM:<sender@example.com>
740 RCPT TO:<recipient@example.com>
741 DATA
742 To: recipient@example.com
743 From: sender@example.com
744 User-Agent: nmh
745 Date:
746
747 with added header field
748 .
749 QUIT
750 EOF
751
752 test_mhmail "$expected" \
753   '-from sender@example.com -headerfield User-Agent:nmh' \
754   -b 'with added header field'
755
756 [ ${failed:-0} -eq 0 ] || exit ${failed:-0}
757
758
759 # check multiple -headerfields.
760 # Not supported by compiled mhmail.
761 cat > "$expected" <<EOF
762 EHLO nosuchhost.example.com
763 MAIL FROM:<sender@example.com>
764 RCPT TO:<recipient@example.com>
765 DATA
766 To: recipient@example.com
767 From: sender@example.com
768 MIME-Version: 1.0
769 Content-Type: text/plain;charset=utf-8
770 Content-Transfer-Encoding: 8bit
771 Date:
772
773 with added header fields
774 .
775 QUIT
776 EOF
777
778 test_mhmail "$expected" \
779   "-from sender@example.com -headerfield MIME-Version:1.0 \
780 -headerfield Content-Type:text/plain;charset=utf-8 \
781 -headerfield Content-Transfer-Encoding:8bit" \
782   -b 'with added header fields'
783
784 [ ${failed:-0} -eq 0 ] || exit ${failed:-0}
785
786
787 # check -attach
788 # Not supported by compiled mhmail.
789 cat > "$expected" <<EOF
790 EHLO nosuchhost.example.com
791 MAIL FROM:<sender@example.com>
792 RCPT TO:<recipient@example.com>
793 DATA
794 To: recipient@example.com
795 From: sender@example.com
796 MIME-Version: 1.0
797 Content-Type: multipart/mixed; boundary="----- =_aaaaaaaaaa0"
798 Content-ID:
799 Date:
800 Message-ID:
801
802 ------- =_aaaaaaaaaa0
803 Content-Type: text/plain; charset="us-ascii"
804
805 See how easy it is to add an attachment!
806
807 ------- =_aaaaaaaaaa0
808 Content-Type: text/plain; name="attachment.txt"; charset="us-ascii"
809 Content-Description: attachment.txt
810 Content-Disposition: attachment; filename="attachment.txt"
811
812 The future disappears into memory, With only a moment between,
813 Forever dwells in that moment, hope is what remains to be seen
814 Forever dwells in that moment, hope is what remains to be seen.
815
816 ------- =_aaaaaaaaaa0--
817 .
818 QUIT
819 EOF
820
821 test_mhmail "$expected" \
822   "-from sender@example.com -attach ${srcdir}/test/mhmail/attachment.txt" \
823   -b 'See how easy it is to add an attachment!'
824
825 [ ${failed:-0} -eq 0 ] || exit ${failed:-0}
826
827
828 exit ${failed:-0}