Codebase list entr / e1ad73c
New upstream snapshot. Debian Janitor 1 year, 6 months ago
11 changed file(s) with 151 addition(s) and 103 deletion(s). Raw diff Collapse all Expand all
00 PREFIX ?= /usr/local
11 MANPREFIX ?= ${PREFIX}/man
2 RELEASE = 5.1
2 RELEASE = 5.3
33 CPPFLAGS += -DRELEASE=\"${RELEASE}\"
44
55 all: versioncheck entr
0 = Next Release: 5.3
1
2 - Symlink changes detected on Linux by setting 'ENTR_INOTIFY_SYMLINK'
3 - Use /dev/null rather then closed pipe for stdin in -r mode
4 - Utilize {O,FD}_CLOEXEC flag for unintentional leaks of descriptors to
5 executed utilities
6
07 = Release History
8
9 == 5.2: May 05, 2022
10
11 - Update copy of strlcpy(3) for Linux
12 - Detect file deletion from directories on Linux
13 - Print the signal that terminated a child when using '-s'
14 - Return 128+signal that terminated a child when using '-z'
15 - Ensure terminal settings are reset when '-z' is set
116
217 == 5.1: December 28, 2021
318
1313
1414 To see available build options run `./configure -h`
1515
16 Docker and Windows Subsystem for Linux
17 --------------------------------------
16 Docker and WSL
17 --------------
1818
19 Incomplete inotify support on WSL and Docker for Mac can cause `entr`
20 to respond inconsistently. Since version 4.4, `entr` includes a workaround:
21 Set the environment variable `ENTR_INOTIFY_WORKAROUND`.
19 Incomplete inotify support on Windows Subsystem for Linux and Docker for Mac can
20 cause `entr` to respond inconsistently. Setting the environment variable
21 `ENTR_INOTIFY_WORKAROUND` will enable `entr` to operate in these environments.
2222
23 `entr` will confirm the workaround is enabled:
23 Linux Features
24 --------------
2425
25 ```
26 entr: broken inotify workaround enabled
27 ```
26 Symlinks can be monitored for changes by setting the environment variable
27 `ENTR_INOTIFY_SYMLINK`.
2828
2929 Man Page Examples
3030 -----------------
0 entr (5.2+git20220623.1.0640c6d-1) UNRELEASED; urgency=low
1
2 * New upstream snapshot.
3
4 -- Debian Janitor <janitor@jelmer.uk> Sat, 15 Oct 2022 17:09:09 -0000
5
06 entr (5.1-1) unstable; urgency=medium
17
28 [ Yuri D'Elia ]
1212 .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1313 .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1414 .\"
15 .Dd August 13, 2021
15 .Dd May 5, 2022
1616 .Dt ENTR 1
1717 .Os
1818 .Sh NAME
145145 .Fl z
146146 flag is set and the
147147 .Ar utility
148 is successfully executed, the status of the child process is
149 returned.
150 Otherwise
148 is successfully executed, the status of the child process is returned.
149 If the child process was terminated by a signal, the exit status is the signal
150 number plus 128.
151 .Pp
151152 .Nm
152153 normally returns one of the following values:
153154 .Pp
7171 WatchFile **files;
7272 WatchFile *leading_edge;
7373 int child_pid;
74 int child_exitstatus;
74 int child_status;
7575 int terminating;
7676
7777 int aggressive_opt;
9292 static void terminate_utility();
9393 static void handle_exit(int sig);
9494 static void proc_exit(int sig);
95 static void print_child_status(int status);
9596 static int process_input(FILE *, WatchFile *[], int);
9697 static int set_options(char *[]);
9798 static int list_dir(char *);
195196 if ((kq = kqueue()) == -1)
196197 err(1, "cannot create kqueue");
197198
199 if (fcntl(kq, F_SETFD, FD_CLOEXEC) == -1)
200 warn("failed to set FD_CLOEXEC to kqueue descriptor");
201
198202 /* expect file list from a pipe */
199203 if (isatty(fileno(stdin)))
200204 usage();
250254
251255 if (child_pid > 0) {
252256 xkillpg(child_pid, SIGTERM);
253 if (xwaitpid(child_pid, &status, 0) > 0)
254 child_exitstatus = WEXITSTATUS(status);
257 xwaitpid(child_pid, &status, 0);
255258 child_pid = 0;
256259 }
257260
264267 handle_exit(int sig) {
265268 if ((!noninteractive_opt) && (termios_set))
266269 xtcsetattr(STDIN_FILENO, TCSADRAIN, &canonical_tty);
270
267271 terminate_utility();
272
268273 if ((sig == SIGINT || sig == SIGHUP))
269274 exit(0);
270275 else
275280 proc_exit(int sig) {
276281 int status;
277282
278 if (wait(&status) > 0)
279 child_exitstatus = WEXITSTATUS(status);
283 if ((!noninteractive_opt) && (termios_set))
284 xtcsetattr(STDIN_FILENO, TCSADRAIN, &canonical_tty);
285
286 if (wait(&status) != -1)
287 child_status = status;
288
280289 if ((oneshot_opt == 1) && (terminating == 0)) {
281 if ((shell_opt == 1) && (restart_opt == 0)) {
282 fprintf(stdout, "%s returned exit code %d\n",
283 basename(getenv("SHELL")), child_exitstatus);
284 }
285 exit(child_exitstatus);
286 }
287 }
288
290 if ((shell_opt == 1) && (restart_opt == 0))
291 print_child_status(child_status);
292
293 if WIFSIGNALED(child_status)
294 exit(128 + WTERMSIG(child_status));
295 else
296 exit(WEXITSTATUS(child_status));
297 }
298 }
299
300 void
301 print_child_status(int status) {
302 if WIFSIGNALED(status)
303 fprintf(stdout, "%s terminated by signal %d\n",
304 basename(getenv("SHELL")), WTERMSIG(status));
305 else
306 fprintf(stdout, "%s returned exit code %d\n",
307 basename(getenv("SHELL")), WEXITSTATUS(status));
308 }
289309
290310 /*
291311 * Read lines from a file stream (normally STDIN). Returns the number of
419439 char **new_argv;
420440 char *p, *arg_buf;
421441 int argc;
422 int stdin_pipe[2] = {0, 0};
423
424 if (restart_opt == 1) {
442
443 if (restart_opt == 1)
425444 terminate_utility();
426
427 if (pipe(stdin_pipe) != 0)
428 err(1, "Failed to create stdin pipe");
429 close(stdin_pipe[1]);
430 }
431445
432446 if (shell_opt == 1) {
433447 /* run argv[1] with a shell using the leading edge as $0 */
477491 /* Set process group so subprocess can be signaled */
478492 if (restart_opt == 1) {
479493 setpgid(0, getpid());
480 dup2(stdin_pipe[0], STDIN_FILENO);
494 close(STDIN_FILENO);
495 open(_PATH_DEVNULL, O_RDONLY);
481496 }
482497 /* wait up to 1 seconds for each file to become available */
483498 for (i=0; i < 10; i++) {
491506 }
492507 child_pid = pid;
493508
494 if (restart_opt == 0) {
495 if (xwaitpid(pid, &status, 0) > 0)
496 child_exitstatus = WEXITSTATUS(status);
509 if (restart_opt == 0 && oneshot_opt == 0) {
510 if (wait(&status) != -1)
511 child_status = status;
512
497513 if (shell_opt == 1)
498 fprintf(stdout, "%s returned exit code %d\n",
499 basename(getenv("SHELL")), child_exitstatus);
500
501 if (oneshot_opt == 1)
502 exit(child_exitstatus);
514 print_child_status(child_status);
503515 }
504516
505517 xfree(arg_buf);
518530 /* wait up to 1 second for file to become available */
519531 for (i=0; i < 10; i++) {
520532 #ifdef O_EVTONLY
521 file->fd = xopen(file->fn, O_RDONLY|O_EVTONLY);
533 file->fd = xopen(file->fn, O_RDONLY|O_CLOEXEC|O_EVTONLY);
522534 #else
523 file->fd = xopen(file->fn, O_RDONLY);
535 file->fd = xopen(file->fn, O_RDONLY|O_CLOEXEC);
524536 #endif
525537 if (file->fd == -1) nanosleep(&delay, NULL);
526538 else break;
805805
806806 argv_offset = set_options(argv);
807807
808 ok(argv_offset == 2);
808809 ok(clear_opt == 2);
809810 return 0;
810811 }
55
66 #if defined(_LINUX_PORT) && defined(__GLIBC__)
77 #include <sys/types.h>
8 size_t strlcpy(char *to, const char *from, int l);
8 size_t strlcpy(char *dst, const char *src, size_t dsize);
99 #endif
1010
1111 #if defined(_LINUX_PORT)
8080
8181 #define EVENT_SIZE (sizeof (struct inotify_event))
8282 #define EVENT_BUF_LEN (32 * (EVENT_SIZE + 16))
83 #define IN_ALL IN_CLOSE_WRITE|IN_DELETE_SELF|IN_MOVE_SELF|IN_MOVED_TO|IN_MOVED_FROM|IN_ATTRIB|IN_CREATE
83 #define IN_ALL IN_CLOSE_WRITE|IN_DELETE_SELF|IN_MOVE_SELF|IN_MOVE|IN_ATTRIB|IN_CREATE|IN_DELETE
8484
8585 /*
8686 * inotify and kqueue ids both have the type `int`
9393 inotify_queue = inotify_init();
9494 if (getenv("ENTR_INOTIFY_WORKAROUND"))
9595 warnx("broken inotify workaround enabled");
96 else if (getenv("ENTR_INOTIFY_SYMLINK"))
97 warnx("monitoring symlinks");
9698 return inotify_queue;
9799 }
98100
145147 else if (kev->flags & EV_ADD) {
146148 if (getenv("ENTR_INOTIFY_WORKAROUND"))
147149 wd = inotify_add_watch(kq, file->fn, IN_ALL|IN_MODIFY);
150 else if (getenv("ENTR_INOTIFY_SYMLINK"))
151 wd = inotify_add_watch(kq, file->fn, IN_ALL|IN_DONT_FOLLOW);
148152 else
149153 wd = inotify_add_watch(kq, file->fn, IN_ALL);
150154 if (wd < 0)
190194 if (iev->mask & IN_DELETE_SELF) fflags |= NOTE_DELETE;
191195 if (iev->mask & IN_CLOSE_WRITE) fflags |= NOTE_WRITE;
192196 if (iev->mask & IN_CREATE) fflags |= NOTE_WRITE;
197 if (iev->mask & IN_DELETE) fflags |= NOTE_WRITE;
193198 if (iev->mask & IN_MOVE_SELF) fflags |= NOTE_RENAME;
194199 if (iev->mask & IN_MOVED_TO) fflags |= NOTE_RENAME;
195200 if (iev->mask & IN_MOVED_FROM) fflags |= NOTE_RENAME;
0 /* $OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp $ */
0 /* $OpenBSD: strlcpy.c,v 1.16 2019/01/25 00:19:25 millert Exp $ */
11
22 /*
3 * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
3 * Copyright (c) 1998, 2015 Todd C. Miller <millert@openbsd.org>
44 *
55 * Permission to use, copy, modify, and distribute this software for any
66 * purpose with or without fee is hereby granted, provided that the above
1919 #include <string.h>
2020
2121 /*
22 * Copy src to string dst of size siz. At most siz-1 characters
23 * will be copied. Always NUL terminates (unless siz == 0).
24 * Returns strlen(src); if retval >= siz, truncation occurred.
22 * Copy string src to buffer dst of size dsize. At most dsize-1
23 * chars will be copied. Always NUL terminates (unless dsize == 0).
24 * Returns strlen(src); if retval >= dsize, truncation occurred.
2525 */
2626 size_t
27 strlcpy(char *dst, const char *src, size_t siz)
27 strlcpy(char *dst, const char *src, size_t dsize)
2828 {
29 char *d = dst;
30 const char *s = src;
31 size_t n = siz;
29 const char *osrc = src;
30 size_t nleft = dsize;
3231
33 /* Copy as many bytes as will fit */
34 if (n != 0) {
35 while (--n != 0) {
36 if ((*d++ = *s++) == '\0')
32 /* Copy as many bytes as will fit. */
33 if (nleft != 0) {
34 while (--nleft != 0) {
35 if ((*dst++ = *src++) == '\0')
3736 break;
3837 }
3938 }
4039
41 /* Not enough room in dst, add NUL and traverse rest of src */
42 if (n == 0) {
43 if (siz != 0)
44 *d = '\0'; /* NUL-terminate dst */
45 while (*s++)
40 /* Not enough room in dst, add NUL and traverse rest of src. */
41 if (nleft == 0) {
42 if (dsize != 0)
43 *dst = '\0'; /* NUL-terminate dst */
44 while (*src++)
4645 ;
4746 }
4847
49 return(s - src - 1); /* count does not include NUL */
48 return(src - osrc - 1); /* count does not include NUL */
5049 }
1515
1616 # test runner
1717
18 trap 'printf "$0: exit code $? on line $LINENO\nFAIL: $this\n"; exit 1' ERR \
19 2> /dev/null || exec bash $0 "$@"
20 typeset -i tests=0
2118 function try { let tests+=1; this="$1"; }
2219
2320 function assert {
9491
9592 try "exec a command using one-shot option"
9693 setup
97 ls $tmp/file* | ./entr -zp cat $tmp/file2 >$tmp/exec.out 2>$tmp/exec.err &
94 ls $tmp/file2 | ./entr -zp cat $tmp/file2 >$tmp/exec.out 2>$tmp/exec.err &
9895 bgpid=$! ; zz
9996 echo 456 >> $tmp/file2 ; zz
100 wait $bgpid || assert "$?" "0"
97 wait $bgpid; assert "$?" "0"
10198 assert "$(cat $tmp/exec.err)" ""
10299 assert "$(head -n1 $tmp/exec.out)" "$(printf '456\n')"
103100
101 try "exec a command using one-shot option and return signal number"
102 setup
103 ls $tmp/file2 | ./entr -z sh -c 'kill -9 $$' >$tmp/exec.out 2>$tmp/exec.err
104 assert "$?" "137"
105 assert "$(cat $tmp/exec.err)" ""
106 assert "$(cat $tmp/exec.out)" ""
107
108 try "exec a command using one-shot and shell options and return signal"
109 setup
110 ls $tmp/file2 | ./entr -z -s 'kill -9 $$' >$tmp/exec.out 2>$tmp/exec.err
111 assert "$?" "137"
112 assert "$(tail -c23 $tmp/exec.out)" "$(printf "terminated by signal 9\n")"
113
104114 try "fail to exec a command using one-shot option"
105115 setup
106 ls $tmp/file* | ./entr -z /usr/bin/false_X >$tmp/exec.out 2>$tmp/exec.err &
107 bgpid=$! ; zz
108 wait $bgpid || assert "$?" "1"
116 ls $tmp/file* | ./entr -z /usr/bin/false_X 2>$tmp/exec.err
117 assert "$?" "1"
109118
110119 try "exec a command using one-shot option exit code from child"
111120 setup
112121 ls $tmp/file* | ./entr -z sh -c 'exit 4' &
113122 bgpid=$! ; zz
114 wait $bgpid || assert "$?" "4"
123 wait $bgpid; assert "$?" "4"
115124
116125 try "restart a server when a file is modified using one-shot option"
117126 setup
124133 echo "123" | nc -U $tmp/nc.s
125134 } ; zz
126135 echo 456 >> $tmp/file2 ; zz
127 wait $bgpid || assert "$?" "130"
136 wait $bgpid; assert "$?" "0"
128137 assert "$(cat $tmp/exec.out)" "123"
129138 fi
130139
133142 ls $tmp/file* | ./entr -n tty >$tmp/exec.out &
134143 bgpid=$! ; zz
135144 kill -INT $bgpid
136 wait $bgpid || assert "$?" "130"
145 wait $bgpid; assert "$?" "0"
137146 assert "$(cat $tmp/exec.out)" "not a tty"
138147
139148 try "exec a command as a background task and ensure stdin is closed"
141150 ls $tmp/file* | ./entr -r sh -c 'test -t 0; echo $?; kill $$' >$tmp/exec.out &
142151 bgpid=$! ; zz
143152 kill -INT $bgpid
144 wait $bgpid || assert "$?" "130"
153 wait $bgpid; assert "$?" "0"
145154 assert "$(cat $tmp/exec.out)" "1"
146155
147156 try "exec a command as a background task, and verify that read from stdin doesn't complain"
149158 ls $tmp/file* | ./entr -r sh -c 'read X' 2>$tmp/exec.err &
150159 bgpid=$! ; zz
151160 kill -INT $bgpid
152 wait $bgpid || assert "$?" "130"
161 wait $bgpid; assert "$?" "0"
153162 assert "$(cat $tmp/exec.err)" ""
154163
155164 try "exec single shell utility and exit when a file is added to an implicit watch path"
158167 || true &
159168 bgpid=$! ; zz
160169 touch $tmp/newfile
161 wait $bgpid || assert "$?" "130"
170 wait $bgpid; assert "$?" "0"
162171 assert "$(cat $tmp/exec.out)" "ping"
163172 assert "$(cat $tmp/exec.err)" "entr: directory altered"
164173
168177 || true &
169178 bgpid=$! ; zz
170179 mkdir $tmp/newdir
171 wait $bgpid || assert "$?" "130"
180 wait $bgpid; assert "$?" "0"
172181 assert "$(cat $tmp/exec.out)" "ping"
173182 assert "$(cat $tmp/exec.err)" "entr: directory altered"
174183 rmdir $tmp/newdir
179188 || true &
180189 bgpid=$! ; zz
181190 mkdir $tmp/.newdir
182 wait $bgpid || assert "$?" "130"
191 wait $bgpid; assert "$?" "0"
183192 assert "$(cat $tmp/exec.out)" "ping"
184193 assert "$(cat $tmp/exec.err)" "entr: directory altered"
185194 rmdir $tmp/.newdir
190199 || true &
191200 bgpid=$! ; zz
192201 touch $tmp/newfile
193 wait $bgpid || assert "$?" "130"
202 wait $bgpid; assert "$?" "0"
194203 assert "$(cat $tmp/exec.out)" "ping"
195204 assert "$(cat $tmp/exec.err)" "entr: directory altered"
196205
200209 bgpid=$! ; zz
201210 echo "123" > $tmp/file1
202211 kill -INT $bgpid
203 wait $bgpid || assert "$?" "130"
212 wait $bgpid; assert "$?" "0"
204213 assert "$(cat $tmp/exec.out)" ""
205214 assert "$(cat $tmp/exec.err)" ""
206215
212221 -c ":r!date" \
213222 -c ":wq" $tmp/file1 ; zz
214223 kill -INT $bgpid
215 wait $bgpid || assert "$?" "130"
224 wait $bgpid; assert "$?" "0"
216225 assert "$(cat $tmp/exec.out)" "changed"
217226 assert "$(cat $tmp/exec.err)" ""
218227
223232 bgpid=$! ; zz
224233 : > $tmp/file1 ; zz
225234 kill -INT $bgpid
226 wait $bgpid || assert "$?" "130"
235 wait $bgpid; assert "$?" "0"
227236 if [ $(uname | egrep 'Darwin|FreeBSD|DragonFly') ]; then
228237 skip "NOTE_TRUNCATE not supported"
229238 else
251260 git checkout *.h -q
252261 cd - > /dev/null ; zz
253262 kill -INT $bgpid
254 wait $bgpid || assert "$?" "130"
263 wait $bgpid; assert "$?" "0"
255264 assert "$(cat $tmp/exec.out)" "changed"
256265 fi
257266
263272 -c ":r!date" \
264273 -c ":wq" $tmp/file1 ; zz
265274 kill -INT $bgpid
266 wait $bgpid || assert "$?" "130"
275 wait $bgpid; assert "$?" "0"
267276 assert "$(cat $tmp/exec.out)" "changed"
268277
269278 try "exec shell utility when a file is written by Vim with 'backup'"
275284 -c ":r!date" \
276285 -c ":wq" $tmp/file1 ; zz
277286 kill -INT $bgpid
278 wait $bgpid || assert "$?" "130"
287 wait $bgpid; assert "$?" "0"
279288 assert "$(cat $tmp/exec.out)" "changed"
280289
281290 try "exec shell utility when a file is written by Vim with 'nowritebackup'"
287296 -c ":r!date" \
288297 -c ":wq" $tmp/file1 ; zz
289298 kill -INT $bgpid
290 wait $bgpid || assert "$?" "130"
299 wait $bgpid; assert "$?" "0"
291300 assert "$(cat $tmp/exec.out)" "changed"
292301
293302 try "restart a server when a file is modified"
298307 assert "$(cat $tmp/exec.out)" "started."
299308 echo 456 >> $tmp/file2 ; zz
300309 kill -INT $bgpid
301 wait $bgpid || assert "$?" "130"
310 wait $bgpid; assert "$?" "0"
302311 assert "$(cat $tmp/exec.out)" "$(printf 'started.\nstarted.')"
303312
304313 try "ensure that all shell subprocesses are terminated in restart mode"
335344 assert "$(cat $tmp/exec.out)" "started."
336345 touch $tmp/newfile
337346 kill -INT $bgpid
338 wait $bgpid || assert "$?" "130"
347 wait $bgpid; assert "$?" "0"
339348 assert "$(cat $tmp/exec.out)" "$(printf 'started.')"
340349
341350 try "exec single shell utility when two files change simultaneously"
345354 bgpid=$! ; zz
346355 echo 456 >> $tmp/file1 ; zz
347356 kill -INT $bgpid
348 wait $bgpid || assert "$?" "130"
357 wait $bgpid; assert "$?" "0"
349358 assert "$(cat $tmp/exec.out)" "ping"
350359
351360 try "exec single shell utility on startup and when a file is changed"
354363 bgpid=$! ; zz
355364 echo 456 >> $tmp/file1 ; zz
356365 kill -INT $bgpid
357 wait $bgpid || assert "$?" "130"
366 wait $bgpid; assert "$?" "0"
358367 assert "$(cat $tmp/exec.out)" "pingping"
359368
360369 try "exec a command if a file is made executable"
363372 bgpid=$! ; zz
364373 chmod +x $tmp/file2 ; zz
365374 kill -INT $bgpid
366 wait $bgpid || assert "$?" "130"
375 wait $bgpid; assert "$?" "0"
367376 assert "$(cat $tmp/exec.out)" "$tmp/file2"
368377
369378 try "ensure watches operate on a running executable"
374383 bgpid=$! ; zz
375384 cp -f /bin/sleep $tmp/ ; zz
376385 kill -INT $bgpid
377 wait $bgpid || assert "$?" "130"
386 wait $bgpid; assert "$?" "0"
378387 rm -f $tmp/sleep
379388 assert "$(cat $tmp/exec.out)" "$(printf 'vroom\nvroom\n')"
380389
384393 bgpid=$! ; zz
385394 echo 456 > $tmp/file1 ; zz
386395 kill -INT $bgpid
387 wait $bgpid || assert "$?" "130"
396 wait $bgpid; assert "$?" "0"
388397 assert "$(cat $tmp/exec.out)" "456"
389398
390399 try "exec single shell utility using utility substitution"
393402 bgpid=$! ; zz
394403 echo 456 >> $tmp/file2; zz
395404 kill -INT $bgpid
396 wait $bgpid || assert "$?" "130"
405 wait $bgpid; assert "$?" "0"
397406 assert "$(cat $tmp/exec.out)" "$tmp/file2: ASCII text"
398407
399408 try "watch and exec a program that is overwritten"
406415 echo vroom
407416 EOF
408417 zz ; kill -INT $bgpid
409 wait $bgpid || assert "$?" "130"
418 wait $bgpid; assert "$?" "0"
410419 assert "$(cat $tmp/exec.out)" "vroom"
411420
412421 try "exec an interactive utility when a file changes"
415424 bgpid=$! ; zz
416425 echo 456 >> $tmp/file2 ; zz
417426 kill -INT $bgpid
418 wait $bgpid || assert "$?" "130"
427 wait $bgpid; assert "$?" "0"
419428 if ! test -t 0 ; then
420429 skip "A TTY is not available"
421430 else
428437 bgpid=$! ; zz
429438 echo 456 >> $tmp/file2 ; zz
430439 kill -INT $bgpid
431 wait $bgpid || assert "$?" "130"
440 wait $bgpid; assert "$?" "0"
432441 assert "$(cat $tmp/exec.err)" ""
433442 assert "$(head -n1 $tmp/exec.out)" "$(printf ${tmp}'/file2: ASCII text')"
434443
449458 echo "123" > $tmp/file1
450459 sleep 1
451460 kill -INT $bgpid
452 wait $bgpid || assert "$?" "130"
461 wait $bgpid; assert "$?" "0"
453462 assert "$(cat $tmp/exec.out)" "$(printf 'vroom\nvroom\n')"
454463
455464 try "ensure that all subprocesses are terminated in restart mode when a file is removed"