New upstream snapshot.
Debian Janitor
1 year, 6 months ago
0 | 0 | PREFIX ?= /usr/local |
1 | 1 | MANPREFIX ?= ${PREFIX}/man |
2 | RELEASE = 5.1 | |
2 | RELEASE = 5.3 | |
3 | 3 | CPPFLAGS += -DRELEASE=\"${RELEASE}\" |
4 | 4 | |
5 | 5 | 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 | ||
0 | 7 | = 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 | |
1 | 16 | |
2 | 17 | == 5.1: December 28, 2021 |
3 | 18 |
13 | 13 | |
14 | 14 | To see available build options run `./configure -h` |
15 | 15 | |
16 | Docker and Windows Subsystem for Linux | |
17 | -------------------------------------- | |
16 | Docker and WSL | |
17 | -------------- | |
18 | 18 | |
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. | |
22 | 22 | |
23 | `entr` will confirm the workaround is enabled: | |
23 | Linux Features | |
24 | -------------- | |
24 | 25 | |
25 | ``` | |
26 | entr: broken inotify workaround enabled | |
27 | ``` | |
26 | Symlinks can be monitored for changes by setting the environment variable | |
27 | `ENTR_INOTIFY_SYMLINK`. | |
28 | 28 | |
29 | 29 | Man Page Examples |
30 | 30 | ----------------- |
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 | ||
0 | 6 | entr (5.1-1) unstable; urgency=medium |
1 | 7 | |
2 | 8 | [ Yuri D'Elia ] |
12 | 12 | .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
13 | 13 | .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
14 | 14 | .\" |
15 | .Dd August 13, 2021 | |
15 | .Dd May 5, 2022 | |
16 | 16 | .Dt ENTR 1 |
17 | 17 | .Os |
18 | 18 | .Sh NAME |
145 | 145 | .Fl z |
146 | 146 | flag is set and the |
147 | 147 | .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 | |
151 | 152 | .Nm |
152 | 153 | normally returns one of the following values: |
153 | 154 | .Pp |
71 | 71 | WatchFile **files; |
72 | 72 | WatchFile *leading_edge; |
73 | 73 | int child_pid; |
74 | int child_exitstatus; | |
74 | int child_status; | |
75 | 75 | int terminating; |
76 | 76 | |
77 | 77 | int aggressive_opt; |
92 | 92 | static void terminate_utility(); |
93 | 93 | static void handle_exit(int sig); |
94 | 94 | static void proc_exit(int sig); |
95 | static void print_child_status(int status); | |
95 | 96 | static int process_input(FILE *, WatchFile *[], int); |
96 | 97 | static int set_options(char *[]); |
97 | 98 | static int list_dir(char *); |
195 | 196 | if ((kq = kqueue()) == -1) |
196 | 197 | err(1, "cannot create kqueue"); |
197 | 198 | |
199 | if (fcntl(kq, F_SETFD, FD_CLOEXEC) == -1) | |
200 | warn("failed to set FD_CLOEXEC to kqueue descriptor"); | |
201 | ||
198 | 202 | /* expect file list from a pipe */ |
199 | 203 | if (isatty(fileno(stdin))) |
200 | 204 | usage(); |
250 | 254 | |
251 | 255 | if (child_pid > 0) { |
252 | 256 | xkillpg(child_pid, SIGTERM); |
253 | if (xwaitpid(child_pid, &status, 0) > 0) | |
254 | child_exitstatus = WEXITSTATUS(status); | |
257 | xwaitpid(child_pid, &status, 0); | |
255 | 258 | child_pid = 0; |
256 | 259 | } |
257 | 260 | |
264 | 267 | handle_exit(int sig) { |
265 | 268 | if ((!noninteractive_opt) && (termios_set)) |
266 | 269 | xtcsetattr(STDIN_FILENO, TCSADRAIN, &canonical_tty); |
270 | ||
267 | 271 | terminate_utility(); |
272 | ||
268 | 273 | if ((sig == SIGINT || sig == SIGHUP)) |
269 | 274 | exit(0); |
270 | 275 | else |
275 | 280 | proc_exit(int sig) { |
276 | 281 | int status; |
277 | 282 | |
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 | ||
280 | 289 | 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 | } | |
289 | 309 | |
290 | 310 | /* |
291 | 311 | * Read lines from a file stream (normally STDIN). Returns the number of |
419 | 439 | char **new_argv; |
420 | 440 | char *p, *arg_buf; |
421 | 441 | int argc; |
422 | int stdin_pipe[2] = {0, 0}; | |
423 | ||
424 | if (restart_opt == 1) { | |
442 | ||
443 | if (restart_opt == 1) | |
425 | 444 | terminate_utility(); |
426 | ||
427 | if (pipe(stdin_pipe) != 0) | |
428 | err(1, "Failed to create stdin pipe"); | |
429 | close(stdin_pipe[1]); | |
430 | } | |
431 | 445 | |
432 | 446 | if (shell_opt == 1) { |
433 | 447 | /* run argv[1] with a shell using the leading edge as $0 */ |
477 | 491 | /* Set process group so subprocess can be signaled */ |
478 | 492 | if (restart_opt == 1) { |
479 | 493 | setpgid(0, getpid()); |
480 | dup2(stdin_pipe[0], STDIN_FILENO); | |
494 | close(STDIN_FILENO); | |
495 | open(_PATH_DEVNULL, O_RDONLY); | |
481 | 496 | } |
482 | 497 | /* wait up to 1 seconds for each file to become available */ |
483 | 498 | for (i=0; i < 10; i++) { |
491 | 506 | } |
492 | 507 | child_pid = pid; |
493 | 508 | |
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 | ||
497 | 513 | 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); | |
503 | 515 | } |
504 | 516 | |
505 | 517 | xfree(arg_buf); |
518 | 530 | /* wait up to 1 second for file to become available */ |
519 | 531 | for (i=0; i < 10; i++) { |
520 | 532 | #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); | |
522 | 534 | #else |
523 | file->fd = xopen(file->fn, O_RDONLY); | |
535 | file->fd = xopen(file->fn, O_RDONLY|O_CLOEXEC); | |
524 | 536 | #endif |
525 | 537 | if (file->fd == -1) nanosleep(&delay, NULL); |
526 | 538 | else break; |
805 | 805 | |
806 | 806 | argv_offset = set_options(argv); |
807 | 807 | |
808 | ok(argv_offset == 2); | |
808 | 809 | ok(clear_opt == 2); |
809 | 810 | return 0; |
810 | 811 | } |
5 | 5 | |
6 | 6 | #if defined(_LINUX_PORT) && defined(__GLIBC__) |
7 | 7 | #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); | |
9 | 9 | #endif |
10 | 10 | |
11 | 11 | #if defined(_LINUX_PORT) |
80 | 80 | |
81 | 81 | #define EVENT_SIZE (sizeof (struct inotify_event)) |
82 | 82 | #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 | |
84 | 84 | |
85 | 85 | /* |
86 | 86 | * inotify and kqueue ids both have the type `int` |
93 | 93 | inotify_queue = inotify_init(); |
94 | 94 | if (getenv("ENTR_INOTIFY_WORKAROUND")) |
95 | 95 | warnx("broken inotify workaround enabled"); |
96 | else if (getenv("ENTR_INOTIFY_SYMLINK")) | |
97 | warnx("monitoring symlinks"); | |
96 | 98 | return inotify_queue; |
97 | 99 | } |
98 | 100 | |
145 | 147 | else if (kev->flags & EV_ADD) { |
146 | 148 | if (getenv("ENTR_INOTIFY_WORKAROUND")) |
147 | 149 | 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); | |
148 | 152 | else |
149 | 153 | wd = inotify_add_watch(kq, file->fn, IN_ALL); |
150 | 154 | if (wd < 0) |
190 | 194 | if (iev->mask & IN_DELETE_SELF) fflags |= NOTE_DELETE; |
191 | 195 | if (iev->mask & IN_CLOSE_WRITE) fflags |= NOTE_WRITE; |
192 | 196 | if (iev->mask & IN_CREATE) fflags |= NOTE_WRITE; |
197 | if (iev->mask & IN_DELETE) fflags |= NOTE_WRITE; | |
193 | 198 | if (iev->mask & IN_MOVE_SELF) fflags |= NOTE_RENAME; |
194 | 199 | if (iev->mask & IN_MOVED_TO) fflags |= NOTE_RENAME; |
195 | 200 | 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 $ */ | |
1 | 1 | |
2 | 2 | /* |
3 | * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com> | |
3 | * Copyright (c) 1998, 2015 Todd C. Miller <millert@openbsd.org> | |
4 | 4 | * |
5 | 5 | * Permission to use, copy, modify, and distribute this software for any |
6 | 6 | * purpose with or without fee is hereby granted, provided that the above |
19 | 19 | #include <string.h> |
20 | 20 | |
21 | 21 | /* |
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. | |
25 | 25 | */ |
26 | 26 | size_t |
27 | strlcpy(char *dst, const char *src, size_t siz) | |
27 | strlcpy(char *dst, const char *src, size_t dsize) | |
28 | 28 | { |
29 | char *d = dst; | |
30 | const char *s = src; | |
31 | size_t n = siz; | |
29 | const char *osrc = src; | |
30 | size_t nleft = dsize; | |
32 | 31 | |
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') | |
37 | 36 | break; |
38 | 37 | } |
39 | 38 | } |
40 | 39 | |
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++) | |
46 | 45 | ; |
47 | 46 | } |
48 | 47 | |
49 | return(s - src - 1); /* count does not include NUL */ | |
48 | return(src - osrc - 1); /* count does not include NUL */ | |
50 | 49 | } |
15 | 15 | |
16 | 16 | # test runner |
17 | 17 | |
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 | |
21 | 18 | function try { let tests+=1; this="$1"; } |
22 | 19 | |
23 | 20 | function assert { |
94 | 91 | |
95 | 92 | try "exec a command using one-shot option" |
96 | 93 | 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 & | |
98 | 95 | bgpid=$! ; zz |
99 | 96 | echo 456 >> $tmp/file2 ; zz |
100 | wait $bgpid || assert "$?" "0" | |
97 | wait $bgpid; assert "$?" "0" | |
101 | 98 | assert "$(cat $tmp/exec.err)" "" |
102 | 99 | assert "$(head -n1 $tmp/exec.out)" "$(printf '456\n')" |
103 | 100 | |
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 | ||
104 | 114 | try "fail to exec a command using one-shot option" |
105 | 115 | 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" | |
109 | 118 | |
110 | 119 | try "exec a command using one-shot option exit code from child" |
111 | 120 | setup |
112 | 121 | ls $tmp/file* | ./entr -z sh -c 'exit 4' & |
113 | 122 | bgpid=$! ; zz |
114 | wait $bgpid || assert "$?" "4" | |
123 | wait $bgpid; assert "$?" "4" | |
115 | 124 | |
116 | 125 | try "restart a server when a file is modified using one-shot option" |
117 | 126 | setup |
124 | 133 | echo "123" | nc -U $tmp/nc.s |
125 | 134 | } ; zz |
126 | 135 | echo 456 >> $tmp/file2 ; zz |
127 | wait $bgpid || assert "$?" "130" | |
136 | wait $bgpid; assert "$?" "0" | |
128 | 137 | assert "$(cat $tmp/exec.out)" "123" |
129 | 138 | fi |
130 | 139 | |
133 | 142 | ls $tmp/file* | ./entr -n tty >$tmp/exec.out & |
134 | 143 | bgpid=$! ; zz |
135 | 144 | kill -INT $bgpid |
136 | wait $bgpid || assert "$?" "130" | |
145 | wait $bgpid; assert "$?" "0" | |
137 | 146 | assert "$(cat $tmp/exec.out)" "not a tty" |
138 | 147 | |
139 | 148 | try "exec a command as a background task and ensure stdin is closed" |
141 | 150 | ls $tmp/file* | ./entr -r sh -c 'test -t 0; echo $?; kill $$' >$tmp/exec.out & |
142 | 151 | bgpid=$! ; zz |
143 | 152 | kill -INT $bgpid |
144 | wait $bgpid || assert "$?" "130" | |
153 | wait $bgpid; assert "$?" "0" | |
145 | 154 | assert "$(cat $tmp/exec.out)" "1" |
146 | 155 | |
147 | 156 | try "exec a command as a background task, and verify that read from stdin doesn't complain" |
149 | 158 | ls $tmp/file* | ./entr -r sh -c 'read X' 2>$tmp/exec.err & |
150 | 159 | bgpid=$! ; zz |
151 | 160 | kill -INT $bgpid |
152 | wait $bgpid || assert "$?" "130" | |
161 | wait $bgpid; assert "$?" "0" | |
153 | 162 | assert "$(cat $tmp/exec.err)" "" |
154 | 163 | |
155 | 164 | try "exec single shell utility and exit when a file is added to an implicit watch path" |
158 | 167 | || true & |
159 | 168 | bgpid=$! ; zz |
160 | 169 | touch $tmp/newfile |
161 | wait $bgpid || assert "$?" "130" | |
170 | wait $bgpid; assert "$?" "0" | |
162 | 171 | assert "$(cat $tmp/exec.out)" "ping" |
163 | 172 | assert "$(cat $tmp/exec.err)" "entr: directory altered" |
164 | 173 | |
168 | 177 | || true & |
169 | 178 | bgpid=$! ; zz |
170 | 179 | mkdir $tmp/newdir |
171 | wait $bgpid || assert "$?" "130" | |
180 | wait $bgpid; assert "$?" "0" | |
172 | 181 | assert "$(cat $tmp/exec.out)" "ping" |
173 | 182 | assert "$(cat $tmp/exec.err)" "entr: directory altered" |
174 | 183 | rmdir $tmp/newdir |
179 | 188 | || true & |
180 | 189 | bgpid=$! ; zz |
181 | 190 | mkdir $tmp/.newdir |
182 | wait $bgpid || assert "$?" "130" | |
191 | wait $bgpid; assert "$?" "0" | |
183 | 192 | assert "$(cat $tmp/exec.out)" "ping" |
184 | 193 | assert "$(cat $tmp/exec.err)" "entr: directory altered" |
185 | 194 | rmdir $tmp/.newdir |
190 | 199 | || true & |
191 | 200 | bgpid=$! ; zz |
192 | 201 | touch $tmp/newfile |
193 | wait $bgpid || assert "$?" "130" | |
202 | wait $bgpid; assert "$?" "0" | |
194 | 203 | assert "$(cat $tmp/exec.out)" "ping" |
195 | 204 | assert "$(cat $tmp/exec.err)" "entr: directory altered" |
196 | 205 | |
200 | 209 | bgpid=$! ; zz |
201 | 210 | echo "123" > $tmp/file1 |
202 | 211 | kill -INT $bgpid |
203 | wait $bgpid || assert "$?" "130" | |
212 | wait $bgpid; assert "$?" "0" | |
204 | 213 | assert "$(cat $tmp/exec.out)" "" |
205 | 214 | assert "$(cat $tmp/exec.err)" "" |
206 | 215 | |
212 | 221 | -c ":r!date" \ |
213 | 222 | -c ":wq" $tmp/file1 ; zz |
214 | 223 | kill -INT $bgpid |
215 | wait $bgpid || assert "$?" "130" | |
224 | wait $bgpid; assert "$?" "0" | |
216 | 225 | assert "$(cat $tmp/exec.out)" "changed" |
217 | 226 | assert "$(cat $tmp/exec.err)" "" |
218 | 227 | |
223 | 232 | bgpid=$! ; zz |
224 | 233 | : > $tmp/file1 ; zz |
225 | 234 | kill -INT $bgpid |
226 | wait $bgpid || assert "$?" "130" | |
235 | wait $bgpid; assert "$?" "0" | |
227 | 236 | if [ $(uname | egrep 'Darwin|FreeBSD|DragonFly') ]; then |
228 | 237 | skip "NOTE_TRUNCATE not supported" |
229 | 238 | else |
251 | 260 | git checkout *.h -q |
252 | 261 | cd - > /dev/null ; zz |
253 | 262 | kill -INT $bgpid |
254 | wait $bgpid || assert "$?" "130" | |
263 | wait $bgpid; assert "$?" "0" | |
255 | 264 | assert "$(cat $tmp/exec.out)" "changed" |
256 | 265 | fi |
257 | 266 | |
263 | 272 | -c ":r!date" \ |
264 | 273 | -c ":wq" $tmp/file1 ; zz |
265 | 274 | kill -INT $bgpid |
266 | wait $bgpid || assert "$?" "130" | |
275 | wait $bgpid; assert "$?" "0" | |
267 | 276 | assert "$(cat $tmp/exec.out)" "changed" |
268 | 277 | |
269 | 278 | try "exec shell utility when a file is written by Vim with 'backup'" |
275 | 284 | -c ":r!date" \ |
276 | 285 | -c ":wq" $tmp/file1 ; zz |
277 | 286 | kill -INT $bgpid |
278 | wait $bgpid || assert "$?" "130" | |
287 | wait $bgpid; assert "$?" "0" | |
279 | 288 | assert "$(cat $tmp/exec.out)" "changed" |
280 | 289 | |
281 | 290 | try "exec shell utility when a file is written by Vim with 'nowritebackup'" |
287 | 296 | -c ":r!date" \ |
288 | 297 | -c ":wq" $tmp/file1 ; zz |
289 | 298 | kill -INT $bgpid |
290 | wait $bgpid || assert "$?" "130" | |
299 | wait $bgpid; assert "$?" "0" | |
291 | 300 | assert "$(cat $tmp/exec.out)" "changed" |
292 | 301 | |
293 | 302 | try "restart a server when a file is modified" |
298 | 307 | assert "$(cat $tmp/exec.out)" "started." |
299 | 308 | echo 456 >> $tmp/file2 ; zz |
300 | 309 | kill -INT $bgpid |
301 | wait $bgpid || assert "$?" "130" | |
310 | wait $bgpid; assert "$?" "0" | |
302 | 311 | assert "$(cat $tmp/exec.out)" "$(printf 'started.\nstarted.')" |
303 | 312 | |
304 | 313 | try "ensure that all shell subprocesses are terminated in restart mode" |
335 | 344 | assert "$(cat $tmp/exec.out)" "started." |
336 | 345 | touch $tmp/newfile |
337 | 346 | kill -INT $bgpid |
338 | wait $bgpid || assert "$?" "130" | |
347 | wait $bgpid; assert "$?" "0" | |
339 | 348 | assert "$(cat $tmp/exec.out)" "$(printf 'started.')" |
340 | 349 | |
341 | 350 | try "exec single shell utility when two files change simultaneously" |
345 | 354 | bgpid=$! ; zz |
346 | 355 | echo 456 >> $tmp/file1 ; zz |
347 | 356 | kill -INT $bgpid |
348 | wait $bgpid || assert "$?" "130" | |
357 | wait $bgpid; assert "$?" "0" | |
349 | 358 | assert "$(cat $tmp/exec.out)" "ping" |
350 | 359 | |
351 | 360 | try "exec single shell utility on startup and when a file is changed" |
354 | 363 | bgpid=$! ; zz |
355 | 364 | echo 456 >> $tmp/file1 ; zz |
356 | 365 | kill -INT $bgpid |
357 | wait $bgpid || assert "$?" "130" | |
366 | wait $bgpid; assert "$?" "0" | |
358 | 367 | assert "$(cat $tmp/exec.out)" "pingping" |
359 | 368 | |
360 | 369 | try "exec a command if a file is made executable" |
363 | 372 | bgpid=$! ; zz |
364 | 373 | chmod +x $tmp/file2 ; zz |
365 | 374 | kill -INT $bgpid |
366 | wait $bgpid || assert "$?" "130" | |
375 | wait $bgpid; assert "$?" "0" | |
367 | 376 | assert "$(cat $tmp/exec.out)" "$tmp/file2" |
368 | 377 | |
369 | 378 | try "ensure watches operate on a running executable" |
374 | 383 | bgpid=$! ; zz |
375 | 384 | cp -f /bin/sleep $tmp/ ; zz |
376 | 385 | kill -INT $bgpid |
377 | wait $bgpid || assert "$?" "130" | |
386 | wait $bgpid; assert "$?" "0" | |
378 | 387 | rm -f $tmp/sleep |
379 | 388 | assert "$(cat $tmp/exec.out)" "$(printf 'vroom\nvroom\n')" |
380 | 389 | |
384 | 393 | bgpid=$! ; zz |
385 | 394 | echo 456 > $tmp/file1 ; zz |
386 | 395 | kill -INT $bgpid |
387 | wait $bgpid || assert "$?" "130" | |
396 | wait $bgpid; assert "$?" "0" | |
388 | 397 | assert "$(cat $tmp/exec.out)" "456" |
389 | 398 | |
390 | 399 | try "exec single shell utility using utility substitution" |
393 | 402 | bgpid=$! ; zz |
394 | 403 | echo 456 >> $tmp/file2; zz |
395 | 404 | kill -INT $bgpid |
396 | wait $bgpid || assert "$?" "130" | |
405 | wait $bgpid; assert "$?" "0" | |
397 | 406 | assert "$(cat $tmp/exec.out)" "$tmp/file2: ASCII text" |
398 | 407 | |
399 | 408 | try "watch and exec a program that is overwritten" |
406 | 415 | echo vroom |
407 | 416 | EOF |
408 | 417 | zz ; kill -INT $bgpid |
409 | wait $bgpid || assert "$?" "130" | |
418 | wait $bgpid; assert "$?" "0" | |
410 | 419 | assert "$(cat $tmp/exec.out)" "vroom" |
411 | 420 | |
412 | 421 | try "exec an interactive utility when a file changes" |
415 | 424 | bgpid=$! ; zz |
416 | 425 | echo 456 >> $tmp/file2 ; zz |
417 | 426 | kill -INT $bgpid |
418 | wait $bgpid || assert "$?" "130" | |
427 | wait $bgpid; assert "$?" "0" | |
419 | 428 | if ! test -t 0 ; then |
420 | 429 | skip "A TTY is not available" |
421 | 430 | else |
428 | 437 | bgpid=$! ; zz |
429 | 438 | echo 456 >> $tmp/file2 ; zz |
430 | 439 | kill -INT $bgpid |
431 | wait $bgpid || assert "$?" "130" | |
440 | wait $bgpid; assert "$?" "0" | |
432 | 441 | assert "$(cat $tmp/exec.err)" "" |
433 | 442 | assert "$(head -n1 $tmp/exec.out)" "$(printf ${tmp}'/file2: ASCII text')" |
434 | 443 | |
449 | 458 | echo "123" > $tmp/file1 |
450 | 459 | sleep 1 |
451 | 460 | kill -INT $bgpid |
452 | wait $bgpid || assert "$?" "130" | |
461 | wait $bgpid; assert "$?" "0" | |
453 | 462 | assert "$(cat $tmp/exec.out)" "$(printf 'vroom\nvroom\n')" |
454 | 463 | |
455 | 464 | try "ensure that all subprocesses are terminated in restart mode when a file is removed" |