int rmdir(const char* path) { register int n; struct stat st; char* av[3]; static char* cmd[] = { "/bin/rmdir", "/usr/5bin/rmdir", 0 }; if (stat(path, &st) < 0) return(-1); if (!S_ISDIR(st.st_mode)) { errno = ENOTDIR; return(-1); } av[0] = "rmdir"; av[1] = path; av[2] = 0; for (n = 0; n < elementsof(cmd); n++) if (procclose(procopen(cmd[n], av, NiL, NiL, 0)) != -1) break; n = errno; if (access(path, F_OK) < 0) { errno = n; return(0); } errno = EPERM; return(-1); }
int mkdir(const char* path, mode_t mode) { register int n; char* av[3]; static char* cmd[] = { "/bin/mkdir", "/usr/5bin/mkdir", 0 }; n = errno; if (!access(path, F_OK)) { errno = EEXIST; return(-1); } if (errno != ENOENT) return(-1); errno = n; av[0] = "mkdir"; av[1] = path; av[2] = 0; for (n = 0; n < elementsof(cmd); n++) if (procclose(procopen(cmd[n], av, NiL, NiL, 0)) != -1) break; return(chmod(path, mode)); }
static void finish(int status) { if (remote) { kill(remote->pid, SIGKILL); procclose(remote); } exit(status); }
int procrun(const char* path, char** argv, int flags) { #if __OBSOLETE__ < 20090101 flags &= argv ? PROC_ARGMOD : PROC_CHECK; #endif if (flags & PROC_CHECK) { char buf[PATH_MAX]; return pathpath(path, NiL, PATH_REGULAR|PATH_EXECUTE, buf, sizeof(buf)) ? 0 : -1; } return procclose(procopen(path, argv, NiL, NiL, flags|PROC_FOREGROUND|PROC_GID|PROC_UID)); }
int main(int argc, char** argv) { register int n; register int i; register long v; char* s; char* e; char* data; int uf; int wf; int idlecmd; int usercount; unsigned long t; unsigned long toss; unsigned long usertime; unsigned long now; unsigned long then; Proc_t* proc; CSSTAT ss; struct stat st; char cmd[PATH_MAX]; char buf[PATH_MAX]; char tmp[PATH_MAX / 4]; char* av[4]; char* iv[3]; #if NAMELIST DIR* root; struct dirent* entry; int kf; #endif NoP(argc); error_info.id = CS_STAT_DAEMON; if (!pathpath(error_info.id, argv[0], PATH_ABSOLUTE|PATH_REGULAR|PATH_EXECUTE, cmd, sizeof(cmd))) error(ERROR_SYSTEM|3, "cannot locate daemon executable"); if (!pathpath(CS_STAT_DIR, argv[0], PATH_EXECUTE, buf, sizeof(buf))) error(3, "%s: cannot locate data directory", CS_STAT_DIR); if (stat(buf, &st)) error(ERROR_SYSTEM|3, "%s: stat error", buf); if (st.st_uid != geteuid()) error(3, "%s: effective uid mismatch", buf); if (chdir(buf)) error(ERROR_SYSTEM|3, "%s: chdir error", buf); data = csname(0); if (argv[1] && strcmp(argv[1], data)) { /* * start remote status daemon */ data = argv[1]; if (!csaddr(data)) error(3, "%s: unknown host", data); if (!stat(data, &st) && (long)(CSTIME() - (unsigned long)st.st_ctime) < CS_STAT_DOWN) exit(0); sfsprintf(buf, sizeof(buf), "./%s", data); csstat(buf, &ss); if (s = csattr(CS_HOST_LOCAL, "type")) { strcpy(tmp, s); if (s = csattr(data, "type")) pathrepl(cmd, sizeof(cmd), tmp, s); } /* * loop until remote status daemon starts * check for competing startup daemon */ if (csdaemon(0)) exit(1); umask(S_IRWXU|S_IRWXG|S_IRWXO); av[0] = CS_REMOTE_SHELL; av[1] = data; av[2] = cmd; av[3] = 0; for (;;) { update(data, 0, 0, &ss); if (!(remote = procopen(av[0], av, NiL, NiL, PROC_UID|PROC_GID))) break; while (!kill(remote->pid, 0)) update(data, 0, CS_STAT_FREQ + (CS_STAT_DOWN - CS_STAT_FREQ) / 2, &ss); procclose(remote); remote = 0; if (ss.up > 0) ss.up = -ss.up; } for (;;) update(data, 0, CS_STAT_FREQ + (CS_STAT_DOWN - CS_STAT_FREQ) / 2, &ss); } remove(data); if ((n = open(data, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0)) < 0) error(ERROR_SYSTEM|3, "%s: cannot update", data); for (i = 0; i < elementsof(usrfiles); i++) if ((uf = open(usrfile = usrfiles[i], O_RDONLY)) >= 0) break; if (uf < 0) error(ERROR_SYSTEM|3, "%s: cannot read", usrfiles[0]); /* * final initialization */ if (csdaemon((1<<2)|(1<<n)|(1<<uf))) error(ERROR_SYSTEM|3, "cannot dive into background"); umask(S_IRWXU|S_IRWXG|S_IRWXO); close(2); dup(n); close(n); error_info.id = data; av[0] = "uptime"; av[1] = 0; toss = getpid(); for (s = data; *s; s++) CSTOSS(toss, *s); usertime = 0; #if NAMELIST for (n = 0; n < elementsof(symbols); n++) names[n].n_name = symbols[n].name; if ((kf = open(memfile, O_RDONLY)) >= 0) { if (chdir("/")) error(ERROR_SYSTEM|3, "/: chdir error"); s = 0; for (i = 0; i < elementsof(sysfiles); i++) if (!access(sysfiles[i], F_OK)) { s = sysfiles[i]; break; } if (!s) { if (!(root = opendir("."))) error(ERROR_SYSTEM|3, "/: cannot read"); while (entry = readdir(root)) { if ((i = strlen(entry->d_name) - 2) > 0 && entry->d_name[i] == 'i' && entry->d_name[i + 1] == 'x' && !stat(entry->d_name, &st) && (st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))) { s = entry->d_name; break; } } closedir(root); } nlist(s, names); for (n = 0; n < elementsof(symbols); n++) if (!names[n].n_type) { error(1, "%s: %s not in nlist", s, names[n].n_name); close(kf); kf = -1; } if (chdir(buf)) error(ERROR_SYSTEM|3, "%s: chdir error", buf); } if (kf < 0) #endif { sfsprintf(buf, sizeof(buf), "%s/%s%s%s", WHODIR, WHOPRE, data, WHOSUF); if ((wf = open(buf, O_RDONLY)) >= 0) { if (read(wf, &who, sizeof(who)) != sizeof(who) || who.wd_vers != WHOVERS || who.wd_type != WHOTYPE) { error(1, "%s: rwhod protocol mismatch", buf); close(wf); wf = -1; } else whofile = strdup(buf); } } strcpy(cmd + strlen(cmd), ".idle"); if (eaccess(cmd, X_OK)) idlecmd = 0; else { idlecmd = 1; iv[0] = cmd; iv[1] = data; iv[2] = 0; } /* * the daemon loop */ ss.idle = 4 * 60 * 60; now = CSTIME(); for (;;) { then = now; now = CSTIME(); /* * update logged in user stats */ if (fstat(uf, &st)) error(ERROR_SYSTEM|3, "%s: stat error", usrfile); if (usertime != (unsigned long)st.st_mtime) { usertime = st.st_mtime; if (lseek(uf, 0L, 0)) error(ERROR_SYSTEM|3, "%s: seek error", usrfile); if ((n = read(uf, usrs, sizeof(usrs))) < 0) error(ERROR_SYSTEM|3, "%s: read error", usrfile); usercount = n / sizeof(struct utmp); } /* * count the interesting users * find the min user idle time */ if (idlecmd) { /* * check idle command */ if (!(proc = procopen(iv[0], iv, NiL, NiL, PROC_READ|PROC_UID|PROC_GID))) idlecmd = 0; else { idlecmd = 1; n = read(proc->rfd, buf, sizeof(buf)); if (procclose(proc) || n < 0) idlecmd = 0; else { if (n > 0) n--; buf[n] = 0; if (isdigit(buf[0])) ss.idle = strtol(buf, NiL, 10); else if (streq(buf, "busy")) ss.idle = 0; else if (streq(buf, "free")) ss.idle = ~0; else if (streq(buf, "idle")) { n = since(then); if ((ss.idle + n) < ss.idle) ss.idle = ~0; else ss.idle += n; } else idlecmd = -1; } } } if (idlecmd <= 0) ss.idle = ~0; ss.users = 0; for (i = 0; i < usercount; i++) if (usrs[i].ut_name[0] && usrs[i].ut_line[0]) { sfsprintf(buf, sizeof(buf), "/dev/%s", usrs[i].ut_line); if (stat(buf, &st)) usrs[i].ut_name[0] = 0; else { v = since(st.st_atime); if (v < CS_STAT_IGNORE) ss.users++; if (idlecmd <= 0 && v < ss.idle) ss.idle = v; } } if (idlecmd <= 0 || !ss.users) { /* * check devices for min idle time */ for (i = 0; i < elementsof(devfiles); i++) if (devfiles[i]) { if (stat(devfiles[i], &st)) devfiles[i] = 0; else { v = since(st.st_atime); if (!ss.users && v < CS_STAT_IGNORE) ss.users++; if (idlecmd <= 0 && v < ss.idle) ss.idle = v; } } } /* * get the hard stuff */ #if NAMELIST if (kf >= 0) { /* * update memfile symbol values */ for (n = 0; n < elementsof(symbols); n++) if (symbols[n].once >= 0) { if (lseek(kf, (long)names[n].n_value, 0) != (long)names[n].n_value) error(ERROR_SYSTEM|3, "%s: %s seek error", memfile, names[n].n_name); if (read(kf, symbols[n].addr, symbols[n].size) != symbols[n].size) error(ERROR_SYSTEM|3, "%s: %s read error", memfile, names[n].n_name); if (symbols[n].once) symbols[n].once = -1; } #ifdef CP_TIME for (i = 0; i < CPUSTATES; i++) cp_time[i] = 0; for (n = 0; n <= maxcpu; n++) if (CPUFOUND(n)) for (i = 0; i < CPUSTATES; i++) cp_time[i] += CP_TIME(n)[i]; #endif ss.load = (avenrun * 100) / FSCALE; } else #endif if (wf >= 0) { if (lseek(wf, 0L, 0)) error(ERROR_SYSTEM|3, "%s: seek error", whofile); read(wf, &who, sizeof(who)); ss.load = who.wd_loadav[0]; boottime = who.wd_boottime; for (i = 0; i < elementsof(cp_time); i++) cp_time[i] = 100; } else if (!(proc = procopen(av[0], av, NiL, NiL, PROC_READ|PROC_UID|PROC_GID))) error(ERROR_SYSTEM|3, "%s: exec error", av[0]); else { /* * defer to process with memfile access */ n = read(proc->rfd, buf, sizeof(buf) - 1); if (procclose(proc) || n <= 0) error(3, "%s: invalid", av[0]); buf[n] = 0; if (!(s = strrchr(buf, ':'))) error(3, "%s: invalid output", av[0]); ss.load = strton(s + 1, NiL, NiL, 100); n = 0; if ((s = strchr(buf, 'u')) && *++s == 'p') { n = strtol(s + 1, &e, 10) * 60 * 60; s = e; while (isspace(*s)) s++; if (*s == 'd') { n *= 24; while (*s && !isdigit(*s)) s++; n += strtol(s, &e, 10) * 60 * 60; s = e; } if (*s == ':') n += strtol(s + 1, NiL, 10) * 60; } boottime = since(n); for (i = 0; i < elementsof(cp_time); i++) cp_time[i] = 0; } /* * finalize the new stat info */ t = 0; for (i = 0; i < elementsof(cp_time); i++) { if ((cp_diff[i] = cp_time[i] - cp_prev[i]) < 0) cp_diff[i] = -cp_diff[i]; t += cp_diff[i]; cp_prev[i] = cp_time[i]; } if (!t) t = 1; ss.pctsys = (cp_diff[CP_SYS] * 100) / t; ss.pctusr = ((cp_diff[CP_USER] + cp_diff[CP_NICE]) * 100) / t; ss.up = since(boottime); update(data, now, (4 * CS_STAT_FREQ + 2 * (CSTOSS(toss, 0) % (CS_STAT_FREQ + 1))) / 5, &ss); } }
void filein(register Archive_t* ap, register File_t* f) { register off_t c; register int n; register char* s; int dfd; int wfd; long checksum; Filter_t* fp; Proc_t* pp; Tv_t t1; Tv_t t2; struct stat st; if (f->skip) goto skip; else if (state.list) { if (fp = filter(ap, f)) { for (n = 0; s = fp->argv[n]; n++) { while (*s) if (*s++ == '%' && *s == '(') break; if (*s) { s = fp->argv[n]; listprintf(state.tmp.str, ap, f, s); if (!(fp->argv[n] = sfstruse(state.tmp.str))) nospace(); break; } } pp = procopen(*fp->argv, fp->argv, NiL, NiL, PROC_WRITE); if (s) fp->argv[n] = s; if (!pp) { error(2, "%s: %s: cannot execute filter %s", ap->name, f->path, *fp->argv); goto skip; } if (!ap->format->getdata || !(*ap->format->getdata)(&state, ap, f, pp->wfd)) { checksum = 0; for (c = f->st->st_size; c > 0; c -= n) { n = (c > state.buffersize) ? state.buffersize : c; if (!(s = bget(ap, n, NiL))) { error(ERROR_SYSTEM|2, "%s: read error", f->name); break; } if (write(pp->wfd, s, n) != n) { error(ERROR_SYSTEM|2, "%s: write error", f->name); break; } if (ap->format->checksum) checksum = (*ap->format->checksum)(&state, ap, f, s, n, checksum); } } if (ap->format->checksum && checksum != f->checksum) error(1, "%s: %s checksum error (0x%08x != 0x%08x)", f->name, ap->format->name, checksum, f->checksum); /* * explicitly ignore exit status */ procclose(pp); return; } listentry(f); goto skip; } else switch (f->delta.op) { case DELTA_create: if (f->delta.base) error(3, "%s: base archive mismatch [%s#%d]", f->name, __FILE__, __LINE__); if (ap->delta->format->flags & PSEUDO) goto regular; if ((wfd = openout(ap, f)) < 0) goto skip; else paxdelta(NiL, ap, f, DELTA_TAR|DELTA_FD|DELTA_FREE|DELTA_OUTPUT|DELTA_COUNT, wfd, DELTA_DEL|DELTA_BIO|DELTA_SIZE, ap, f->st->st_size, 0); break; case DELTA_update: if (!f->delta.base || (unsigned long)f->delta.base->mtime.tv_sec >= (unsigned long)f->st->st_mtime) error(3, "%s: base archive mismatch [%s#%d]", f->name, __FILE__, __LINE__); c = f->st->st_size; if ((wfd = openout(ap, f)) < 0) goto skip; if (state.ordered) { if (!f->delta.base->uncompressed) paxdelta(NiL, ap, f, DELTA_SRC|DELTA_BIO|DELTA_SIZE, ap->delta->base, f->delta.base->size, DELTA_TAR|DELTA_FD|DELTA_FREE|DELTA_OUTPUT|DELTA_COUNT, wfd, DELTA_DEL|DELTA_BIO|DELTA_SIZE, ap, c, 0); else if (!paxdelta(NiL, ap, f, DELTA_DEL|DELTA_BIO|DELTA_SIZE, ap->delta->base, f->delta.base->size, DELTA_TAR|DELTA_TEMP|DELTA_OUTPUT, &dfd, 0)) paxdelta(NiL, ap, f, DELTA_SRC|DELTA_FD|DELTA_SIZE|DELTA_FREE, dfd, f->delta.base->uncompressed, DELTA_TAR|DELTA_FD|DELTA_FREE|DELTA_OUTPUT|DELTA_COUNT, wfd, DELTA_DEL|DELTA_BIO|DELTA_SIZE, ap, c, 0); } else if (!f->delta.base->uncompressed) paxdelta(NiL, ap, f, DELTA_SRC|DELTA_FD|DELTA_OFFSET|DELTA_SIZE, ap->delta->base->io->fd, f->delta.base->offset, f->delta.base->size, DELTA_TAR|DELTA_FD|DELTA_FREE|DELTA_OUTPUT|DELTA_COUNT, wfd, DELTA_DEL|DELTA_BIO|DELTA_SIZE, ap, c, 0); else if (!paxdelta(NiL, ap, f, DELTA_DEL|DELTA_FD|DELTA_OFFSET|DELTA_SIZE, ap->delta->base->io->fd, f->delta.base->offset, f->delta.base->size, DELTA_TAR|DELTA_TEMP|DELTA_OUTPUT, &dfd, 0)) paxdelta(NiL, ap, f, DELTA_SRC|DELTA_FD|DELTA_SIZE|DELTA_FREE, dfd, f->delta.base->uncompressed, DELTA_TAR|DELTA_FD|DELTA_FREE|DELTA_OUTPUT|DELTA_COUNT, wfd, DELTA_DEL|DELTA_BIO|DELTA_SIZE, ap, c, 0); break; case DELTA_verify: if (!f->delta.base || f->delta.base->mtime.tv_sec != f->st->st_mtime) error(3, "%s: base archive mismatch [%s#%d]", f->name, __FILE__, __LINE__); if ((*state.statf)(f->name, &st)) error(2, "%s: not copied from base archive", f->name); else if (st.st_size != f->delta.base->size || state.modtime && tvcmp(tvmtime(&t1, &st), tvmtime(&t2, f->st))) error(1, "%s: changed from base archive", f->name); break; case DELTA_delete: if (!f->delta.base) error(3, "%s: base archive mismatch [%s#%d]", f->name, __FILE__, __LINE__); /*FALLTHROUGH*/ default: regular: wfd = openout(ap, f); if (wfd >= 0) { holeinit(wfd); if (!ap->format->getdata || !(*ap->format->getdata)(&state, ap, f, wfd)) { checksum = 0; for (c = f->st->st_size; c > 0; c -= n) { n = (c > state.buffersize) ? state.buffersize : c; if (!(s = bget(ap, n, NiL))) { error(ERROR_SYSTEM|2, "%s: read error", f->name); break; } if (holewrite(wfd, s, n) != n) { error(ERROR_SYSTEM|2, "%s: write error", f->name); break; } if (ap->format->checksum) checksum = (*ap->format->checksum)(&state, ap, f, s, n, checksum); } } holedone(wfd); closeout(ap, f, wfd); setfile(ap, f); if (ap->format->checksum && checksum != f->checksum) error(1, "%s: %s checksum error (0x%08x != 0x%08x)", f->name, ap->format->name, checksum, f->checksum); } else if (ap->format->getdata) (*ap->format->getdata)(&state, ap, f, wfd); else { if (wfd < -1) listentry(f); goto skip; } break; } listentry(f); return; skip: fileskip(ap, f); }
static int agent(register Cs_t* state, const char* host, const char* user, const char* path) { register int n; register int m; register char* s; Proc_t* proc; int fd = -1; char* av[REMOTE_ARGC]; char fv[REMOTE_FLAGC]; char buf[PATH_MAX / 4]; char num[64]; char tmp[64]; remote(state, host, user, path, 1, av, fv); if (!(proc = procopen(av[0], av, NiL, NiL, PROC_READ|PROC_WRITE|PROC_PRIVELEGED))) goto sorry; if ((m = csread(state, proc->rfd, buf, sizeof(buf), CS_LINE)) <= 1) goto sorry; buf[--m] = 0; if (buf[--m] == 'A') buf[--m] = 0; else m = 0; if ((fd = reopen(state, buf)) < 0) goto sorry; if (m) { if ((m = csread(state, proc->rfd, buf, sizeof(buf), CS_LINE)) <= 1) goto sorry; if (cswrite(state, fd, buf, m) != m) goto sorry; if ((n = csread(state, fd, num, sizeof(num), CS_LINE)) <= 0) goto sorry; if (*num != '\n') { buf[m - 1] = 0; num[n - 1] = 0; n = sfsprintf(tmp, sizeof(tmp), "%s %s\n", num, (s = strchr(buf, ' ')) ? (s + 1) : buf); if (cswrite(state, proc->wfd, tmp, n) != n) goto sorry; if ((m = csread(state, proc->rfd, buf, sizeof(buf), CS_LINE)) <= 0) goto sorry; if (cswrite(state, fd, buf, m) != m) goto sorry; if (csread(state, fd, num, 1, CS_LINE) != 1) goto sorry; if (cswrite(state, proc->wfd, num, 1) != 1) goto sorry; } } procclose(proc); return fd; sorry: if (fd >= 0) close(fd); if (proc) procclose(proc); errno = EACCES; return -1; }
static int initiate(register Cs_t* state, char* user, char* path, char* service, char* name) { register char* s; char* on; char* local; Sfio_t* sp; Sfio_t* np; int n; char* av[REMOTE_ARGC]; char buf[PATH_MAX / 4]; local = csname(state, 0); s = service + strlen(service); *s++ = '/'; if (!(state->flags & CS_ADDR_SHARE)) { sfsprintf(buf, sizeof(buf), "%s\n", state->host); if (!(sp = tokline(buf, SF_STRING, NiL))) return -1; } else if (state->flags & CS_ADDR_LOCAL) { sfsprintf(buf, sizeof(buf), "%s\n", CS_HOST_LOCAL); if (!(sp = tokline(buf, SF_STRING, NiL))) return -1; } else { strcpy(s, CS_SVC_HOSTS); if (!(sp = tokline(service, SF_READ, NiL))) { if (streq(state->host, CS_HOST_SHARE)) sfsprintf(buf, sizeof(buf), "%s\n%s\n", CS_HOST_SHARE, CS_HOST_LOCAL); else sfsprintf(buf, sizeof(buf), "%s\n%s\n%s\n", state->host, CS_HOST_SHARE, CS_HOST_LOCAL); if (!(sp = tokline(buf, SF_STRING, NiL))) return -1; } } sfsprintf(s, PATH_MAX - (s - service) - 1, "%s%s", name, CS_SVC_SUFFIX); while (s = sfgetr(sp, '\n', 1)) if (tokscan(s, NiL, " %s ", &on) == 1) { if (streq(on, CS_HOST_LOCAL) || streq(on, local)) { sfclose(sp); av[0] = service; av[1] = path; av[2] = 0; return procclose(procopen(av[0], av, NiL, NiL, PROC_PRIVELEGED|PROC_ZOMBIE)) < 0 ? -1 : 0; } else if (!streq(on, CS_HOST_SHARE)) { Proc_t* proc; time_t otime; struct stat st; char fv[REMOTE_FLAGC]; long ov[3]; remote(state, on, user, path, 0, av, fv); otime = lstat(state->mount, &st) ? 0 : st.st_ctime; n = open("/dev/null", O_RDWR); ov[0] = PROC_FD_DUP(n, 0, 0); ov[1] = PROC_FD_DUP(n, 1, PROC_FD_PARENT|PROC_FD_CHILD); ov[2] = 0; if (proc = procopen(av[0], av, NiL, ov, PROC_PRIVELEGED|PROC_ZOMBIE)) { n = 1; for (;;) { if (!lstat(state->mount, &st) && st.st_ctime != otime) { if (!procclose(proc)) { sfclose(sp); return 0; } break; } /* * sleep() and MNT_TMP * hack around remote * fs cache delays */ if (n >= CS_REMOTE_DELAY) { procclose(proc); break; } if (n == 1) { *state->control = CS_MNT_TMP; if (remove(state->mount)) { close(open(state->mount, O_WRONLY|O_CREAT|O_TRUNC, 0)); remove(state->mount); } *state->control = CS_MNT_STREAM; } sleep(n); n <<= 1; } } } else if (!sfstacked(sp) && (np = csinfo(state, on, NiL))) sfstack(sp, np); } sfclose(sp); return -1; }
char* pathprobe_20100601(const char* lang, const char* tool, const char* aproc, int op, char* path, size_t pathsize, char* attr, size_t attrsize) { char* proc = (char*)aproc; register char* p; register char* k; register char* x; register char** ap; int n; int v; int force; ssize_t r; char* e; char* np; char* nx; char* probe; const char* dirs; const char* dir; Proc_t* pp; Sfio_t* sp; char buf[PATH_MAX]; char cmd[PATH_MAX]; char exe[PATH_MAX]; char lib[PATH_MAX]; char ver[PATH_MAX]; char key[16]; char* arg[8]; long ops[2]; unsigned long ptime; struct stat st; struct stat ps; if (*proc != '/') { if (p = strchr(proc, ' ')) { strncopy(buf, proc, p - proc + 1); proc = buf; } if (!(proc = pathpath(proc, NiL, PATH_ABSOLUTE|PATH_REGULAR|PATH_EXECUTE, cmd, sizeof(cmd)))) proc = (char*)aproc; else if (p) { n = strlen(proc); strncopy(proc + n, p, PATH_MAX - n - 1); } } if (!path) { path = buf; pathsize = sizeof(buf); } probe = PROBE; x = lib + sizeof(lib) - 1; k = lib + sfsprintf(lib, x - lib, "lib/%s/", probe); p = k + sfsprintf(k, x - k, "%s/%s/", lang, tool); pathkey(lang, tool, proc, key, sizeof(key), attr, attrsize); if (op >= -2) { strncopy(p, key, x - p); if (pathpath(lib, "", PATH_ABSOLUTE, path, pathsize) && !stat(path, &st) && (st.st_mode & S_IWUSR)) return path == buf ? strdup(path) : path; } e = strncopy(p, probe, x - p); if (!pathpath(lib, "", PATH_ABSOLUTE|PATH_EXECUTE, path, pathsize) || stat(path, &ps)) return 0; for (;;) { ptime = ps.st_mtime; n = strlen(path); if (n < (PATH_MAX - 5)) { strcpy(path + n, ".ini"); if (!stat(path, &st) && st.st_size && ptime < (unsigned long)st.st_mtime) ptime = st.st_mtime; path[n] = 0; } np = path + n - (e - k); nx = path + PATH_MAX - 1; strncopy(np, probe, nx - np); if (!stat(path, &st)) break; /* * yes lib/probe/<lang>/<proc>/probe * no lib/probe/probe * * do a manual pathaccess() to find a dir with both */ sfsprintf(exe, sizeof(exe), "lib/%s/%s", probe, probe); dirs = pathbin(); for (;;) { if (!(dir = dirs)) return 0; dirs = pathcat(dir, ':', "..", exe, path, pathsize); pathcanon(path, pathsize, 0); if (*path == '/' && pathexists(path, PATH_REGULAR|PATH_EXECUTE)) { pathcat(dir, ':', "..", lib, path, pathsize); pathcanon(path, pathsize, 0); if (*path == '/' && pathexists(path, PATH_REGULAR|PATH_EXECUTE) && !stat(path, &ps)) break; } } } strncopy(p, key, x - p); p = np; x = nx; strcpy(exe, path); if (op >= -1 && (!(st.st_mode & S_ISUID) && ps.st_uid != geteuid() || rofs(path))) { if (!(p = getenv("HOME"))) return 0; p = path + sfsprintf(path, PATH_MAX - 1, "%s/.%s/%s/", p, probe, HOSTTYPE); } strncopy(p, k, x - p); force = 0; if (op >= 0 && !stat(path, &st)) { if (ptime <= (unsigned long)st.st_mtime || ptime <= (unsigned long)st.st_ctime) { /* * verify (<sep><name><sep><option><sep><value>)* header */ if (sp = sfopen(NiL, path, "r")) { if (x = sfgetr(sp, '\n', 1)) { while (*x && *x != ' ') x++; while (*x == ' ') x++; if (n = *x++) for (;;) { for (k = x; *x && *x != n; x++); if (!*x) break; *x++ = 0; for (p = x; *x && *x != n; x++); if (!*x) break; *x++ = 0; for (e = x; *x && *x != n; x++); if (!*x) break; *x++ = 0; if (streq(k, "VERSION")) { ap = arg; *ap++ = proc; *ap++ = p; *ap = 0; ops[0] = PROC_FD_DUP(1, 2, 0); ops[1] = 0; if (pp = procopen(proc, arg, NiL, ops, PROC_READ)) { if ((v = x - e) >= sizeof(ver)) v = sizeof(ver) - 1; for (k = p = ver;; k++) { if (k >= p) { if (v <= 0 || (r = read(pp->rfd, k, v)) <= 0) break; v -= r; p = k + r; } if (*k == '\n' || *k == '\r') break; if (*k == n) *k = ' '; } *k = 0; if (strcmp(ver, e)) { force = 1; error(0, "probe processor %s version \"%s\" changed -- expected \"%s\"", proc, ver, e); } procclose(pp); } break; } } } sfclose(sp); } if (!force) op = -1; } if (op >= 0 && (st.st_mode & S_IWUSR)) { if (op == 0) error(0, "%s probe information for %s language processor %s must be manually regenerated", tool, lang, proc); op = -1; force = 0; } } if (op >= 0) { ap = arg; *ap++ = exe; if (force) *ap++ = "-f"; if (op > 0) *ap++ = "-s"; *ap++ = (char*)lang; *ap++ = (char*)tool; *ap++ = proc; *ap = 0; if (procrun(exe, arg, 0)) return 0; if (eaccess(path, R_OK)) return 0; } return path == buf ? strdup(path) : path; }