/* * Read lines from a file stream (normally STDIN) * Returns the number of regular files to be watched or -1 if max_files is * exceeded */ int process_input(FILE *file, WatchFile *files[], int max_files) { char buf[PATH_MAX]; char *p, *path; int n_files = 0; struct stat sb; int i, matches; while (fgets(buf, sizeof(buf), file) != NULL) { buf[PATH_MAX-1] = '\0'; if ((p = strchr(buf, '\n')) != NULL) *p = '\0'; if (buf[0] == '\0') continue; if (xstat(buf, &sb) == -1) { xwarnx("unable to stat '%s'", buf); continue; } if (S_ISREG(sb.st_mode) != 0) { files[n_files] = malloc(sizeof(WatchFile)); strlcpy(files[n_files]->fn, buf, MEMBER_SIZE(WatchFile, fn)); files[n_files]->is_dir = 0; files[n_files]->file_count = 0; files[n_files]->mode = sb.st_mode; n_files++; } /* also watch the directory if it's not already in the list */ if (dirwatch_opt == 1) { if (S_ISDIR(sb.st_mode) != 0) path = &buf[0]; else if ((path = dirname(buf)) == 0) err(1, "dirname '%s' failed", buf); for (matches=0, i=0; i<n_files; i++) if (strcmp(files[i]->fn, path) == 0) matches++; if (matches == 0) { files[n_files] = malloc(sizeof(WatchFile)); strlcpy(files[n_files]->fn, path, MEMBER_SIZE(WatchFile, fn)); files[n_files]->is_dir = 1; files[n_files]->file_count = xlist_dir(path); files[n_files]->mode = sb.st_mode; n_files++; } } if (n_files+1 > max_files) return -1; } return n_files; }
/* * The Event Notify Test Runner * run arbitrary commands when files change */ int main(int argc, char *argv[]) { struct rlimit rl; int kq; struct sigaction act; int ttyfd; short argv_index; int n_files; int i; if ((*test_runner_main)) return(test_runner_main(argc, argv)); /* set up pointers to real functions */ xstat = stat; xkevent = kevent; xkillpg = killpg; xexecvp = execvp; xwaitpid = waitpid; xfork = fork; xopen = open; xrealpath = realpath; xfree = free; xwarnx = warnx; xerrx = errx; xlist_dir = list_dir; /* call usage() if no command is supplied */ if (argc < 2) usage(); argv_index = set_options(argv); /* normally a user will exit this utility by do_execting Ctrl-C */ act.sa_flags = 0; act.sa_flags = SA_RESETHAND; act.sa_handler = handle_exit; if (sigemptyset(&act.sa_mask) & (sigaction(SIGINT, &act, NULL) != 0)) err(1, "Failed to set SIGINT handler"); if (sigemptyset(&act.sa_mask) & (sigaction(SIGTERM, &act, NULL) != 0)) err(1, "Failed to set TERM handler"); /* raise soft limit */ getrlimit(RLIMIT_NOFILE, &rl); rl.rlim_cur = min((rlim_t)sysconf(_SC_OPEN_MAX), rl.rlim_max); if (setrlimit(RLIMIT_NOFILE, &rl) != 0) err(1, "setrlimit cannot set rlim_cur to %d", (int)rl.rlim_cur); /* prevent interactive utilities from paging output */ setenv("PAGER", "/bin/cat", 0); /* sequential scan may depend on a 0 at the end */ files = calloc(rl.rlim_cur+1, sizeof(WatchFile *)); if ((kq = kqueue()) == -1) err(1, "cannot create kqueue"); /* read input and populate watch list, skipping non-regular files */ n_files = process_input(stdin, files, rl.rlim_cur); if (n_files == 0) errx(1, "No regular files to watch"); if (n_files == -1) errx(1, "Too many files listed; the hard limit for your login" " class is %d. Please consult" " http://entrproject.org/limits.html", (int)rl.rlim_cur); for (i=0; i<n_files; i++) watch_file(kq, files[i]); /* Attempt to open a tty so that editors don't complain */ ttyfd = xopen(_PATH_TTY, O_RDONLY); if (ttyfd > STDIN_FILENO) { if (dup2(ttyfd, STDIN_FILENO) != 0) xwarnx("can't dup2 to stdin"); close(ttyfd); } watch_loop(kq, argv+argv_index); return 1; }
/* * getopt_long -- * Parse argc/argv argument vector. */ int getopt_long(int nargc, char * const *nargv, const char *options, const struct option *long_options, int *idx) { int retval; _DIAGASSERT(nargv != NULL); _DIAGASSERT(options != NULL); _DIAGASSERT(long_options != NULL); /* idx may be NULL */ progname = nargv[0]; /* fprintf(stderr, "FYI: using private getoptlong.c implementation\n"); */ if ((retval = getopt_internal(nargc, nargv, options)) == -2) { char *current_argv, *has_equal; size_t current_argv_len; int i, match; current_argv = place; match = -1; optind++; place = EMSG; if (*current_argv == '\0') { /* found "--" */ /* * We found an option (--), so if we skipped * non-options, we have to permute. */ if (nonopt_end != -1) { permute_args(nonopt_start, nonopt_end, optind, nargv); optind -= nonopt_end - nonopt_start; } nonopt_start = nonopt_end = -1; return -1; } if ((has_equal = strchr(current_argv, '=')) != NULL) { /* argument found (--option=arg) */ current_argv_len = has_equal - current_argv; has_equal++; } else current_argv_len = strlen(current_argv); for (i = 0; long_options[i].name; i++) { /* find matching long option */ if (strncmp(current_argv, long_options[i].name, current_argv_len)) continue; if (strlen(long_options[i].name) == (unsigned)current_argv_len) { /* exact match */ match = i; break; } if (match == -1) /* partial match */ match = i; else { /* ambiguous abbreviation */ if (PRINT_ERROR) xwarnx(ambig, (int)current_argv_len, current_argv); optopt = 0; return BADCH; } } if (match != -1) { /* option found */ if (long_options[match].has_arg == no_argument && has_equal) { if (PRINT_ERROR) xwarnx(noarg, (int)current_argv_len, current_argv); /* * XXX: GNU sets optopt to val regardless of * flag */ if (long_options[match].flag == NULL) optopt = long_options[match].val; else optopt = 0; /* XXX: GNU returns '?' if options[0] != ':' */ fprintf(stdout, "Sanity: 5\n");fprintf(stderr, "SANITY: 5\n"); // if (options[0] != ':') // return BADCH; optopt = BADCH; // return BADCH; return BADARG; } if (long_options[match].has_arg == required_argument || long_options[match].has_arg == optional_argument) { if (has_equal) optarg = has_equal; else if (long_options[match].has_arg == required_argument) { /* * optional argument doesn't use * next nargv */ if (optind >= nargc) { /* end of argument vector */ //fprintf(stdout, "Sanity: 8\n");fprintf(stderr, "SANITY: 8\n"); optarg = 0; } else { //fprintf(stdout, "Sanity: 9\n");fprintf(stderr, "SANITY: 9\n"); optarg = nargv[optind++]; } } } if ((long_options[match].has_arg == required_argument) && (optarg == NULL)) { /* * Missing argument; leading ':' * indicates no error should be generated */ if (PRINT_ERROR) xwarnx(recargstring, current_argv); /* * XXX: GNU sets optopt to val regardless * of flag */ if (long_options[match].flag == NULL) optopt = long_options[match].val; else optopt = 0; /* XXX: GNU returns '?' if options[0] != ':' */ //--optind; //fprintf(stdout, "Sanity: 6\n");fprintf(stderr, "SANITY: 6\n"); return BADARG; } } else { /* unknown option */ if (PRINT_ERROR) xwarnx(illoptstring, current_argv); optopt = 0; optarg = current_argv; return BADCH; } if (long_options[match].flag) { *long_options[match].flag = long_options[match].val; retval = 0; } else retval = long_options[match].val; if (idx) *idx = match; } //fprintf(stdout, "Terminal: %d\n",retval);fprintf(stderr, "TERMINAL: %d\n",retval); return retval; }
/* * getopt_internal -- * Parse argc/argv argument vector. Called by user level routines. * Returns -2 if -- is found (can be long option or end of options marker). */ static int getopt_internal(int nargc, char * const *nargv, const char *options) { char *oli; /* option letter list index */ int optchar; _DIAGASSERT(nargv != NULL); _DIAGASSERT(options != NULL); optarg = NULL; /* * XXX Some programs (like rsyncd) expect to be able to * XXX re-initialize optind to 0 and have getopt_long(3) * XXX properly function again. Work around this braindamage. */ if (optind == 0) optind = 1; if (optreset) nonopt_start = nonopt_end = -1; start: if (optreset || !*place) { /* update scanning pointer */ optreset = 0; if (optind >= nargc) { /* end of argument vector */ place = EMSG; if (nonopt_end != -1) { /* do permutation, if we have to */ permute_args(nonopt_start, nonopt_end, optind, nargv); optind -= nonopt_end - nonopt_start; } else if (nonopt_start != -1) { /* * If we skipped non-options, set optind * to the first of them. */ optind = nonopt_start; } nonopt_start = nonopt_end = -1; return -1; } if (*(place = nargv[optind]) != '-') { /* found non-option */ place = EMSG; if (IN_ORDER) { /* * GNU extension: * return non-option as argument to option 1 */ optarg = nargv[optind++]; return INORDER; } if (!PERMUTE) { /* * if no permutation wanted, stop parsing * at first non-option */ return -1; } /* do permutation */ if (nonopt_start == -1) nonopt_start = optind; else if (nonopt_end != -1) { permute_args(nonopt_start, nonopt_end, optind, nargv); nonopt_start = optind - (nonopt_end - nonopt_start); nonopt_end = -1; } optind++; /* process next argument */ goto start; } if (nonopt_start != -1 && nonopt_end == -1) nonopt_end = optind; if (place[1] && *++place == '-') { /* found "--" */ place++; return -2; } } if ((optchar = (int)*place++) == (int)':' || (oli = strchr(options + (IGNORE_FIRST ? 1 : 0), optchar)) == NULL) { /* option letter unknown or ':' */ if (!*place) ++optind; if (PRINT_ERROR) xwarnx(illoptchar, optchar); optopt = optchar; return BADCH; } if (optchar == 'W' && oli[1] == ';') { /* -W long-option */ /* XXX: what if no long options provided (called by getopt)? */ if (*place) return -2; if (++optind >= nargc) { /* no arg */ place = EMSG; if (PRINT_ERROR) xwarnx(recargchar, optchar); optopt = optchar; /* XXX: GNU returns '?' if options[0] != ':' */ fprintf(stdout, "Sanity: 2\n");fprintf(stderr, "SANITY: 2\n"); return BADARG; } else /* white space */ place = nargv[optind]; /* * Handle -W arg the same as --arg (which causes getopt to * stop parsing). */ return -2; } if (*++oli != ':') { /* doesn't take argument */ if (!*place) ++optind; } else { /* takes (optional) argument */ optarg = NULL; if (*place) /* no white space */ optarg = place; /* XXX: disable test for :: if PC? (GNU doesn't) */ else if (oli[1] != ':') { /* arg not optional */ if (++optind >= nargc) { /* no arg */ place = EMSG; if (PRINT_ERROR) xwarnx(recargchar, optchar); optopt = optchar; /* XXX: GNU returns '?' if options[0] != ':' */ fprintf(stdout, "Sanity: 3\n");fprintf(stderr, "SANITY: 3\n"); return BADARG; } else optarg = nargv[optind]; } place = EMSG; ++optind; } /* dump back option letter */ return optchar; }
static bool _rtld_load_by_name(const char *name, Obj_Entry *obj, Needed_Entry **needed, int flags) { Library_Xform *x = _rtld_xforms; Obj_Entry *o = NULL; size_t j; ssize_t i; bool got = false; union { int i; u_quad_t q; char s[16]; } val; dbg(("load by name %s %p", name, x)); for (; x; x = x->next) { #ifdef __minix continue; #else if (strcmp(x->name, name) != 0) continue; j = sizeof(val); if ((i = _rtld_sysctl(x->ctlname, &val, &j)) == -1) { xwarnx(_PATH_LD_HINTS ": invalid/unknown sysctl for %s (%d)", name, errno); break; } switch (i) { case CTLTYPE_QUAD: xsnprintf(val.s, sizeof(val.s), "%" PRIu64, val.q); break; case CTLTYPE_INT: xsnprintf(val.s, sizeof(val.s), "%d", val.i); break; case CTLTYPE_STRING: break; default: xwarnx("unsupported sysctl type %d", (int)i); break; } dbg(("sysctl returns %s", val.s)); for (i = 0; i < RTLD_MAX_ENTRY && x->entry[i].value != NULL; i++) { dbg(("entry %ld", (unsigned long)i)); if (strcmp(x->entry[i].value, val.s) == 0) break; } if (i == RTLD_MAX_ENTRY) { xwarnx("sysctl value %s not found for lib%s", val.s, name); break; } for (j = 0; j < RTLD_MAX_LIBRARY && x->entry[i].library[j] != NULL; j++) { o = _rtld_load_library(x->entry[i].library[j], obj, flags); if (o == NULL) { xwarnx("could not load %s for %s", x->entry[i].library[j], name); continue; } got = true; if (j == 0) (*needed)->obj = o; else { /* make a new one and put it in the chain */ Needed_Entry *ne = xmalloc(sizeof(*ne)); ne->name = (*needed)->name; ne->obj = o; ne->next = (*needed)->next; (*needed)->next = ne; *needed = ne; } } #endif } if (got) return true; return ((*needed)->obj = _rtld_load_library(name, obj, flags)) != NULL; }
/* * Process library mappings of the form: * <library_name> <machdep_variable> <value,...:library_name,...> ... */ static void _rtld_process_mapping(Library_Xform **lib_p, const char *bp, const char *ep) { Library_Xform *hwptr = NULL; const char *ptr, *key, *ekey, *lib, *elib, *l; int i, j; dbg((" processing mapping \"%.*s\"", (int)(ep - bp), bp)); if ((ptr = getword(&bp, ep, WS)) == NULL || ptr == bp) return; dbg((" library \"%.*s\"", (int)(bp - ptr), ptr)); hwptr = xmalloc(sizeof(*hwptr)); memset(hwptr, 0, sizeof(*hwptr)); hwptr->name = exstrdup(ptr, bp); bp++; if ((ptr = getword(&bp, ep, WS)) == NULL || ptr == bp) { xwarnx("missing sysctl variable name"); goto cleanup; } dbg((" sysctl \"%.*s\"", (int)(bp - ptr), ptr)); hwptr->ctlname = exstrdup(ptr, bp); for (i = 0; bp++, (ptr = getword(&bp, ep, WS)) != NULL;) { dbg((" ptr = %.*s", (int)(bp - ptr), ptr)); if (ptr == bp) continue; if (i == RTLD_MAX_ENTRY) { no_more: xwarnx("maximum library entries exceeded `%s'", hwptr->name); goto cleanup; } if ((key = getstr(&ptr, bp, ":")) == NULL) { xwarnx("missing sysctl variable value for `%s'", hwptr->name); goto cleanup; } ekey = ptr++; if ((lib = getstr(&ptr, bp, ":")) == NULL) { xwarnx("missing sysctl library list for `%s'", hwptr->name); goto cleanup; } elib = ptr; /* No need to advance */ for (j = 0; (l = getstr(&lib, elib, ",")) != NULL; j++, lib++) { if (j == RTLD_MAX_LIBRARY) { xwarnx("maximum library entries exceeded `%s'", hwptr->name); goto cleanup; } dbg((" library \"%.*s\"", (int)(lib - l), l)); hwptr->entry[i].library[j] = exstrdup(l, lib); } if (j == 0) { xwarnx("No library map entries for `%s/%.*s'", hwptr->name, (int)(bp - ptr), ptr); goto cleanup; } j = i; for (; (l = getstr(&key, ekey, ",")) != NULL; i++, key++) { /* * Allow empty key (it is valid as string * value). Thus, we loop at least once and * `i' is incremented. */ dbg((" key \"%.*s\"", (int)(key - l), l)); if (i == RTLD_MAX_ENTRY) goto no_more; if (i != j) (void)memcpy(hwptr->entry[i].library, hwptr->entry[j].library, sizeof(hwptr->entry[j].library)); hwptr->entry[i].value = exstrdup(l, key); } } if (i == 0) { xwarnx("No library entries for `%s'", hwptr->name); goto cleanup; } hwptr->next = *lib_p; *lib_p = hwptr; return; cleanup: if (hwptr->name) xfree(hwptr->name); xfree(hwptr); }