static bool _match_daemon(const char *path, const char *file, RC_STRINGLIST *match) { char *line = NULL; size_t len = 0; char ffile[PATH_MAX]; FILE *fp; RC_STRING *m; snprintf(ffile, sizeof(ffile), "%s/%s", path, file); fp = fopen(ffile, "r"); if (!fp) return false; while ((rc_getline(&line, &len, fp))) { TAILQ_FOREACH(m, match, entries) if (strcmp(line, m->value) == 0) { TAILQ_REMOVE(match, m, entries); break; } if (!TAILQ_FIRST(match)) break; } fclose(fp); free(line); if (TAILQ_FIRST(match)) return false; return true; }
static bool file_regex(const char *file, const char *regex) { FILE *fp; char *line = NULL; size_t len = 0; regex_t re; bool retval = true; int result; if (!(fp = fopen(file, "r"))) return false; if ((result = regcomp(&re, regex, REG_EXTENDED | REG_NOSUB)) != 0) { fclose(fp); line = xmalloc(sizeof(char) * BUFSIZ); regerror(result, &re, line, BUFSIZ); fprintf(stderr, "file_regex: %s", line); free(line); return false; } while ((rc_getline(&line, &len, fp))) { char *str = line; /* some /proc files have \0 separated content so we have to loop through the 'line' */ do { if (regexec(&re, str, 0, NULL, 0) == 0) goto found; str += strlen(str) + 1; /* len is the size of allocated buffer and we don't want call regexec BUFSIZE times. find next str */ while (str < line + len && *str == '\0') str++; } while (str < line + len); } retval = false; found: fclose(fp); free(line); regfree(&re); return retval; }
RC_PIDLIST * rc_find_pids(const char *exec, const char *const *argv, uid_t uid, pid_t pid) { DIR *procdir; struct dirent *entry; FILE *fp; bool container_pid = false; bool openvz_host = false; char *line = NULL; size_t len = 0; pid_t p; char buffer[PATH_MAX]; struct stat sb; pid_t runscript_pid = 0; char *pp; RC_PIDLIST *pids = NULL; RC_PID *pi; if ((procdir = opendir("/proc")) == NULL) return NULL; /* We never match RC_RUNSCRIPT_PID if present so we avoid the below scenario /etc/init.d/ntpd stop does start-stop-daemon --stop --name ntpd catching /etc/init.d/ntpd stop nasty */ if ((pp = getenv("RC_RUNSCRIPT_PID"))) { if (sscanf(pp, "%d", &runscript_pid) != 1) runscript_pid = 0; } /* If /proc/self/status contains EnvID: 0, then we are an OpenVZ host, and we will need to filter out processes that are inside containers from our list of pids. */ if (exists("/proc/self/status")) { fp = fopen("/proc/self/status", "r"); if (fp) { while (! feof(fp)) { rc_getline(&line, &len, fp); if (strncmp(line, "envID:\t0", 8) == 0) { openvz_host = true; break; } } fclose(fp); } } while ((entry = readdir(procdir)) != NULL) { if (sscanf(entry->d_name, "%d", &p) != 1) continue; if (runscript_pid != 0 && runscript_pid == p) continue; if (pid != 0 && pid != p) continue; if (uid) { snprintf(buffer, sizeof(buffer), "/proc/%d", p); if (stat(buffer, &sb) != 0 || sb.st_uid != uid) continue; } if (exec && !pid_is_exec(p, exec)) continue; if (argv && !pid_is_argv(p, (const char *const *)argv)) continue; /* If this is an OpenVZ host, filter out container processes */ if (openvz_host) { snprintf(buffer, sizeof(buffer), "/proc/%d/status", p); if (exists(buffer)) { fp = fopen(buffer, "r"); if (! fp) continue; while (! feof(fp)) { rc_getline(&line, &len, fp); if (strncmp(line, "envID:", 6) == 0) { container_pid = ! (strncmp(line, "envID:\t0", 8) == 0); break; } } fclose(fp); } } if (container_pid) continue; if (!pids) { pids = xmalloc(sizeof(*pids)); LIST_INIT(pids); } pi = xmalloc(sizeof(*pi)); pi->pid = p; LIST_INSERT_HEAD(pids, pi, entries); } if (line != NULL) free(line); closedir(procdir); return pids; }
bool rc_service_daemons_crashed(const char *service) { char dirpath[PATH_MAX]; DIR *dp; struct dirent *d; char *path = dirpath; FILE *fp; char *line = NULL; size_t len = 0; char **argv = NULL; char *exec = NULL; char *name = NULL; char *pidfile = NULL; pid_t pid = 0; RC_PIDLIST *pids; RC_PID *p1; RC_PID *p2; char *p; char *token; bool retval = false; RC_STRINGLIST *list = NULL; RC_STRING *s; size_t i; char *ch_root; char *spidfile; path += snprintf(dirpath, sizeof(dirpath), RC_SVCDIR "/daemons/%s", basename_c(service)); if (!(dp = opendir(dirpath))) return false; while ((d = readdir(dp))) { if (d->d_name[0] == '.') continue; snprintf(path, sizeof(dirpath) - (path - dirpath), "/%s", d->d_name); fp = fopen(dirpath, "r"); if (!fp) break; while ((rc_getline(&line, &len, fp))) { p = line; if ((token = strsep(&p, "=")) == NULL || !p) continue; if (!*p) continue; if (strcmp(token, "exec") == 0) { if (exec) free(exec); exec = xstrdup(p); } else if (strncmp(token, "argv_", 5) == 0) { if (!list) list = rc_stringlist_new(); rc_stringlist_add(list, p); } else if (strcmp(token, "name") == 0) { if (name) free(name); name = xstrdup(p); } else if (strcmp(token, "pidfile") == 0) { pidfile = xstrdup(p); break; } } fclose(fp); ch_root = rc_service_value_get(basename_c(service), "chroot"); spidfile = pidfile; if (ch_root && pidfile) { spidfile = xmalloc(strlen(ch_root) + strlen(pidfile) + 1); strcpy(spidfile, ch_root); strcat(spidfile, pidfile); free(pidfile); pidfile = spidfile; } pid = 0; if (pidfile) { retval = true; if ((fp = fopen(pidfile, "r"))) { if (fscanf(fp, "%d", &pid) == 1) retval = false; fclose(fp); } free(pidfile); pidfile = NULL; /* We have the pid, so no need to match on exec or name */ free(exec); exec = NULL; free(name); name = NULL; } else { if (exec) { if (!list) list = rc_stringlist_new(); if (!TAILQ_FIRST(list)) rc_stringlist_add(list, exec); free(exec); exec = NULL; } if (list) { /* We need to flatten our linked list into an array */ i = 0; TAILQ_FOREACH(s, list, entries) i++; argv = xmalloc(sizeof(char *) * (i + 1)); i = 0; TAILQ_FOREACH(s, list, entries) argv[i++] = s->value; argv[i] = '\0'; } } if (!retval) { if (pid != 0) { if (kill(pid, 0) == -1 && errno == ESRCH) retval = true; } else if ((pids = rc_find_pids(exec, (const char *const *)argv, 0, pid))) { p1 = LIST_FIRST(pids); while (p1) { p2 = LIST_NEXT(p1, entries); free(p1); p1 = p2; } free(pids); } else retval = true; } rc_stringlist_free(list); list = NULL; free(argv); argv = NULL; free(exec); exec = NULL; free(name); name = NULL; if (retval) break; } closedir(dp); free(line); return retval; }