+++ /dev/null
-/**
- * \file lib/fileutil.c
- */
-
-#include "system.h"
-#include <rpmlib.h>
-#include "misc.h"
-#include "debug.h"
-
-static struct {
- const char *token;
- int nargs;
-} cmds[] = {
- { "mkdir", 1 },
-#define RPMSYSCALL_MKDIR 0
- { "rmdir", 1 },
-#define RPMSYSCALL_RMDIR 1
- { "mv", -2 },
-#define RPMSYSCALL_MV 2
- { "symlink", 2 },
-#define RPMSYSCALL_SYMLINK 3
- { "S_ISLNK", 1 }
-#define RPMSYSCALL_ISLNK 4
-};
-int ncmds = sizeof(cmds)/sizeof(cmds[0]);
-
-int rpmSyscall(const char * cmd, int noexec)
-{
- const char ** argv = NULL;
- int argc;
- struct stat st;
- int i, j;
- int rc;
-
- rc = (noexec)
- ? poptParseArgvString(cmd, &argc, &argv)
- : rpmGlob(cmd, &argc, &argv);
-
- if (rc)
- goto exit;
-
- /* Check: argv[0] must be known. */
- for (i = 0; i < ncmds; i++) {
- if (!strcmp(cmds[i].token, argv[0]))
- break;
- }
- if (i >= ncmds) {
- rc = EPERM;
- goto exit;
- }
-
- /* Check: must have exactly (or, if negative, at least) nargs. */
- if (cmds[i].nargs >= 0 && argc != (cmds[i].nargs+1)) {
- rc = EPERM;
- goto exit;
- } else if (argc < (1-cmds[i].nargs)) {
- rc = EPERM;
- goto exit;
- }
-
- /* Check: all args (except for 1st arg to symlink) must start with '/'. */
- for (j = (i == RPMSYSCALL_SYMLINK ? 2 : 1); j < argc; j++) {
- if (argv[j][0] != '/') {
- rc = EPERM;
- goto exit;
- }
- }
-
- /* Check: parse only with 2 or more args, last arg cannot be glob. */
- if (noexec) {
- if (argc > 2 && Glob_pattern_p(argv[argc-1], 0)) {
- rc = 1;
- goto exit;
- }
- rc = 0;
- goto exit;
- }
-
- /* Execute only checks below */
-
- switch (i) {
- case RPMSYSCALL_MKDIR: /* mkdir */
- { mode_t mode = 0755;
- rc = mkdir(argv[1], mode);
- if (rc < 0) rc = errno;
- if (stat(argv[1], &st) < 0) {
- if (rc == 0) rc = errno;
- goto exit;
- }
- if (!S_ISDIR(st.st_mode)) {
- if (rc == 0) rc = ENOTDIR;
- goto exit;
- }
- rc = 0;
- } break;
- case RPMSYSCALL_RMDIR: /* rmdir */
- rc = rmdir(argv[1]);
- if (rc < 0) rc = errno;
- break;
- case RPMSYSCALL_MV: /* mv */
- { dev_t dev;
- const char * fn, * bn;
- char * t;
- size_t bnlen;
-
- /* Check: if more than 2 args ... */
- if (argc > 3) {
- /* ... last arg must be existing directory ... */
- if (stat(argv[argc-1], &st) < 0) {
- if (rc == 0) rc = errno;
- goto exit;
- }
- if (!S_ISDIR(st.st_mode)) {
- if (rc == 0) rc = ENOTDIR;
- goto exit;
- }
- /* ... and other args must all be on the same device. */
- dev = st.st_dev;
- bnlen = 0;
- for (j = 1; j < (argc-1); j++) {
- if (stat(argv[j], &st) < 0) {
- if (rc == 0) rc = errno;
- goto exit;
- }
- if (dev != st.st_dev) {
- if (rc == 0) rc = EXDEV;
- goto exit;
- }
- bn = strrchr(argv[j], '/');
- if (bn) {
- int k = strlen(bn);
- if (k > bnlen) bnlen = k;
- }
- }
- /* Everything looks OK, so do the renames. */
- fn = t = alloca(strlen(argv[argc-1])+2+bnlen);
- t = stpcpy(t, argv[argc-1]);
- if (t[-1] != '/') *t++ = '/';
- for (j = 1; j < (argc-1); j++) {
- bn = strrchr(argv[j], '/');
- (void) stpcpy(t, bn+1);
- rc = rename(argv[j], fn);
- if (rc < 0) {
- rc = errno;
- goto exit;
- }
- }
- } else { /* Otherwise exactly 2 args. */
- rc = rename(argv[1], argv[2]);
- if (rc < 0) rc = errno;
- }
- } break;
- case RPMSYSCALL_SYMLINK: /* symlink */
- rc = symlink(argv[1], argv[2]);
- if (rc < 0) rc = errno;
- break;
- case RPMSYSCALL_ISLNK: /* stat(2) with S_ISLNK */
- if (stat(argv[1], &st) < 0) {
- if (rc == 0) rc = errno;
- goto exit;
- }
- if (S_ISLNK(st.st_mode)) {
- if (rc == 0) rc = EPERM;
- goto exit;
- }
- rc = 0;
- break;
- default:
- rc = EPERM;
- break;
- }
-
-exit:
- argv = _free(argv);
- return rc;
-}