/* * Substitue only the first occurance of '/_' */ int run_utility_02() { static char *argv[] = { "/_", "/_", NULL }; char input[] = "one.sh\ntwo.sh"; FILE *fake; fake = fmemopen(input, strlen(input), "r"); (void) process_input(fake, files, 3); leading_edge = files[0]; run_utility(argv); ok(ctx.exec.count == 1); ok(ctx.exec.file != 0); ok(strcmp(ctx.exec.file, "/home/user/one.sh") == 0); ok(strcmp(ctx.exec.argv[0], "/home/user/one.sh") == 0); ok(strcmp(ctx.exec.argv[1], "/_") == 0); return 0; }
/* * Wait for events to and execute a command. Four major concerns are in play: * leading_edge: Global reference to the first file to have changed * reopen_only : Unlink or rename events which require us to spin while * waiting for the file to reappear. These must always be * processed * collate_only: Changes that indicate that more events are likely to occur. * Watch for more events using a short timeout * do_exec : Delay execution until all events have been processed. Allow * the user to edit files while the utility is running without * any visible side-effects * dir_modified: The number of files changed for a directory under watch */ void watch_loop(int kq, char *argv[]) { struct kevent evSet; struct kevent evList[32]; int nev; WatchFile *file; int i; struct timespec evTimeout = { 0, 1000000 }; int reopen_only = 0; int collate_only = 0; int do_exec = 0; int dir_modified = 0; int leading_edge_set = 0; struct stat sb; leading_edge = files[0]; /* default */ if (postpone_opt == 0) run_utility(argv); main: if ((reopen_only == 1) || (collate_only == 1)) nev = xkevent(kq, NULL, 0, evList, 32, &evTimeout); else { nev = xkevent(kq, NULL, 0, evList, 32, NULL); dir_modified = 0; } /* escape for test runner */ if ((nev == -2) && (collate_only == 0)) return; for (i=0; i<nev; i++) { if (evList[i].filter != EVFILT_VNODE) continue; file = (WatchFile *)evList[i].udata; if (file->is_dir == 1) dir_modified += compare_dir_contents(file); else if (leading_edge_set == 0) if ((reopen_only == 0) && (collate_only == 0)) { leading_edge = file; leading_edge_set = 1; } } collate_only = 0; for (i=0; i<nev; i++) { file = (WatchFile *)evList[i].udata; if (evList[i].fflags & NOTE_DELETE || evList[i].fflags & NOTE_RENAME) { EV_SET(&evSet, file->fd, EVFILT_VNODE, EV_DELETE, NOTE_ALL, 0, file); if (xkevent(kq, &evSet, 1, NULL, 0, NULL) == -1) err(1, "failed to remove VNODE event"); if ((file->fd != -1) && (close(file->fd) == -1)) err(1, "unable to close file"); watch_file(kq, file); collate_only = 1; } } if (reopen_only == 1) { reopen_only = 0; goto main; } for (i=0; i<nev && reopen_only == 0; i++) { file = (WatchFile *)evList[i].udata; if ((file->is_dir == 1) && (dir_modified == 0)) continue; if (evList[i].fflags & NOTE_DELETE || evList[i].fflags & NOTE_WRITE || evList[i].fflags & NOTE_RENAME || evList[i].fflags & NOTE_TRUNCATE) { if ((dir_modified > 0) && (restart_opt == 1)) continue; do_exec = 1; } if (evList[i].fflags & NOTE_ATTRIB && S_ISREG(file->mode) != 0 && xstat(file->fn, &sb) == 0 && file->mode != sb.st_mode) { do_exec = 1; file->mode = sb.st_mode; } } if (collate_only == 1) goto main; if (do_exec == 1) { do_exec = 0; run_utility(argv); reopen_only = 1; leading_edge_set = 0; } if (dir_modified > 0) { terminate_utility(); xerrx(2, "directory altered"); } goto main; }
/* * Wait for events to and execute a command or write filename to a FIFO. * Four major concerns are in play here: * leading_edge: Global reference to the first file to have changed * reopen_only : Unlink or rename events which require us to spin while * waiting for the file to reappear. These must always be * processed * collate_only: Changes that indicate that more events are likely to occur. * Watch for more events using a short timeout * do_exec : Delay execution until all events have been processed. Allow * the user to edit files while the utility is running without * any visible side-effects * dir_modified: The number of files changed for a directory under watch */ void watch_loop(int kq, char *argv[]) { struct kevent evSet; struct kevent evList[32]; int nev; WatchFile *file; int i; struct timespec evTimeout = { 0, 1000000 }; int reopen_only = 0; int collate_only = 0; int do_exec = 0; int dir_modified = 0; leading_edge = files[0]; /* default */ if (restart_opt) run_utility(argv); main: if ((reopen_only == 1) || (collate_only == 1)) nev = xkevent(kq, NULL, 0, evList, 32, &evTimeout); else { nev = xkevent(kq, NULL, 0, evList, 32, NULL); dir_modified = 0; } /* escape for test runner */ if ((nev == -2) && (collate_only == 0)) return; for (i=0; i<nev; i++) { #ifdef DEBUG fprintf(stderr, "event %d/%d: ident %d filter %d flags 0x%x " "fflags 0x%x udata %d udata %p\n", i+1, nev, evList[i].ident, evList[i].filter, evList[i].flags, evList[i].fflags, evList[i].data, evList[i].udata); #endif if (evList[i].filter != EVFILT_VNODE) continue; file = (WatchFile *)evList[i].udata; if (file->is_dir == 1) dir_modified += compare_dir_contents(file); if ((i == 0) && (reopen_only == 0) && (collate_only == 0)) leading_edge = file; } collate_only = 0; for (i=0; i<nev; i++) { file = (WatchFile *)evList[i].udata; if (evList[i].fflags & NOTE_DELETE || evList[i].fflags & NOTE_RENAME) { EV_SET(&evSet, file->fd, EVFILT_VNODE, EV_DELETE, NOTE_ALL, 0, file); if (xkevent(kq, &evSet, 1, NULL, 0, NULL) == -1) err(1, "failed to remove VNODE event"); if ((file->fd != -1) && (close(file->fd) == -1)) err(1, "unable to close file"); watch_file(kq, file); collate_only = 1; } } if (reopen_only == 1) { reopen_only = 0; goto main; } for (i=0; i<nev && reopen_only == 0; i++) { file = (WatchFile *)evList[i].udata; if ((file->is_dir == 1) && (dir_modified == 0)) continue; if (evList[i].fflags & NOTE_DELETE || evList[i].fflags & NOTE_WRITE || evList[i].fflags & NOTE_RENAME || evList[i].fflags & NOTE_TRUNCATE) { if (fifo.fd == 0) { if ((dir_modified > 0) && (restart_opt == 1)) continue; do_exec = 1; } else { write(fifo.fd, file->fn, strlen(file->fn)); write(fifo.fd, "\n", 1); fsync(fifo.fd); reopen_only = 1; } } } if (collate_only == 1) goto main; if (do_exec == 1) { do_exec = 0; run_utility(argv); reopen_only = 1; } if (dir_modified > 0) xerrx(2, "directory altered"); goto main; }