static int rm(State_t* state, register FTSENT* ent) { register char* path; register int n; int v; struct stat st; if (ent->fts_info == FTS_NS || ent->fts_info == FTS_ERR || ent->fts_info == FTS_SLNONE) { if (!state->force) error(2, "%s: not found", ent->fts_path); } else if (state->fs3d && iview(ent->fts_statp)) fts_set(NiL, ent, FTS_SKIP); else switch (ent->fts_info) { case FTS_DNR: case FTS_DNX: if (state->unconditional) { if (!beenhere(ent)) break; if (!chmod(ent->fts_name, (ent->fts_statp->st_mode & S_IPERM)|S_IRWXU)) { fts_set(NiL, ent, FTS_AGAIN); break; } error_info.errors++; } else if (!state->force) error(2, "%s: cannot %s directory", ent->fts_path, (ent->fts_info & FTS_NR) ? "read" : "search"); else error_info.errors++; fts_set(NiL, ent, FTS_SKIP); nonempty(ent); break; case FTS_D: case FTS_DC: path = ent->fts_name; if (path[0] == '.' && (!path[1] || path[1] == '.' && !path[2]) && (ent->fts_level > 0 || path[1])) { fts_set(NiL, ent, FTS_SKIP); if (!state->force) error(2, "%s: cannot remove", ent->fts_path); else error_info.errors++; break; } if (!state->recursive) { fts_set(NiL, ent, FTS_SKIP); error(2, "%s: directory", ent->fts_path); break; } if (!beenhere(ent)) { if (state->unconditional && (ent->fts_statp->st_mode & S_IRWXU) != S_IRWXU) chmod(path, (ent->fts_statp->st_mode & S_IPERM)|S_IRWXU); if (ent->fts_level > 0) { char* s; if (ent->fts_accpath == ent->fts_name || !(s = strrchr(ent->fts_accpath, '/'))) v = !stat(".", &st); else { path = ent->fts_accpath; *s = 0; v = !stat(path, &st); *s = '/'; } if (v) v = st.st_nlink <= 2 || st.st_ino == ent->fts_parent->fts_statp->st_ino && st.st_dev == ent->fts_parent->fts_statp->st_dev || strchr(astconf("PATH_ATTRIBUTES", path, NiL), 'l'); } else v = 1; if (v) { if (state->interactive) { if ((v = astquery(-1, "remove directory %s? ", ent->fts_path)) < 0 || sh_checksig(state->context)) return -1; if (v > 0) { fts_set(NiL, ent, FTS_SKIP); nonempty(ent); } } if (ent->fts_info == FTS_D) break; } else { ent->fts_info = FTS_DC; error(1, "%s: hard link to directory", ent->fts_path); } } else if (ent->fts_info == FTS_D) break; /*FALLTHROUGH*/ case FTS_DP: if (isempty(ent) || state->directory) { path = ent->fts_name; if (path[0] != '.' || path[1]) { path = ent->fts_accpath; if (state->verbose) sfputr(sfstdout, ent->fts_path, '\n'); if ((ent->fts_info == FTS_DC || state->directory) ? remove(path) : rmdir(path)) switch (errno) { case ENOENT: break; case EEXIST: #if defined(ENOTEMPTY) && (ENOTEMPTY) != (EEXIST) case ENOTEMPTY: #endif if (ent->fts_info == FTS_DP && !beenhere(ent)) { retry(ent); fts_set(NiL, ent, FTS_AGAIN); break; } /*FALLTHROUGH*/ default: nonempty(ent); if (!state->force) error(ERROR_SYSTEM|2, "%s: directory not removed", ent->fts_path); else error_info.errors++; break; } } else if (!state->force) error(2, "%s: cannot remove", ent->fts_path); else error_info.errors++; } else { nonempty(ent); if (!state->force) error(2, "%s: directory not removed", ent->fts_path); else error_info.errors++; } break; default: path = ent->fts_accpath; if (state->verbose) sfputr(sfstdout, ent->fts_path, '\n'); if (state->interactive) { if ((v = astquery(-1, "remove %s? ", ent->fts_path)) < 0 || sh_checksig(state->context)) return -1; if (v > 0) { nonempty(ent); break; } } else if (!state->force && state->terminal && eaccess(path, W_OK)) { if ((v = astquery(-1, "override protection %s for %s? ", #ifdef ETXTBSY errno == ETXTBSY ? "``running program''" : #endif ent->fts_statp->st_uid != state->uid ? "``not owner''" : fmtmode(ent->fts_statp->st_mode & S_IPERM, 0) + 1, ent->fts_path)) < 0 || sh_checksig(state->context)) return -1; if (v > 0) { nonempty(ent); break; } } #if _lib_fsync if (state->clobber && S_ISREG(ent->fts_statp->st_mode) && ent->fts_statp->st_size > 0) { if ((n = open(path, O_WRONLY)) < 0) error(ERROR_SYSTEM|2, "%s: cannot clear data", ent->fts_path); else { off_t c = ent->fts_statp->st_size; for (;;) { if (write(n, state->buf, sizeof(state->buf)) != sizeof(state->buf)) { error(ERROR_SYSTEM|2, "%s: data clear error", ent->fts_path); break; } if (c <= sizeof(state->buf)) break; c -= sizeof(state->buf); } fsync(n); close(n); } } #endif if (remove(path)) { nonempty(ent); switch (errno) { case ENOENT: break; default: if (!state->force || state->interactive) error(ERROR_SYSTEM|2, "%s: not removed", ent->fts_path); else error_info.errors++; break; } } break; } return 0; }
int b_rm(int argc, register char** argv, void* context) { State_t state; FTS* fts; FTSENT* ent; int set3d; cmdinit(argc, argv, context, ERROR_CATALOG, ERROR_NOTIFY); memset(&state, 0, sizeof(state)); state.context = context; state.fs3d = fs3d(FS3D_TEST); state.terminal = isatty(0); for (;;) { switch (optget(argv, usage)) { case 'd': state.directory = 1; continue; case 'f': state.force = 1; state.interactive = 0; continue; case 'i': state.interactive = 1; state.force = 0; continue; case 'r': case 'R': state.recursive = 1; continue; case 'F': #if _lib_fsync state.clobber = 1; #else error(1, "%s not implemented on this system", opt_info.name); #endif continue; case 'u': state.unconditional = 1; continue; case 'v': state.verbose = 1; continue; case '?': error(ERROR_USAGE|4, "%s", opt_info.arg); break; case ':': error(2, "%s", opt_info.arg); break; } break; } argv += opt_info.index; if (*argv && streq(*argv, "-") && !streq(*(argv - 1), "--")) argv++; if (error_info.errors || !*argv) error(ERROR_USAGE|4, "%s", optusage(NiL)); /* * do it */ if (state.interactive) state.verbose = 0; state.uid = geteuid(); state.unconditional = state.unconditional && state.recursive && state.force; if (state.recursive && state.fs3d) { set3d = state.fs3d; state.fs3d = 0; fs3d(0); } else set3d = 0; if (fts = fts_open(argv, FTS_PHYSICAL, NiL)) { while (!sh_checksig(context) && (ent = fts_read(fts)) && !rm(&state, ent)); fts_close(fts); } else if (!state.force) error(ERROR_SYSTEM|2, "%s: cannot remove", argv[0]); if (set3d) fs3d(set3d); return error_info.errors != 0; }
int b_mktemp(int argc, char** argv, Shbltin_t* context) { mode_t mode = 0; mode_t mask; int fd; int i; int quiet = 0; int unsafe = 0; int* fdp = &fd; char* dir = ""; char* pfx; char* t; char path[PATH_MAX]; cmdinit(argc, argv, context, ERROR_CATALOG, ERROR_NOTIFY); for (;;) { switch (optget(argv, usage)) { case 'd': fdp = 0; continue; case 'm': mode = strperm(pfx = opt_info.arg, &opt_info.arg, S_IRWXU); if (*opt_info.arg) error(ERROR_exit(0), "%s: invalid mode", pfx); continue; case 'p': if ((t = getenv("TMPDIR")) && *t) dir = 0; else dir = opt_info.arg; continue; case 'q': quiet = 1; continue; case 't': dir = 0; continue; case 'u': unsafe = 1; fdp = 0; continue; case 'R': if (!pathtemp(NiL, 0, opt_info.arg, "/seed", NiL)) error(2, "%s: regression test initializtion failed", opt_info.arg); continue; case ':': error(2, "%s", opt_info.arg); break; case '?': error(ERROR_usage(2), "%s", opt_info.arg); break; } break; } argv += opt_info.index; if (error_info.errors || (pfx = *argv++) && *argv) error(ERROR_usage(2), "%s", optusage(NiL)); mask = umask(0); if (!mode) mode = (fdp ? (S_IRUSR|S_IWUSR) : S_IRWXU) & ~mask; umask(~mode & (S_IRWXU|S_IRWXG|S_IRWXO)); if (!pfx) { pfx = "tmp_"; if (dir && !*dir) dir = 0; } if (t = strrchr(pfx, '/')) { i = ++t - pfx; dir = fmtbuf(i); memcpy(dir, pfx, i); dir[i] = 0; pfx = t; } for (;;) { if (!pathtemp(path, sizeof(path), dir, pfx, fdp)) { if (quiet) error_info.errors++; else error(ERROR_SYSTEM|2, "cannot create temporary path"); break; } if (fdp || unsafe || !mkdir(path, mode)) { if (fdp) close(*fdp); sfputr(sfstdout, path, '\n'); break; } if (sh_checksig(context)) { error_info.errors++; break; } } umask(mask); return error_info.errors != 0; }