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; }
static Extype_t eval(Expr_t* ex, register Exnode_t* expr, void* env) { register Exnode_t* x; register Exnode_t* a; register Extype_t** t; register int n; Extype_t v; Extype_t r; Extype_t i; char* e; Exnode_t tmp; Exassoc_t* assoc; Extype_t args[FRAME+1]; Extype_t save[FRAME]; if (!expr || ex->loopcount) { v.integer = 1; return v; } x = expr->data.operand.left; switch (expr->op) { case BREAK: case CONTINUE: v = eval(ex, x, env); ex->loopcount = v.integer; ex->loopop = expr->op; return v; case CONSTANT: return expr->data.constant.value; case DEC: n = -1; add: if (x->op == DYNAMIC) r = getdyn(ex, x, env, &assoc); else { if (x->data.variable.index) i = eval(ex, x->data.variable.index, env); else i.integer = EX_SCALAR; r = (*ex->disc->getf)(ex, x, x->data.variable.symbol, x->data.variable.reference, env, (int)i.integer, ex->disc); } v = r; switch (x->type) { case FLOATING: v.floating += n; break; case INTEGER: case UNSIGNED: v.integer += n; break; default: goto huh; } set: if (x->op == DYNAMIC) { if (x->type == STRING) { v.string = vmstrdup(ex->vm, v.string); if (e = assoc ? assoc->value.string : x->data.variable.symbol->value->data.constant.value.string) vmfree(ex->vm, e); } if (assoc) assoc->value = v; else x->data.variable.symbol->value->data.constant.value = v; } else { if (x->data.variable.index) i = eval(ex, x->data.variable.index, env); else i.integer = EX_SCALAR; if ((*ex->disc->setf)(ex, x, x->data.variable.symbol, x->data.variable.reference, env, (int)i.integer, v, ex->disc) < 0) exerror("%s: cannot set value", x->data.variable.symbol->name); } if (expr->subop == PRE) r = v; return r; case DYNAMIC: return getdyn(ex, expr, env, &assoc); case EXIT: v = eval(ex, x, env); exit((int)v.integer); /*NOTREACHED*/ v.integer = -1; return v; case IF: v = eval(ex, x, env); if (v.integer) eval(ex, expr->data.operand.right->data.operand.left, env); else eval(ex, expr->data.operand.right->data.operand.right, env); v.integer = 1; return v; case FOR: case WHILE: expr = expr->data.operand.right; for (;;) { r = eval(ex, x, env); if (!r.integer) { v.integer = 1; return v; } if (expr->data.operand.right) { eval(ex, expr->data.operand.right, env); if (ex->loopcount > 0 && (--ex->loopcount > 0 || ex->loopop != CONTINUE)) { v.integer = 0; return v; } } if (expr->data.operand.left) eval(ex, expr->data.operand.left, env); } /*NOTREACHED*/ case SWITCH: v = eval(ex, x, env); i.integer = x->type; r.integer = 0; x = expr->data.operand.right; a = x->data.select.statement; n = 0; while (x = x->data.select.next) { if (!(t = x->data.select.constant)) n = 1; else for (; *t; t++) { switch ((int)i.integer) { case INTEGER: case UNSIGNED: if ((*t)->integer == v.integer) break; continue; case STRING: if ((ex->disc->version >= 19981111L && ex->disc->matchf) ? (*ex->disc->matchf)(ex, x, (*t)->string, expr->data.operand.left, v.string, env, ex->disc) : strmatch((*t)->string, v.string)) break; continue; case FLOATING: if ((*t)->floating == v.floating) break; continue; } n = 1; break; } if (n) { if (!x->data.select.statement) { r.integer = 1; break; } r = eval(ex, x->data.select.statement, env); if (ex->loopcount > 0) { ex->loopcount--; break; } } } if (!n && a) { r = eval(ex, a, env); if (ex->loopcount > 0) ex->loopcount--; } return r; case ITERATE: v.integer = 0; if (expr->data.generate.array->op == DYNAMIC) { n = expr->data.generate.index->type == STRING; for (assoc = (Exassoc_t*)dtfirst((Dt_t*)expr->data.generate.array->data.variable.symbol->local.pointer); assoc; assoc = (Exassoc_t*)dtnext((Dt_t*)expr->data.generate.array->data.variable.symbol->local.pointer, assoc)) { v.integer++; if (n) expr->data.generate.index->value->data.constant.value.string = assoc->name; else expr->data.generate.index->value->data.constant.value.integer = strtol(assoc->name, NiL, 0); eval(ex, expr->data.generate.statement, env); if (ex->loopcount > 0 && (--ex->loopcount > 0 || ex->loopop != CONTINUE)) { v.integer = 0; break; } } } else { r = (*ex->disc->getf)(ex, expr, expr->data.generate.array->data.variable.symbol, expr->data.generate.array->data.variable.reference, env, 0, ex->disc); for (v.integer = 0; v.integer < r.integer; v.integer++) { expr->data.generate.index->value->data.constant.value.integer = v.integer; eval(ex, expr->data.generate.statement, env); if (ex->loopcount > 0 && (--ex->loopcount > 0 || ex->loopop != CONTINUE)) { v.integer = 0; break; } } } return v; case CALL: x = expr->data.call.args; for (n = 0, a = expr->data.call.procedure->value->data.procedure.args; a && x; a = a->data.operand.right) { if (n < elementsof(args)) { save[n] = a->data.operand.left->data.variable.symbol->value->data.constant.value; args[n++] = eval(ex, x->data.operand.left, env); } else a->data.operand.left->data.variable.symbol->value->data.constant.value = eval(ex, x->data.operand.left, env); x = x->data.operand.right; } for (n = 0, a = expr->data.call.procedure->value->data.procedure.args; a && n < elementsof(save); a = a->data.operand.right) a->data.operand.left->data.variable.symbol->value->data.constant.value = args[n++]; if (x) exerror("too many actual args"); else if (a) exerror("not enough actual args"); v = exeval(ex, expr->data.call.procedure->value->data.procedure.body, env); for (n = 0, a = expr->data.call.procedure->value->data.procedure.args; a && n < elementsof(save); a = a->data.operand.right) a->data.operand.left->data.variable.symbol->value->data.constant.value = save[n++]; return v; case FUNCTION: n = 0; args[n++].string = (char*)env; for (x = expr->data.operand.right; x && n < elementsof(args); x = x->data.operand.right) args[n++] = eval(ex, x->data.operand.left, env); return (*ex->disc->getf)(ex, expr->data.operand.left, expr->data.operand.left->data.variable.symbol, expr->data.operand.left->data.variable.reference, args+1, EX_CALL, ex->disc); case ID: if (expr->data.variable.index) i = eval(ex, expr->data.variable.index, env); else i.integer = EX_SCALAR; return (*ex->disc->getf)(ex, expr, expr->data.variable.symbol, expr->data.variable.reference, env, (int)i.integer, ex->disc); case INC: n = 1; goto add; case PRINTF: v.integer = print(ex, expr, env, NiL); return v; case QUERY: print(ex, expr, env, sfstderr); v.integer = !astquery(2, ""); return v; case RETURN: ex->loopret = eval(ex, x, env); ex->loopcount = 32767; ex->loopop = expr->op; return ex->loopret; case SCANF: case SSCANF: v.integer = scan(ex, expr, env, NiL); return v; case SPRINTF: print(ex, expr, env, ex->tmp); v.string = exstash(ex->tmp, ex->ve); return v; case '=': v = eval(ex, expr->data.operand.right, env); if (expr->subop != '=') { r = v; if (x->op == DYNAMIC) v = getdyn(ex, x, env, &assoc); else { if (x->data.variable.index) v = eval(ex, x->data.variable.index, env); else v.integer = EX_SCALAR; v = (*ex->disc->getf)(ex, x, x->data.variable.symbol, x->data.variable.reference, env, (int)v.integer, ex->disc); } switch (x->type) { case FLOATING: switch (expr->subop) { case '+': v.floating += r.floating; break; case '-': v.floating -= r.floating; break; case '*': v.floating *= r.floating; break; case '/': if (r.floating == 0.0) exerror("floating divide by 0"); else v.floating /= r.floating; break; case '%': if ((r.integer = r.floating) == 0) exerror("floating 0 modulus"); else v.floating = ((Sflong_t)v.floating) % r.integer; break; case '&': v.floating = ((Sflong_t)v.floating) & ((Sflong_t)r.floating); break; case '|': v.floating = ((Sflong_t)v.floating) | ((Sflong_t)r.floating); break; case '^': v.floating = ((Sflong_t)v.floating) ^ ((Sflong_t)r.floating); break; case LS: v.floating = ((Sflong_t)v.floating) << ((Sflong_t)r.floating); break; case RS: #if _WIN32 v.floating = (Sflong_t)(((Sfulong_t)v.floating) >> ((Sflong_t)r.floating)); #else v.floating = ((Sfulong_t)v.floating) >> ((Sflong_t)r.floating); #endif break; default: goto huh; } break; case INTEGER: case UNSIGNED: switch (expr->subop) { case '+': v.integer += r.integer; break; case '-': v.integer -= r.integer; break; case '*': v.integer *= r.integer; break; case '/': if (r.integer == 0) exerror("integer divide by 0"); else v.integer /= r.integer; break; case '%': if (r.integer == 0) exerror("integer 0 modulus"); else v.integer %= r.integer; break; case '&': v.integer &= r.integer; break; case '|': v.integer |= r.integer; break; case '^': v.integer ^= r.integer; break; case LS: v.integer <<= r.integer; break; case RS: v.integer = (Sfulong_t)v.integer >> r.integer; break; default: goto huh; } break; case STRING: switch (expr->subop) { case '+': v.string = str_add(ex, v.string, r.string); break; case '|': v.string = str_ior(ex, v.string, r.string); break; case '&': v.string = str_and(ex, v.string, r.string); break; case '^': v.string = str_xor(ex, v.string, r.string); break; case '%': v.string = str_mod(ex, v.string, r.string); break; case '*': v.string = str_mpy(ex, v.string, r.string); break; default: goto huh; } break; default: goto huh; } } else if (x->op == DYNAMIC)