/* properties_on_apply */ static void _properties_on_apply(gpointer data) { Properties * properties = data; char * p; struct group * gr; gid_t gid = properties->gid; size_t i; mode_t mode = 0; #if GTK_CHECK_VERSION(2, 24, 0) p = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT( properties->group)); #else p = gtk_combo_box_get_active_text(GTK_COMBO_BOX(properties->group)); #endif if((gr = getgrnam(p)) == NULL) _properties_error(properties, p, 1); else gid = gr->gr_gid; for(i = 0; i < 9; i++) mode |= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( properties->mode[i])) << i; if(lchown(properties->filename, properties->uid, gid) != 0 || lchmod(properties->filename, mode) != 0) _properties_error(properties, properties->filename, 1); }
/* * set attributes to what is specified. XXX: no rollback in case of failure */ static int processvattr(const char *path, const struct vattr *va, int regular) { struct timeval tv[2]; /* XXX: -1 == PUFFS_VNOVAL, but shouldn't trust that */ if (va->va_uid != (unsigned)-1 || va->va_gid != (unsigned)-1) if (lchown(path, va->va_uid, va->va_gid) == -1) return errno; if (va->va_mode != (u_short)PUFFS_VNOVAL) if (lchmod(path, va->va_mode) == -1) return errno; /* sloppy */ if (va->va_atime.tv_sec != (time_t)PUFFS_VNOVAL || va->va_mtime.tv_sec != (time_t)PUFFS_VNOVAL) { TIMESPEC_TO_TIMEVAL(&tv[0], &va->va_atime); TIMESPEC_TO_TIMEVAL(&tv[1], &va->va_mtime); if (lutimes(path, tv) == -1) return errno; } if (regular && va->va_size != (u_quad_t)PUFFS_VNOVAL) if (truncate(path, (off_t)va->va_size) == -1) return errno; return 0; }
static void dosetattr(const char *filename, int fd, struct jattr *jattr) { if (fd >= 0) { if (jattr->uid != (uid_t)-1 && jattr->gid != (gid_t)-1) fchown(fd, jattr->uid, jattr->gid); else if (jattr->uid != (uid_t)-1) fchown(fd, jattr->uid, -1); else if (jattr->gid != (gid_t)-1) fchown(fd, -1, jattr->gid); if (jattr->modes != (mode_t)-1) fchmod(fd, jattr->modes); if (jattr->fflags != -1) fchflags(fd, jattr->fflags); if (jattr->size != -1) ftruncate(fd, jattr->size); } else { if (jattr->uid != (uid_t)-1 && jattr->gid != (gid_t)-1) lchown(filename, jattr->uid, jattr->gid); else if (jattr->uid != (uid_t)-1) lchown(filename, jattr->uid, -1); else if (jattr->gid != (gid_t)-1) lchown(filename, -1, jattr->gid); if (jattr->modes != (mode_t)-1) lchmod(filename, jattr->modes); if (jattr->fflags != -1) chflags(filename, jattr->fflags); if (jattr->size != -1) truncate(filename, jattr->size); } }
int do_chmod(const char *path, mode_t mode) { int code; if (dry_run) return 0; RETURN_ERROR_IF_RO_OR_LO; #ifdef HAVE_LCHMOD code = lchmod(path, mode & CHMOD_BITS); #else if (S_ISLNK(mode)) { # if defined HAVE_SETATTRLIST struct attrlist attrList; uint32_t m = mode & CHMOD_BITS; /* manpage is wrong: not mode_t! */ memset(&attrList, 0, sizeof attrList); attrList.bitmapcount = ATTR_BIT_MAP_COUNT; attrList.commonattr = ATTR_CMN_ACCESSMASK; code = setattrlist(path, &attrList, &m, sizeof m, FSOPT_NOFOLLOW); # else code = 1; # endif } else code = chmod(path, mode & CHMOD_BITS); /* DISCOURAGED FUNCTION */ #endif /* !HAVE_LCHMOD */ if (code != 0 && (preserve_perms || preserve_executability)) return code; return 0; }
/* * Function: setfile * * Purpose: * Set the owner/group/permissions for the "to" file to the information * in the stat structure. If fd is zero, also call set_utimes() to set * the mod/access times. If fd is non-zero, the caller must do a utimes * itself after close(fd). */ int setfile(struct stat *fs, int fd) { int rval; #if HAVE_MEMBER_STRUCT_STAT_ST_FLAGS_SYS_STAT_H int islink; #endif rval = 0; #if HAVE_MEMBER_STRUCT_STAT_ST_FLAGS_SYS_STAT_H islink = S_ISLNK(fs->st_mode); #endif fs->st_mode &= S_ISUID | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO; /* * Changing the ownership probably won't succeed, unless we're root * or POSIX_CHOWN_RESTRICTED is not set. Set uid/gid before setting * the mode; current BSD behavior is to remove all setuid bits on * chown. If chown fails, lose setuid/setgid bits. */ if (fd ? fchown(fd, fs->st_uid, fs->st_gid) : lchown(to.p_path, fs->st_uid, fs->st_gid)) { if (errno != EPERM) { warn("chown: %s", to.p_path); rval = 1; } fs->st_mode &= ~(S_ISUID | S_ISGID); } if (fd ? fchmod(fd, fs->st_mode) : lchmod(to.p_path, fs->st_mode)) { warn("chmod: %s", to.p_path); rval = 1; } #if HAVE_MEMBER_STRUCT_STAT_ST_FLAGS_SYS_STAT_H if (!islink && !Nflag) { unsigned long fflags = fs->st_flags; /* * XXX * NFS doesn't support chflags; ignore errors unless * there's reason to believe we're losing bits. * (Note, this still won't be right if the server * supports flags and we were trying to *remove* flags * on a file that we copied, i.e., that we didn't create.) */ errno = 0; if ((fd ? fchflags(fd, fflags) : chflags(to.p_path, fflags)) == -1) if (errno != EOPNOTSUPP || fs->st_flags != 0) { warn("chflags: %s", to.p_path); rval = 1; } } #endif /* HAVE_MEMBER_STRUCT_STAT_ST_FLAGS_SYS_STAT_H */ /* if fd is non-zero, caller must call set_utimes() after close() */ if (fd == 0 && set_utimes(to.p_path, fs)) rval = 1; return (rval); }
void setup() { create_file("file", "abcdef", 0777); symlink("file", "file-link"); // some platforms use 777, some use 755 by default for symlinks // make sure we're using 777 for the test lchmod("file-link", 0777); mkdir("folder", 0777); }
void set_pmode(char *fnm, mode_t mode) { mode &= ABITS; if (lchmod(fnm, mode) < 0) syswarn(1, errno, "Could not set permissions on %s", fnm); return; }
void set_pmode(char *fnm, mode_t mode) { mode &= A_BITS; if (lchmod(fnm, mode)) { (void)fflush(listf); syswarn(1, errno, "Cannot set permissions on %s", fnm); } return; }
static int _single_p(Copy * copy, char const * dst, struct stat const * st) { struct timeval tv[2]; if(lchown(dst, st->st_uid, st->st_gid) != 0) { _copy_filename_error(copy, dst, 0); if(lchmod(dst, st->st_mode & ~(S_ISUID | S_ISGID)) != 0) _copy_filename_error(copy, dst, 0); } else if(lchmod(dst, st->st_mode) != 0) _copy_filename_error(copy, dst, 0); tv[0].tv_sec = st->st_atime; tv[0].tv_usec = 0; tv[1].tv_sec = st->st_mtime; tv[1].tv_usec = 0; if(lutimes(dst, tv) != 0) _copy_filename_error(copy, dst, 0); return 0; }
int do_chmod(const char *path, mode_t mode) { int code; if (dry_run) return 0; RETURN_ERROR_IF_RO_OR_LO; if (S_ISLNK(mode)) { #ifdef HAVE_LCHMOD code = lchmod(path, mode & CHMOD_BITS); #else code = 1; #endif } else code = chmod(path, mode & CHMOD_BITS); if (code != 0 && preserve_perms) return code; return 0; }
/* Work around trailing slash bugs in lchown. */ int rpl_lchown (const char *file, uid_t uid, gid_t gid) { bool stat_valid = false; int result; # if CHOWN_CHANGE_TIME_BUG struct stat st; if (gid != (gid_t) -1 || uid != (uid_t) -1) { if (lstat (file, &st)) return -1; stat_valid = true; if (!S_ISLNK (st.st_mode)) return chown (file, uid, gid); } # endif # if CHOWN_TRAILING_SLASH_BUG if (!stat_valid) { size_t len = strlen (file); if (len && file[len - 1] == '/') return chown (file, uid, gid); } # endif result = lchown (file, uid, gid); # if CHOWN_CHANGE_TIME_BUG && HAVE_LCHMOD if (result == 0 && stat_valid && (uid == st.st_uid || uid == (uid_t) -1) && (gid == st.st_gid || gid == (gid_t) -1)) { /* No change in ownership, but at least one argument was not -1, so we are required to update ctime. Since lchown succeeded, we assume that lchmod will do likewise. But if the system lacks lchmod and lutimes, we are out of luck. Oh well. */ result = lchmod (file, st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO | S_ISUID | S_ISGID | S_ISVTX)); } # endif return result; }
/* * Restore the owner and permissions (mode) of a Directory. * See attribs.c for the equivalent for files. */ static void set_own_mod(ATTR *attr, char *path, uid_t owner, gid_t group, mode_t mode) { if (lchown(path, owner, group) != 0 && attr->uid == 0 #ifdef AFS && errno != EPERM #endif ) { berrno be; Jmsg2(attr->jcr, M_WARNING, 0, _("Cannot change owner and/or group of %s: ERR=%s\n"), path, be.bstrerror()); } if (lchmod(path, mode) != 0 && attr->uid == 0) { berrno be; Jmsg2(attr->jcr, M_WARNING, 0, _("Cannot change permissions of %s: ERR=%s\n"), path, be.bstrerror()); } }
int do_chmod(const char *path, mode_t mode, uint32 fileflags) { int code; if (dry_run) return 0; RETURN_ERROR_IF_RO_OR_LO; #ifdef HAVE_LCHMOD code = lchmod(path, mode & CHMOD_BITS); #else if (S_ISLNK(mode)) { # if defined HAVE_SETATTRLIST struct attrlist attrList; uint32_t m = mode & CHMOD_BITS; /* manpage is wrong: not mode_t! */ memset(&attrList, 0, sizeof attrList); attrList.bitmapcount = ATTR_BIT_MAP_COUNT; attrList.commonattr = ATTR_CMN_ACCESSMASK; code = setattrlist(path, &attrList, &m, sizeof m, FSOPT_NOFOLLOW); # else code = 1; # endif } else code = chmod(path, mode & CHMOD_BITS); /* DISCOURAGED FUNCTION */ #endif /* !HAVE_LCHMOD */ #ifdef SUPPORT_FORCE_CHANGE if (code < 0 && force_change && errno == EPERM && !S_ISLNK(mode)) { if (fileflags == NO_FFLAGS) { STRUCT_STAT st; if (x_lstat(path, &st, NULL) == 0) fileflags = st.st_flags; } if (fileflags != NO_FFLAGS && make_mutable(path, mode, fileflags, force_change) > 0) { code = chmod(path, mode & CHMOD_BITS); undo_make_mutable(path, fileflags); if (code == 0) return 0; } errno = EPERM; } #else fileflags = 0; /* avoid compiler warning */ #endif if (code != 0 && (preserve_perms || preserve_executability)) return code; return 0; }
int setfile(struct stat *fs, int fd) { static struct timeval tv[2]; struct stat ts; int rval, gotstat, islink, fdval; rval = 0; fdval = fd != -1; islink = !fdval && S_ISLNK(fs->st_mode); fs->st_mode &= S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO; TIMESPEC_TO_TIMEVAL(&tv[0], &fs->st_atim); TIMESPEC_TO_TIMEVAL(&tv[1], &fs->st_mtim); if (islink ? lutimes(to.p_path, tv) : utimes(to.p_path, tv)) { warn("%sutimes: %s", islink ? "l" : "", to.p_path); rval = 1; } if (fdval ? fstat(fd, &ts) : (islink ? lstat(to.p_path, &ts) : stat(to.p_path, &ts))) gotstat = 0; else { gotstat = 1; ts.st_mode &= S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO; } if (!gotstat || fs->st_uid != ts.st_uid || fs->st_gid != ts.st_gid) if (fdval ? fchown(fd, fs->st_uid, fs->st_gid) : (islink ? lchown(to.p_path, fs->st_uid, fs->st_gid) : chown(to.p_path, fs->st_uid, fs->st_gid))) { if (errno != EPERM) { warn("chown: %s", to.p_path); rval = 1; } fs->st_mode &= ~(S_ISUID | S_ISGID); } if (!gotstat || fs->st_mode != ts.st_mode) if (fdval ? fchmod(fd, fs->st_mode) : (islink ? lchmod(to.p_path, fs->st_mode) : chmod(to.p_path, fs->st_mode))) { warn("chmod: %s", to.p_path); rval = 1; } if (!gotstat || fs->st_flags != ts.st_flags) if (fdval ? fchflags(fd, fs->st_flags) : (islink ? lchflags(to.p_path, fs->st_flags) : chflags(to.p_path, fs->st_flags))) { warn("chflags: %s", to.p_path); rval = 1; } return (rval); }
/* No support for micro-second file time resolution. Use utime(). */ int copydate(char *pszToFile, char *pszFromFile) { /* Copy the file dates */ /* Note: "struct _stat" and "struct _utimbuf" don't compile under Linux */ struct stat stFrom = {0}; struct utimbuf utbTo = {0}; int err; err = lstat(pszFromFile, &stFrom); /* Copy file permissions too */ err = lchmod(pszToFile, stFrom.st_mode); /* And copy file times */ utbTo.actime = stFrom.st_atime; utbTo.modtime = stFrom.st_mtime; err = lutime(pszToFile, &utbTo); DEBUG_CODE({ struct tm *pTime; char buf[40]; pTime = LocalFileTime(&(utbTo.modtime)); /* Time of last data modification */ sprintf(buf, "%4d-%02d-%02d %02d:%02d:%02d", pTime->tm_year + 1900, pTime->tm_mon + 1, pTime->tm_mday, pTime->tm_hour, pTime->tm_min, pTime->tm_sec); DEBUG_PRINTF(("utime(\"%s\", %s) = %d %s\n", pszToFile, buf, err, err?strerror(errno):"")); });
int extractfile(char *name) { int flags; uid_t uid; gid_t gid; mode_t mode; struct timeval timep[2]; struct entry *ep; curfile.name = name; curfile.action = USING; timep[0].tv_sec = curfile.dip->di_atime; timep[0].tv_usec = curfile.dip->di_atimensec / 1000; timep[1].tv_sec = curfile.dip->di_mtime; timep[1].tv_usec = curfile.dip->di_mtimensec / 1000; uid = curfile.dip->di_uid; gid = curfile.dip->di_gid; mode = curfile.dip->di_mode; flags = curfile.dip->di_flags; switch (mode & IFMT) { default: fprintf(stderr, "%s: unknown file mode 0%o\n", name, mode); skipfile(); return (FAIL); case IFSOCK: vprintf(stdout, "skipped socket %s\n", name); skipfile(); return (GOOD); case IFDIR: if (mflag) { ep = lookupname(name); if (ep == NULL || ep->e_flags & EXTRACT) panic("unextracted directory %s\n", name); skipfile(); return (GOOD); } vprintf(stdout, "extract file %s\n", name); return (genliteraldir(name, curfile.ino)); case IFLNK: lnkbuf[0] = '\0'; pathlen = 0; getfile(xtrlnkfile, xtrlnkskip); if (pathlen == 0) { vprintf(stdout, "%s: zero length symbolic link (ignored)\n", name); return (GOOD); } if (linkit(lnkbuf, name, SYMLINK) == GOOD) { lchown(name, uid, gid); lchmod(name, mode); lutimes(name, timep); return (GOOD); } return (FAIL); case IFIFO: vprintf(stdout, "extract fifo %s\n", name); if (Nflag) { skipfile(); return (GOOD); } if (uflag && !Nflag) unlink(name); if (mkfifo(name, mode) < 0) { fprintf(stderr, "%s: cannot create fifo: %s\n", name, strerror(errno)); skipfile(); return (FAIL); } chown(name, uid, gid); chmod(name, mode); utimes(name, timep); chflags(name, flags); skipfile(); return (GOOD); case IFCHR: case IFBLK: vprintf(stdout, "extract special file %s\n", name); if (Nflag) { skipfile(); return (GOOD); } if (uflag) unlink(name); if (mknod(name, mode, (int)curfile.dip->di_rdev) < 0) { fprintf(stderr, "%s: cannot create special file: %s\n", name, strerror(errno)); skipfile(); return (FAIL); } chown(name, uid, gid); chmod(name, mode); utimes(name, timep); chflags(name, flags); skipfile(); return (GOOD); case IFREG: vprintf(stdout, "extract file %s\n", name); if (Nflag) { skipfile(); return (GOOD); } if (uflag) unlink(name); if ((ofile = open(name, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) { fprintf(stderr, "%s: cannot create file: %s\n", name, strerror(errno)); skipfile(); return (FAIL); } fchown(ofile, uid, gid); fchmod(ofile, mode); getfile(xtrfile, xtrskip); close(ofile); utimes(name, timep); chflags(name, flags); return (GOOD); } /* NOTREACHED */ }
static bool lchmod_fails(void) { ATF_REQUIRE(mkdir("test", 0755) != -1); return lchmod("test", 0700) == -1 && chmod("test", 0700) != -1; }
/* * Function: setfile * * Purpose: * Set the owner/group/permissions for the "to" file to the information * in the stat structure. If fd is zero, also call set_utimes() to set * the mod/access times. If fd is non-zero, the caller must do a utimes * itself after close(fd). */ int setfile(struct stat *fs, int fd) { int rval = 0; #ifdef BSD int islink = S_ISLNK(fs->st_mode); #endif fs->st_mode &= S_ISUID | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO; /* * Changing the ownership probably won't succeed, unless we're root * or POSIX_CHOWN_RESTRICTED is not set. Set uid/gid before setting * the mode; current BSD behavior is to remove all setuid bits on * chown. If chown fails, lose setuid/setgid bits. */ if (fd ? fchown(fd, fs->st_uid, fs->st_gid) : lchown(to.p_path, fs->st_uid, fs->st_gid)) { if (errno != EPERM) { warn("chown: %s", to.p_path); rval = 1; } fs->st_mode &= ~(S_ISUID | S_ISGID); } #ifndef BSD if (fd ? fchmod(fd, fs->st_mode) : chmod(to.p_path, fs->st_mode)) { #else if (fd ? fchmod(fd, fs->st_mode) : lchmod(to.p_path, fs->st_mode)) { #endif warn("chmod: %s", to.p_path); rval = 1; } #ifdef BSD if (!islink && !Nflag) { unsigned long fflags = fs->st_flags; /* * XXX * NFS doesn't support chflags; ignore errors unless * there's reason to believe we're losing bits. * (Note, this still won't be right if the server * supports flags and we were trying to *remove* flags * on a file that we copied, i.e., that we didn't create.) */ errno = 0; if ((fd ? fchflags(fd, fflags) : chflags(to.p_path, fflags)) == -1) if (errno != EOPNOTSUPP || fs->st_flags != 0) { warn("chflags: %s", to.p_path); rval = 1; } } #endif /* if fd is non-zero, caller must call set_utimes() after close() */ if (fd == 0 && set_utimes(to.p_path, fs)) rval = 1; return (rval); } void cp_usage(void) { (void)fprintf(stderr, "usage: cp [-R [-H | -L | -P]] [-f | -i] [-alNpv] src target\n" " cp [-R [-H | -L | -P]] [-f | -i] [-alNpv] src1 ... srcN directory\n"); exit(1); /* NOTREACHED */ }
int main(int argc, char *argv[]) { FTS *ftsp; FTSENT *p; mode_t *set; int Hflag, Lflag, Rflag, ch, error, fflag, fts_options, hflag, rval; int vflag; char *mode; mode_t newmode; set = NULL; Hflag = Lflag = Rflag = fflag = hflag = vflag = 0; while ((ch = getopt(argc, argv, "HLPRXfghorstuvwx")) != -1) switch (ch) { case 'H': Hflag = 1; Lflag = 0; break; case 'L': Lflag = 1; Hflag = 0; break; case 'P': Hflag = Lflag = 0; break; case 'R': Rflag = 1; break; case 'f': fflag = 1; break; case 'h': /* * In System V (and probably POSIX.2) the -h option * causes chmod to change the mode of the symbolic * link. 4.4BSD's symbolic links didn't have modes, * so it was an undocumented noop. In FreeBSD 3.0, * lchmod(2) is introduced and this option does real * work. */ hflag = 1; break; /* * XXX * "-[rwx]" are valid mode commands. If they are the entire * argument, getopt has moved past them, so decrement optind. * Regardless, we're done argument processing. */ case 'g': case 'o': case 'r': case 's': case 't': case 'u': case 'w': case 'X': case 'x': if (argv[optind - 1][0] == '-' && argv[optind - 1][1] == ch && argv[optind - 1][2] == '\0') --optind; goto done; case 'v': vflag++; break; case '?': default: usage(); } done: argv += optind; argc -= optind; if (argc < 2) usage(); if (Rflag) { fts_options = FTS_PHYSICAL; if (hflag) errx(1, "the -R and -h options may not be specified together."); if (Hflag) fts_options |= FTS_COMFOLLOW; if (Lflag) { fts_options &= ~FTS_PHYSICAL; fts_options |= FTS_LOGICAL; } } else fts_options = hflag ? FTS_PHYSICAL : FTS_LOGICAL; mode = *argv; if ((set = setmode(mode)) == NULL) errx(1, "invalid file mode: %s", mode); if ((ftsp = fts_open(++argv, fts_options, 0)) == NULL) err(1, "fts_open"); for (rval = 0; (p = fts_read(ftsp)) != NULL;) { switch (p->fts_info) { case FTS_D: /* Change it at FTS_DP. */ if (!Rflag) fts_set(ftsp, p, FTS_SKIP); continue; case FTS_DNR: /* Warn, chmod, continue. */ warnx("%s: %s", p->fts_path, strerror(p->fts_errno)); rval = 1; break; case FTS_ERR: /* Warn, continue. */ case FTS_NS: warnx("%s: %s", p->fts_path, strerror(p->fts_errno)); rval = 1; continue; case FTS_SL: /* Ignore. */ case FTS_SLNONE: /* * The only symlinks that end up here are ones that * don't point to anything and ones that we found * doing a physical walk. */ if (!hflag) continue; /* FALLTHROUGH */ default: break; } newmode = getmode(set, p->fts_statp->st_mode); /* * With NFSv4 ACLs, it is possible that applying a mode * identical to the one computed from an ACL will change * that ACL. */ if (may_have_nfs4acl(p, hflag) == 0 && (newmode & ALLPERMS) == (p->fts_statp->st_mode & ALLPERMS)) continue; if (hflag) error = lchmod(p->fts_accpath, newmode); else error = chmod(p->fts_accpath, newmode); if (error) { if (!fflag) { warn("%s", p->fts_path); rval = 1; } } else { if (vflag) { (void)printf("%s", p->fts_path); if (vflag > 1) { char m1[12], m2[12]; strmode(p->fts_statp->st_mode, m1); strmode((p->fts_statp->st_mode & S_IFMT) | newmode, m2); (void)printf(": 0%o [%s] -> 0%o [%s]", p->fts_statp->st_mode, m1, (p->fts_statp->st_mode & S_IFMT) | newmode, m2); } (void)printf("\n"); } } } if (errno) err(1, "fts_read"); exit(rval); }
static unsigned int call_syscall(struct syscall_desc *scall, char *argv[]) { struct stat64 sb; long long flags; unsigned int i; char *endp; int rval; union { char *str; long long num; } args[MAX_ARGS]; /* * Verify correctness of the arguments. */ for (i = 0; i < sizeof(args)/sizeof(args[0]); i++) { if (scall->sd_args[i] == TYPE_NONE) { if (argv[i] == NULL || strcmp(argv[i], ":") == 0) break; fprintf(stderr, "too many arguments [%s]\n", argv[i]); exit(1); } else { if (argv[i] == NULL || strcmp(argv[i], ":") == 0) { if (scall->sd_args[i] & TYPE_OPTIONAL) break; fprintf(stderr, "too few arguments\n"); exit(1); } if (scall->sd_args[i] & TYPE_STRING) { if (strcmp(argv[i], "NULL") == 0) args[i].str = NULL; else if (strcmp(argv[i], "DEADCODE") == 0) args[i].str = (void *)0xdeadc0de; else args[i].str = argv[i]; } else if (scall->sd_args[i] & TYPE_NUMBER) { args[i].num = strtoll(argv[i], &endp, 0); if (*endp != '\0' && !isspace((unsigned char)*endp)) { fprintf(stderr, "invalid argument %u, number expected [%s]\n", i, endp); exit(1); } } } } /* * Call the given syscall. */ #define NUM(n) (args[(n)].num) #define STR(n) (args[(n)].str) switch (scall->sd_action) { case ACTION_OPEN: flags = str2flags(open_flags, STR(1)); if (flags & O_CREAT) { if (i == 2) { fprintf(stderr, "too few arguments\n"); exit(1); } rval = open(STR(0), flags, (mode_t)NUM(2)); } else { if (i == 3) { fprintf(stderr, "too many arguments\n"); exit(1); } rval = open(STR(0), flags); } break; case ACTION_CREATE: rval = open(STR(0), O_CREAT | O_EXCL, NUM(1)); if (rval >= 0) close(rval); break; case ACTION_UNLINK: rval = unlink(STR(0)); break; case ACTION_MKDIR: rval = mkdir(STR(0), NUM(1)); break; case ACTION_RMDIR: rval = rmdir(STR(0)); break; case ACTION_LINK: rval = link(STR(0), STR(1)); break; case ACTION_SYMLINK: rval = symlink(STR(0), STR(1)); break; case ACTION_RENAME: rval = rename(STR(0), STR(1)); break; case ACTION_MKFIFO: rval = mkfifo(STR(0), NUM(1)); break; case ACTION_CHMOD: rval = chmod(STR(0), NUM(1)); break; #ifdef HAS_LCHMOD case ACTION_LCHMOD: rval = lchmod(STR(0), NUM(1)); break; #endif case ACTION_CHOWN: rval = chown(STR(0), NUM(1), NUM(2)); break; case ACTION_LCHOWN: rval = lchown(STR(0), NUM(1), NUM(2)); break; #ifdef HAS_CHFLAGS case ACTION_CHFLAGS: rval = chflags(STR(0), str2flags(chflags_flags, STR(1))); break; #endif #ifdef HAS_LCHFLAGS case ACTION_LCHFLAGS: rval = lchflags(STR(0), str2flags(chflags_flags, STR(1))); break; #endif case ACTION_TRUNCATE: rval = truncate64(STR(0), NUM(1)); break; case ACTION_STAT: rval = stat64(STR(0), &sb); if (rval == 0) { show_stats(&sb, STR(1)); return (i); } break; case ACTION_LSTAT: rval = lstat64(STR(0), &sb); if (rval == 0) { show_stats(&sb, STR(1)); return (i); } break; case ACTION_READDIR: rval = readdir_loop(STR(0)); break; default: fprintf(stderr, "unsupported syscall\n"); exit(1); } #undef STR #undef NUM if (rval < 0) { const char *serrno; serrno = err2str(errno); fprintf(stderr, "%s returned %d\n", scall->sd_name, rval); printf("%s\n", serrno); exit(1); } printf("0\n"); return (i); }
int dirchownmod (int fd, char const *dir, mode_t mkdir_mode, uid_t owner, gid_t group, mode_t mode, mode_t mode_bits) { struct stat st; int result = (fd < 0 ? stat (dir, &st) : fstat (fd, &st)); if (result == 0) { mode_t dir_mode = st.st_mode; /* Check whether DIR is a directory. If FD is nonnegative, this check avoids changing the ownership and mode bits of the wrong file in many cases. This doesn't fix all the race conditions, but it is better than nothing. */ if (! S_ISDIR (dir_mode)) { errno = ENOTDIR; result = -1; } else { /* If at least one of the S_IXUGO bits are set, chown might clear the S_ISUID and S_SGID bits. Keep track of any file mode bits whose values are indeterminate due to this issue. */ mode_t indeterminate = 0; /* On some systems, chown clears S_ISUID and S_ISGID, so do chown before chmod. On older System V hosts, ordinary users can give their files away via chown; don't worry about that here, since users shouldn't do that. */ if ((owner != (uid_t) -1 && owner != st.st_uid) || (group != (gid_t) -1 && group != st.st_gid)) { result = (0 <= fd ? fchown (fd, owner, group) : mkdir_mode != (mode_t) -1 ? lchown (dir, owner, group) : chown (dir, owner, group)); /* Either the user cares about an indeterminate bit and it'll be set properly by chmod below, or the user doesn't care and it's OK to use the bit's pre-chown value. So there's no need to re-stat DIR here. */ if (result == 0 && (dir_mode & S_IXUGO)) indeterminate = dir_mode & (S_ISUID | S_ISGID); } /* If the file mode bits might not be right, use chmod to change them. Don't change bits the user doesn't care about. */ if (result == 0 && (((dir_mode ^ mode) | indeterminate) & mode_bits)) { mode_t chmod_mode = mode | (dir_mode & CHMOD_MODE_BITS & ~mode_bits); result = (HAVE_FCHMOD && 0 <= fd ? fchmod (fd, chmod_mode) : mkdir_mode != (mode_t) -1 ? lchmod (dir, chmod_mode) : chmod (dir, chmod_mode)); } } } if (0 <= fd) { if (result == 0) result = close (fd); else { int e = errno; close (fd); errno = e; } } return result; }
void test() { int err; int lastctime; struct stat s; // // chmod a file // // get the current ctime for the file memset(&s, 0, sizeof s); stat("file", &s); lastctime = s.st_ctime; sleep(1); // do the actual chmod err = chmod("file", 0200); assert(!err); memset(&s, 0, sizeof s); stat("file", &s); #if USE_OLD_FS assert(s.st_mode == (0222 | S_IFREG)); #else assert(s.st_mode == (0200 | S_IFREG)); #endif assert(s.st_ctime != lastctime); // // fchmod a file // lastctime = s.st_ctime; sleep(1); err = fchmod(open("file", O_WRONLY), 0100); assert(!err); memset(&s, 0, sizeof s); stat("file", &s); #if USE_OLD_FS assert(s.st_mode == (0000 | S_IFREG)); #else assert(s.st_mode == (0100 | S_IFREG)); #endif assert(s.st_ctime != lastctime); // // chmod a folder // // get the current ctime for the folder memset(&s, 0, sizeof s); stat("folder", &s); lastctime = s.st_ctime; sleep(1); // do the actual chmod err = chmod("folder", 0300); assert(!err); memset(&s, 0, sizeof s); stat("folder", &s); #if USE_OLD_FS assert(s.st_mode == (0222 | S_IFDIR)); #else assert(s.st_mode == (0300 | S_IFDIR)); #endif assert(s.st_ctime != lastctime); // // chmod a symlink's target // err = chmod("file-link", 0400); assert(!err); // make sure the file it references changed stat("file-link", &s); #if USE_OLD_FS assert(s.st_mode == (0555 | S_IFREG)); #else assert(s.st_mode == (0400 | S_IFREG)); #endif // but the link didn't lstat("file-link", &s); assert(s.st_mode == (0777 | S_IFLNK)); // // chmod the actual symlink // err = lchmod("file-link", 0500); assert(!err); // make sure the file it references didn't change stat("file-link", &s); #if USE_OLD_FS assert(s.st_mode == (0555 | S_IFREG)); #else assert(s.st_mode == (0400 | S_IFREG)); #endif // but the link did lstat("file-link", &s); #if USE_OLD_FS assert(s.st_mode == (0555 | S_IFLNK)); #else assert(s.st_mode == (0500 | S_IFLNK)); #endif puts("success"); }
int main(int argc, char *argv[]) { int ch, i, stdinflag = 0; char cflag = 0, mflag = 0; char *outfile, *outpath = NULL; struct field *fldtab; size_t fldtab_sz, fld_cnt; size_t alloc_size; struct filelist filelist; int num_input_files; FILE *outfp = NULL; struct rlimit rl; struct stat st; setlocale(LC_ALL, ""); /* bump RLIMIT_NOFILE to maximum our hard limit allows */ if (getrlimit(RLIMIT_NOFILE, &rl) < 0) err(2, "getrlimit"); rl.rlim_cur = rl.rlim_max; if (setrlimit(RLIMIT_NOFILE, &rl) < 0) err(2, "setrlimit"); d_mask[REC_D = '\n'] = REC_D_F; d_mask['\t'] = d_mask[' '] = BLANK | FLD_D; /* fldtab[0] is the global options. */ fldtab_sz = 3; fld_cnt = 0; alloc_size = fldtab_sz * sizeof(*fldtab); fldtab = malloc(alloc_size); if (fldtab == NULL) err(1, "Cannot allocate %zu bytes", alloc_size); memset(fldtab, 0, alloc_size); #define SORT_OPTS "bcdD:fHik:lmno:rR:sSt:T:ux" /* Convert "+field" args to -f format */ fixit(&argc, argv, SORT_OPTS); if (!(tmpdir = getenv("TMPDIR"))) tmpdir = _PATH_TMP; while ((ch = getopt(argc, argv, SORT_OPTS)) != -1) { switch (ch) { case 'b': fldtab[0].flags |= BI | BT; break; case 'c': cflag = 1; break; case 'D': /* Debug flags */ for (i = 0; optarg[i]; i++) debug_flags |= 1 << (optarg[i] & 31); break; case 'd': case 'f': case 'i': case 'n': case 'l': fldtab[0].flags |= optval(ch, 0); break; case 'H': /* -H was ; use merge sort for blocks of large files' */ /* That is now the default. */ break; case 'k': alloc_size = (fldtab_sz + 1) * sizeof(*fldtab); fldtab = realloc(fldtab, alloc_size); if (fldtab == NULL) err(1, "Cannot re-allocate %zu bytes", alloc_size); memset(&fldtab[fldtab_sz], 0, sizeof(fldtab[0])); fldtab_sz++; setfield(optarg, &fldtab[++fld_cnt], fldtab[0].flags); break; case 'm': mflag = 1; break; case 'o': outpath = optarg; break; case 'r': REVERSE = 1; break; case 's': /* * Nominally 'stable sort', keep lines with equal keys * in input file order. (Default for NetBSD) * (-s for GNU sort compatibility.) */ posix_sort = 0; break; case 'S': /* * Reverse of -s! * This needs to enforce a POSIX sort where records * with equal keys are then sorted by the raw data. * Currently not implemented! * (using libc radixsort() v sradixsort() doesn't * have the desired effect.) */ posix_sort = 1; break; case 't': if (SEP_FLAG) usage("multiple field delimiters"); SEP_FLAG = 1; d_mask[' '] &= ~FLD_D; d_mask['\t'] &= ~FLD_D; d_mask[(u_char)*optarg] |= FLD_D; if (d_mask[(u_char)*optarg] & REC_D_F) errx(2, "record/field delimiter clash"); break; case 'R': if (REC_D != '\n') usage("multiple record delimiters"); REC_D = *optarg; if (REC_D == '\n') break; if (optarg[1] != '\0') { char *ep; int t = 0; if (optarg[0] == '\\') optarg++, t = 8; REC_D = (int)strtol(optarg, &ep, t); if (*ep != '\0' || REC_D < 0 || REC_D >= (int)__arraycount(d_mask)) errx(2, "invalid record delimiter %s", optarg); } d_mask['\n'] = d_mask[' ']; d_mask[REC_D] = REC_D_F; break; case 'T': /* -T tmpdir */ tmpdir = optarg; break; case 'u': UNIQUE = 1; break; case '?': default: usage(NULL); } } if (UNIQUE) /* Don't sort on raw record if keys match */ posix_sort = 0; if (cflag && argc > optind+1) errx(2, "too many input files for -c option"); if (argc - 2 > optind && !strcmp(argv[argc-2], "-o")) { outpath = argv[argc-1]; argc -= 2; } if (mflag && argc - optind > (MAXFCT - (16+1))*16) errx(2, "too many input files for -m option"); for (i = optind; i < argc; i++) { /* allow one occurrence of /dev/stdin */ if (!strcmp(argv[i], "-") || !strcmp(argv[i], _PATH_STDIN)) { if (stdinflag) warnx("ignoring extra \"%s\" in file list", argv[i]); else stdinflag = 1; /* change to /dev/stdin if '-' */ if (argv[i][0] == '-') { static char path_stdin[] = _PATH_STDIN; argv[i] = path_stdin; } } else if ((ch = access(argv[i], R_OK))) err(2, "%s", argv[i]); } if (fldtab[1].icol.num == 0) { /* No sort key specified */ if (fldtab[0].flags & (I|D|F|N|L)) { /* Modified - generate a key that covers the line */ fldtab[0].flags &= ~(BI|BT); setfield("1", &fldtab[++fld_cnt], fldtab->flags); fldreset(fldtab); } else { /* Unmodified, just compare the line */ SINGL_FLD = 1; fldtab[0].icol.num = 1; } } else { fldreset(fldtab); } settables(); if (optind == argc) { static const char * const names[] = { _PATH_STDIN, NULL }; filelist.names = names; num_input_files = 1; } else { filelist.names = (const char * const *) &argv[optind]; num_input_files = argc - optind; } if (cflag) { order(&filelist, fldtab); /* NOT REACHED */ } if (!outpath) { toutpath[0] = '\0'; /* path not used in this case */ outfile = outpath = toutpath; outfp = stdout; } else if (lstat(outpath, &st) == 0 && !S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode)) { /* output file exists and isn't character or block device */ struct sigaction act; static const int sigtable[] = {SIGHUP, SIGINT, SIGPIPE, SIGXCPU, SIGXFSZ, SIGVTALRM, SIGPROF, 0 }; int outfd; errno = 0; if (access(outpath, W_OK)) err(2, "%s", outpath); (void)snprintf(toutpath, sizeof(toutpath), "%sXXXXXX", outpath); if ((outfd = mkstemp(toutpath)) == -1) err(2, "Cannot create temporary file `%s'", toutpath); (void)atexit(cleanup); act.sa_handler = onsignal; (void) sigemptyset(&act.sa_mask); act.sa_flags = SA_RESTART | SA_RESETHAND; for (i = 0; sigtable[i]; ++i) /* always unlink toutpath */ sigaction(sigtable[i], &act, 0); outfile = toutpath; if ((outfp = fdopen(outfd, "w")) == NULL) err(2, "Cannot open temporary file `%s'", toutpath); } else { outfile = outpath; if ((outfp = fopen(outfile, "w")) == NULL) err(2, "output file %s", outfile); } if (mflag) fmerge(&filelist, num_input_files, outfp, fldtab); else fsort(&filelist, num_input_files, outfp, fldtab); if (outfile != outpath) { if (access(outfile, F_OK)) err(2, "%s", outfile); /* * Copy file permissions bits of the original file. * st is initialized above, when we create the * temporary spool file. */ if (lchmod(outfile, st.st_mode & ALLPERMS) != 0) { err(2, "cannot chmod %s: output left in %s", outpath, outfile); } (void)unlink(outpath); if (link(outfile, outpath)) err(2, "cannot link %s: output left in %s", outpath, outfile); (void)unlink(outfile); toutpath[0] = 0; } exit(0); }
static void miss(NODE *p, char *tail) { int create; char *tp; const char *type; u_int32_t flags; for (; p; p = p->next) { if (p->flags & F_OPT && !(p->flags & F_VISIT)) continue; if (p->type != F_DIR && (dflag || p->flags & F_VISIT)) continue; strcpy(tail, p->name); if (!(p->flags & F_VISIT)) printf("missing: %s", path); switch (p->type) { case F_BLOCK: case F_CHAR: type = "device"; break; case F_DIR: type = "directory"; break; case F_LINK: type = "symlink"; break; default: putchar('\n'); continue; } create = 0; if (!(p->flags & F_VISIT) && uflag) { if (mtree_Wflag || p->type == F_LINK) goto createit; if (!(p->flags & (F_UID | F_UNAME))) printf( " (%s not created: user not specified)", type); else if (!(p->flags & (F_GID | F_GNAME))) printf( " (%s not created: group not specified)", type); else if (!(p->flags & F_MODE)) printf( " (%s not created: mode not specified)", type); else createit: switch (p->type) { case F_BLOCK: case F_CHAR: if (mtree_Wflag) continue; if (!(p->flags & F_DEV)) printf( " (%s not created: device not specified)", type); else if (mknod(path, p->st_mode | nodetoino(p->type), p->st_rdev) == -1) printf(" (%s not created: %s)\n", type, strerror(errno)); else create = 1; break; case F_LINK: if (!(p->flags & F_SLINK)) printf( " (%s not created: link not specified)\n", type); else if (symlink(p->slink, path)) printf( " (%s not created: %s)\n", type, strerror(errno)); else create = 1; break; case F_DIR: if (mkdir(path, S_IRWXU|S_IRWXG|S_IRWXO)) printf(" (not created: %s)", strerror(errno)); else create = 1; break; default: mtree_err("can't create create %s", nodetype(p->type)); } } if (create) printf(" (created)"); if (p->type == F_DIR) { if (!(p->flags & F_VISIT)) putchar('\n'); for (tp = tail; *tp; ++tp) continue; *tp = '/'; miss(p->child, tp + 1); *tp = '\0'; } else putchar('\n'); if (!create || mtree_Wflag) continue; if ((p->flags & (F_UID | F_UNAME)) && (p->flags & (F_GID | F_GNAME)) && (lchown(path, p->st_uid, p->st_gid))) { printf("%s: user/group/mode not modified: %s\n", path, strerror(errno)); printf("%s: warning: file mode %snot set\n", path, (p->flags & F_FLAGS) ? "and file flags " : ""); continue; } if (p->flags & F_MODE) { if (lchmod(path, p->st_mode)) printf("%s: permissions not set: %s\n", path, strerror(errno)); } #if HAVE_STRUCT_STAT_ST_FLAGS if ((p->flags & F_FLAGS) && p->st_flags) { if (iflag) flags = p->st_flags; else flags = p->st_flags & ~SP_FLGS; if (lchflags(path, flags)) printf("%s: file flags not set: %s\n", path, strerror(errno)); } #endif /* HAVE_STRUCT_STAT_ST_FLAGS */ } }
int setfile(struct stat *fs, int fd) { static struct timeval tv[2]; struct stat ts; int rval, gotstat, islink, fdval; rval = 0; fdval = fd != -1; islink = !fdval && S_ISLNK(fs->st_mode); fs->st_mode &= S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO; TIMESPEC_TO_TIMEVAL(&tv[0], &fs->st_atimespec); TIMESPEC_TO_TIMEVAL(&tv[1], &fs->st_mtimespec); if (islink ? lutimes(to.p_path, tv) : utimes(to.p_path, tv)) { warn("%sutimes: %s", islink ? "l" : "", to.p_path); rval = 1; } if (fdval ? fstat(fd, &ts) : (islink ? lstat(to.p_path, &ts) : stat(to.p_path, &ts))) gotstat = 0; else { gotstat = 1; ts.st_mode &= S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO; } /* * Changing the ownership probably won't succeed, unless we're root * or POSIX_CHOWN_RESTRICTED is not set. Set uid/gid before setting * the mode; current BSD behavior is to remove all setuid bits on * chown. If chown fails, lose setuid/setgid bits. */ if (!gotstat || fs->st_uid != ts.st_uid || fs->st_gid != ts.st_gid) if (fdval ? fchown(fd, fs->st_uid, fs->st_gid) : (islink ? lchown(to.p_path, fs->st_uid, fs->st_gid) : chown(to.p_path, fs->st_uid, fs->st_gid))) { if (errno != EPERM) { warn("chown: %s", to.p_path); rval = 1; } fs->st_mode &= ~(S_ISUID | S_ISGID); } if (!gotstat || fs->st_mode != ts.st_mode) if (fdval ? fchmod(fd, fs->st_mode) : (islink ? lchmod(to.p_path, fs->st_mode) : chmod(to.p_path, fs->st_mode))) { warn("chmod: %s", to.p_path); rval = 1; } if (!gotstat || fs->st_flags != ts.st_flags) if (fdval ? fchflags(fd, fs->st_flags) : (islink ? lchflags(to.p_path, fs->st_flags) : chflags(to.p_path, fs->st_flags))) { warn("chflags: %s", to.p_path); rval = 1; } return (rval); }
void set_file_attributes (char const *to, enum file_attributes attr, char const *from, const struct stat *st, mode_t mode, struct timespec *new_time) { if (attr & FA_TIMES) { struct timespec times[2]; if (new_time) times[0] = times[1] = *new_time; else { times[0] = get_stat_atime (st); times[1] = get_stat_mtime (st); } if (lutimens (to, times) != 0) pfatal ("Failed to set the timestamps of %s %s", S_ISLNK (mode) ? "symbolic link" : "file", quotearg (to)); } if (attr & FA_IDS) { static uid_t euid = -1; static gid_t egid = -1; uid_t uid; uid_t gid; if (euid == -1) { euid = geteuid (); egid = getegid (); } uid = (euid == st->st_uid) ? -1 : st->st_uid; gid = (egid == st->st_gid) ? -1 : st->st_gid; /* May fail if we are not privileged to set the file owner, or we are not in group instat.st_gid. Ignore those errors. */ if ((uid != -1 || gid != -1) && lchown (to, uid, gid) != 0 && (errno != EPERM || (uid != -1 && lchown (to, (uid = -1), gid) != 0 && errno != EPERM))) pfatal ("Failed to set the %s of %s %s", (uid == -1) ? "owner" : "owning group", S_ISLNK (mode) ? "symbolic link" : "file", quotearg (to)); } if (attr & FA_XATTRS) if (copy_attr (from, to) != 0 && errno != ENOSYS && errno != ENOTSUP && errno != EPERM) fatal_exit (0); if (attr & FA_MODE) { #if 0 && defined HAVE_LCHMOD /* The "diff --git" format does not store the file permissions of symlinks, so don't try to set symlink file permissions even on systems where we could. */ if (lchmod (to, mode)) #else if (! S_ISLNK (mode) && chmod (to, mode) != 0) #endif pfatal ("Failed to set the permissions of %s %s", S_ISLNK (mode) ? "symbolic link" : "file", quotearg (to)); } }
static unsigned int call_syscall(struct syscall_desc *scall, char *argv[]) { struct stat64 sb; struct utimbuf ut; long long flags; unsigned int i; char *endp; int rval; int more; union { char *str; long long num; } args[MAX_ARGS]; more = 0; /* * Verify correctness of the arguments. */ for (i = 0; i < sizeof(args)/sizeof(args[0]); i++) { if (scall->sd_args[i] == TYPE_NONE) { if (argv[i] == NULL || strcmp(argv[i], ":") == 0) break; fprintf(stderr, "too many arguments [%s]\n", argv[i]); exit(1); } else { if (argv[i] == NULL || strcmp(argv[i], ":") == 0) { if (scall->sd_args[i] & TYPE_OPTIONAL) { args[i].str = NULL; break; } fprintf(stderr, "too few arguments\n"); exit(1); } if ((scall->sd_args[i] & TYPE_MASK) == TYPE_STRING) { if (strcmp(argv[i], "NULL") == 0) args[i].str = NULL; else if (strcmp(argv[i], "DEADCODE") == 0) args[i].str = (void *)0xdeadc0de; else args[i].str = argv[i]; } else if ((scall->sd_args[i] & TYPE_MASK) == TYPE_NUMBER) { args[i].num = strtoll(argv[i], &endp, 0); if (*endp != '\0' && !isspace((unsigned char)*endp)) { fprintf(stderr, "invalid argument %u, number expected [%s]\n", i, endp); exit(1); } } else if ((scall->sd_args[i] & TYPE_MASK) == TYPE_DESCRIPTOR) { if (strcmp(argv[i], "AT_FDCWD") == 0) { args[i].num = AT_FDCWD; } else if (strcmp(argv[i], "BADFD") == 0) { /* In case AT_FDCWD is -1 on some systems... */ if (AT_FDCWD == -1) args[i].num = -2; else args[i].num = -1; } else { int pos; pos = strtoll(argv[i], &endp, 0); if (*endp != '\0' && !isspace((unsigned char)*endp)) { fprintf(stderr, "invalid argument %u, number expected [%s]\n", i, endp); exit(1); } args[i].num = descriptor_get(pos); } } } } /* * Call the given syscall. */ #define NUM(n) (args[(n)].num) #define STR(n) (args[(n)].str) switch (scall->sd_action) { case ACTION_OPEN: flags = str2flags(open_flags, STR(1)); if (flags & O_CREAT) { if (i == 2) { fprintf(stderr, "too few arguments\n"); exit(1); } rval = open(STR(0), flags, (mode_t)NUM(2)); } else { if (i == 3) { fprintf(stderr, "too many arguments\n"); exit(1); } rval = open(STR(0), flags); } if (rval >= 0) { more = argv[i] && !strcmp(argv[i], ":"); descriptor_add(rval); } break; case ACTION_CREATE: rval = open(STR(0), O_CREAT | O_EXCL, NUM(1)); if (rval >= 0) { more = argv[i] && !strcmp(argv[i], ":"); descriptor_add(rval); } break; case ACTION_UNLINK: rval = unlink(STR(0)); break; case ACTION_MKDIR: rval = mkdir(STR(0), NUM(1)); break; case ACTION_RMDIR: rval = rmdir(STR(0)); break; case ACTION_LINK: rval = link(STR(0), STR(1)); break; case ACTION_SYMLINK: rval = symlink(STR(0), STR(1)); break; case ACTION_RENAME: rval = rename(STR(0), STR(1)); break; case ACTION_MKFIFO: rval = mkfifo(STR(0), NUM(1)); break; case ACTION_CHMOD: rval = chmod(STR(0), NUM(1)); break; #ifdef HAS_LCHMOD case ACTION_LCHMOD: rval = lchmod(STR(0), NUM(1)); break; #endif case ACTION_CHOWN: rval = chown(STR(0), NUM(1), NUM(2)); break; case ACTION_LCHOWN: rval = lchown(STR(0), NUM(1), NUM(2)); break; #ifdef HAS_CHFLAGS case ACTION_CHFLAGS: rval = chflags(STR(0), str2flags(chflags_flags, STR(1))); break; #endif #ifdef HAS_LCHFLAGS case ACTION_LCHFLAGS: rval = lchflags(STR(0), str2flags(chflags_flags, STR(1))); break; #endif case ACTION_TRUNCATE: rval = truncate64(STR(0), NUM(1)); break; case ACTION_FTRUNCATE: rval = ftruncate64(NUM(0), NUM(1)); break; case ACTION_STAT: rval = stat64(STR(0), &sb); if (rval == 0) { show_stats(&sb, STR(1)); return (i); } break; case ACTION_LSTAT: rval = lstat64(STR(0), &sb); if (rval == 0) { show_stats(&sb, STR(1)); return (i); } break; case ACTION_UTIME : switch (i) { case 1 : rval = utime(STR(0), (struct utimbuf*)NULL); break; case 3: ut.actime = NUM(1); ut.modtime = NUM(2); rval = utime(STR(0), &ut); break; default : fprintf(stderr,"utime() requires 1 or 3 arguments\n"); exit(1); } break; case ACTION_BIND: { struct sockaddr_un sunx; sunx.sun_family = AF_UNIX; strncpy(sunx.sun_path, STR(0), sizeof(sunx.sun_path) - 1); sunx.sun_path[sizeof(sunx.sun_path) - 1] = '\0'; rval = socket(AF_UNIX, SOCK_STREAM, 0); if (rval < 0) break; rval = bind(rval, (struct sockaddr *)&sunx, sizeof(sunx)); break; } case ACTION_MKNOD: case ACTION_MKNODAT: { mode_t ntype; dev_t dev; int fa; switch (scall->sd_action) { case ACTION_MKNOD: fa = 0; break; case ACTION_MKNODAT: fa = 1; break; default: abort(); } dev = makedev(NUM(fa + 3), NUM(fa + 4)); if (strcmp(STR(fa + 1), "c") == 0) /* character device */ ntype = S_IFCHR; else if (strcmp(STR(fa + 1), "b") == 0) /* block device */ ntype = S_IFBLK; else if (strcmp(STR(fa + 1), "f") == 0) /* fifo special */ ntype = S_IFIFO; else if (strcmp(STR(fa + 1), "d") == 0) /* directory */ ntype = S_IFDIR; else if (strcmp(STR(fa + 1), "o") == 0) /* regular file */ ntype = S_IFREG; else { fprintf(stderr, "wrong argument 1\n"); exit(1); } switch (scall->sd_action) { case ACTION_MKNOD: rval = mknod(STR(0), ntype | NUM(2), dev); break; case ACTION_MKNODAT: rval = mknodat(NUM(0), STR(1), ntype | NUM(3), dev); break; default: abort(); } break; } #ifdef HAS_ACL case ACTION_GETFACL : rval = do_getfacl(STR(0), STR(1)); if (rval == 0) return (i); break; case ACTION_SETFACL : rval = do_setfacl(STR(0), STR(1), STR(2)); break; #endif default: fprintf(stderr, "unsupported syscall\n"); exit(1); } #undef STR #undef NUM if (rval < 0) { const char *serrno; serrno = err2str(errno); fprintf(stderr, "%s returned %d\n", scall->sd_name, rval); printf("%s\n", serrno); exit(1); } /* Do not output a "0" when more syscalls to come */ if (!more) printf("0\n"); return (i); }
static unsigned int call_syscall(struct syscall_desc *scall, char *argv[]) { struct stat64 sb; long long flags; unsigned int i; char *endp; int name, rval; union { char *str; long long num; } args[MAX_ARGS]; #ifdef HAS_FREEBSD_ACL int entry_id = ACL_FIRST_ENTRY; acl_t acl, newacl; acl_entry_t entry, newentry; #endif /* * Verify correctness of the arguments. */ for (i = 0; i < sizeof(args)/sizeof(args[0]); i++) { if (scall->sd_args[i] == TYPE_NONE) { if (argv[i] == NULL || strcmp(argv[i], ":") == 0) break; fprintf(stderr, "too many arguments [%s]\n", argv[i]); exit(1); } else { if (argv[i] == NULL || strcmp(argv[i], ":") == 0) { if (scall->sd_args[i] & TYPE_OPTIONAL) break; fprintf(stderr, "too few arguments\n"); exit(1); } if ((scall->sd_args[i] & TYPE_MASK) == TYPE_STRING) { if (strcmp(argv[i], "NULL") == 0) args[i].str = NULL; else if (strcmp(argv[i], "DEADCODE") == 0) args[i].str = (void *)0xdeadc0de; else args[i].str = argv[i]; } else if ((scall->sd_args[i] & TYPE_MASK) == TYPE_NUMBER) { args[i].num = strtoll(argv[i], &endp, 0); if (*endp != '\0' && !isspace((unsigned char)*endp)) { fprintf(stderr, "invalid argument %u, number expected [%s]\n", i, endp); exit(1); } } else if ((scall->sd_args[i] & TYPE_MASK) == TYPE_DESCRIPTOR) { if (strcmp(argv[i], "AT_FDCWD") == 0) { args[i].num = AT_FDCWD; } else if (strcmp(argv[i], "BADFD") == 0) { /* In case AT_FDCWD is -1 on some systems... */ if (AT_FDCWD == -1) args[i].num = -2; else args[i].num = -1; } else { int pos; pos = strtoll(argv[i], &endp, 0); if (*endp != '\0' && !isspace((unsigned char)*endp)) { fprintf(stderr, "invalid argument %u, number expected [%s]\n", i, endp); exit(1); } args[i].num = descriptor_get(pos); } } } } /* * Call the given syscall. */ #define NUM(n) (args[(n)].num) #define STR(n) (args[(n)].str) switch (scall->sd_action) { case ACTION_OPEN: flags = str2flags(open_flags, STR(1)); if (flags & O_CREAT) { if (i == 2) { fprintf(stderr, "too few arguments\n"); exit(1); } rval = open(STR(0), (int)flags, (mode_t)NUM(2)); } else { if (i == 3) { fprintf(stderr, "too many arguments\n"); exit(1); } rval = open(STR(0), (int)flags); } if (rval >= 0) descriptor_add(rval); break; case ACTION_OPENAT: flags = str2flags(open_flags, STR(2)); if (flags & O_CREAT) { if (i == 3) { fprintf(stderr, "too few arguments\n"); exit(1); } rval = openat(NUM(0), STR(1), (int)flags, (mode_t)NUM(3)); } else { if (i == 4) { fprintf(stderr, "too many arguments\n"); exit(1); } rval = openat(NUM(0), STR(1), (int)flags); } if (rval >= 0) descriptor_add(rval); break; case ACTION_CREATE: rval = open(STR(0), O_CREAT | O_EXCL, (mode_t)NUM(1)); if (rval >= 0) close(rval); break; case ACTION_UNLINK: rval = unlink(STR(0)); break; case ACTION_UNLINKAT: rval = unlinkat(NUM(0), STR(1), (int)str2flags(unlinkat_flags, STR(2))); break; case ACTION_MKDIR: rval = mkdir(STR(0), (mode_t)NUM(1)); break; case ACTION_MKDIRAT: rval = mkdirat(NUM(0), STR(1), (mode_t)NUM(2)); break; case ACTION_RMDIR: rval = rmdir(STR(0)); break; case ACTION_LINK: rval = link(STR(0), STR(1)); break; case ACTION_LINKAT: rval = linkat(NUM(0), STR(1), NUM(2), STR(3), (int)str2flags(linkat_flags, STR(4))); break; case ACTION_SYMLINK: rval = symlink(STR(0), STR(1)); break; case ACTION_SYMLINKAT: rval = symlinkat(STR(0), NUM(1), STR(2)); break; case ACTION_RENAME: rval = rename(STR(0), STR(1)); break; case ACTION_RENAMEAT: rval = renameat(NUM(0), STR(1), NUM(2), STR(3)); break; case ACTION_MKFIFO: rval = mkfifo(STR(0), (mode_t)NUM(1)); break; case ACTION_MKFIFOAT: rval = mkfifoat(NUM(0), STR(1), (mode_t)NUM(2)); break; case ACTION_MKNOD: case ACTION_MKNODAT: { mode_t ntype; dev_t dev; int fa; switch (scall->sd_action) { case ACTION_MKNOD: fa = 0; break; case ACTION_MKNODAT: fa = 1; break; default: abort(); } dev = makedev(NUM(fa + 3), NUM(fa + 4)); if (strcmp(STR(fa + 1), "c") == 0) /* character device */ ntype = S_IFCHR; else if (strcmp(STR(fa + 1), "b") == 0) /* block device */ ntype = S_IFBLK; else if (strcmp(STR(fa + 1), "f") == 0) /* fifo special */ ntype = S_IFIFO; else if (strcmp(STR(fa + 1), "d") == 0) /* directory */ ntype = S_IFDIR; else if (strcmp(STR(fa + 1), "o") == 0) /* regular file */ ntype = S_IFREG; else { fprintf(stderr, "wrong argument 1\n"); exit(1); } switch (scall->sd_action) { case ACTION_MKNOD: rval = mknod(STR(0), ntype | NUM(2), dev); break; case ACTION_MKNODAT: rval = mknodat(NUM(0), STR(1), ntype | NUM(3), dev); break; default: abort(); } break; } case ACTION_BIND: { struct sockaddr_un sunx; sunx.sun_family = AF_UNIX; strncpy(sunx.sun_path, STR(0), sizeof(sunx.sun_path) - 1); sunx.sun_path[sizeof(sunx.sun_path) - 1] = '\0'; rval = socket(AF_UNIX, SOCK_STREAM, 0); if (rval < 0) break; rval = bind(rval, (struct sockaddr *)&sunx, sizeof(sunx)); break; } #ifdef HAS_BINDAT case ACTION_BINDAT: { struct sockaddr_un sunx; sunx.sun_family = AF_UNIX; strncpy(sunx.sun_path, STR(1), sizeof(sunx.sun_path) - 1); sunx.sun_path[sizeof(sunx.sun_path) - 1] = '\0'; rval = socket(AF_UNIX, SOCK_STREAM, 0); if (rval < 0) break; rval = bindat(NUM(0), rval, (struct sockaddr *)&sunx, sizeof(sunx)); break; } #endif case ACTION_CONNECT: { struct sockaddr_un sunx; sunx.sun_family = AF_UNIX; strncpy(sunx.sun_path, STR(0), sizeof(sunx.sun_path) - 1); sunx.sun_path[sizeof(sunx.sun_path) - 1] = '\0'; rval = socket(AF_UNIX, SOCK_STREAM, 0); if (rval < 0) break; rval = connect(rval, (struct sockaddr *)&sunx, sizeof(sunx)); break; } #ifdef HAS_CONNECTAT case ACTION_CONNECTAT: { struct sockaddr_un sunx; sunx.sun_family = AF_UNIX; strncpy(sunx.sun_path, STR(1), sizeof(sunx.sun_path) - 1); sunx.sun_path[sizeof(sunx.sun_path) - 1] = '\0'; rval = socket(AF_UNIX, SOCK_STREAM, 0); if (rval < 0) break; rval = connectat(NUM(0), rval, (struct sockaddr *)&sunx, sizeof(sunx)); break; } #endif case ACTION_CHMOD: rval = chmod(STR(0), (mode_t)NUM(1)); break; case ACTION_FCHMOD: rval = fchmod(NUM(0), (mode_t)NUM(1)); break; #ifdef HAS_LCHMOD case ACTION_LCHMOD: rval = lchmod(STR(0), (mode_t)NUM(1)); break; #endif case ACTION_FCHMODAT: rval = fchmodat(NUM(0), STR(1), (mode_t)NUM(2), str2flags(fchmodat_flags, STR(3))); break; case ACTION_CHOWN: rval = chown(STR(0), (uid_t)NUM(1), (gid_t)NUM(2)); break; case ACTION_FCHOWN: rval = fchown(NUM(0), (uid_t)NUM(1), (gid_t)NUM(2)); break; case ACTION_LCHOWN: rval = lchown(STR(0), (uid_t)NUM(1), (gid_t)NUM(2)); break; case ACTION_FCHOWNAT: rval = fchownat(NUM(0), STR(1), (uid_t)NUM(2), (gid_t)NUM(3), (int)str2flags(fchownat_flags, STR(4))); break; #ifdef HAS_CHFLAGS case ACTION_CHFLAGS: rval = chflags(STR(0), (unsigned long)str2flags(chflags_flags, STR(1))); break; #endif #ifdef HAS_FCHFLAGS case ACTION_FCHFLAGS: rval = fchflags(NUM(0), (unsigned long)str2flags(chflags_flags, STR(1))); break; #endif #ifdef HAS_CHFLAGSAT case ACTION_CHFLAGSAT: rval = chflagsat(NUM(0), STR(1), (unsigned long)str2flags(chflags_flags, STR(2)), (int)str2flags(chflagsat_flags, STR(3))); break; #endif #ifdef HAS_LCHFLAGS case ACTION_LCHFLAGS: rval = lchflags(STR(0), (unsigned long)str2flags(chflags_flags, STR(1))); break; #endif case ACTION_TRUNCATE: rval = truncate64(STR(0), NUM(1)); break; case ACTION_FTRUNCATE: rval = ftruncate64(NUM(0), NUM(1)); break; case ACTION_STAT: rval = stat64(STR(0), &sb); if (rval == 0) { show_stats(&sb, STR(1)); return (i); } break; case ACTION_FSTAT: rval = fstat64(NUM(0), &sb); if (rval == 0) { show_stats(&sb, STR(1)); return (i); } break; case ACTION_LSTAT: rval = lstat64(STR(0), &sb); if (rval == 0) { show_stats(&sb, STR(1)); return (i); } break; case ACTION_FSTATAT: rval = fstatat(NUM(0), STR(1), &sb, (int)str2flags(fstatat_flags, STR(2))); if (rval == 0) { show_stats(&sb, STR(3)); return (i); } break; case ACTION_PATHCONF: case ACTION_FPATHCONF: case ACTION_LPATHCONF: { long lrval; name = str2name(pathconf_names, STR(1)); if (name == -1) { fprintf(stderr, "unknown name %s", STR(1)); exit(1); } errno = 0; switch (scall->sd_action) { case ACTION_PATHCONF: lrval = pathconf(STR(0), name); break; case ACTION_FPATHCONF: lrval = fpathconf(NUM(0), name); break; case ACTION_LPATHCONF: lrval = lpathconf(STR(0), name); break; default: abort(); } if (lrval == -1 && errno == 0) { printf("unlimited\n"); return (i); } else if (lrval >= 0) { printf("%ld\n", lrval); return (i); } rval = -1; break; } #ifdef HAS_FREEBSD_ACL case ACTION_PREPENDACL: rval = -1; acl = acl_get_file(STR(0), ACL_TYPE_NFS4); if (acl == NULL) break; newacl = acl_from_text(STR(1)); if (acl == NULL) break; while (acl_get_entry(newacl, entry_id, &newentry) == 1) { entry_id = ACL_NEXT_ENTRY; if (acl_create_entry_np(&acl, &entry, 0)) break; if (acl_copy_entry(entry, newentry)) break; } rval = acl_set_file(STR(0), ACL_TYPE_NFS4, acl); break; case ACTION_READACL: acl = acl_get_file(STR(0), ACL_TYPE_NFS4); if (acl == NULL) rval = -1; else rval = 0; break; #endif case ACTION_WRITE: rval = write(NUM(0), STR(1), strlen(STR(1))); break; default: fprintf(stderr, "unsupported syscall\n"); exit(1); } #undef STR #undef NUM if (rval < 0) { const char *serrno; serrno = err2str(errno); fprintf(stderr, "%s returned %d\n", scall->sd_name, rval); printf("%s\n", serrno); exit(1); } printf("0\n"); return (i); }
int extractfile(char *name) { int flags; uid_t uid; gid_t gid; mode_t mode; int extsize; struct timeval mtimep[2], ctimep[2]; struct entry *ep; char *buf; curfile.name = name; curfile.action = USING; mtimep[0].tv_sec = curfile.atime_sec; mtimep[0].tv_usec = curfile.atime_nsec / 1000; mtimep[1].tv_sec = curfile.mtime_sec; mtimep[1].tv_usec = curfile.mtime_nsec / 1000; ctimep[0].tv_sec = curfile.atime_sec; ctimep[0].tv_usec = curfile.atime_nsec / 1000; ctimep[1].tv_sec = curfile.birthtime_sec; ctimep[1].tv_usec = curfile.birthtime_nsec / 1000; extsize = curfile.extsize; uid = getuid(); if (uid == 0) uid = curfile.uid; gid = curfile.gid; mode = curfile.mode; flags = curfile.file_flags; switch (mode & IFMT) { default: fprintf(stderr, "%s: unknown file mode 0%o\n", name, mode); skipfile(); return (FAIL); case IFSOCK: vprintf(stdout, "skipped socket %s\n", name); skipfile(); return (GOOD); case IFDIR: if (mflag) { ep = lookupname(name); if (ep == NULL || ep->e_flags & EXTRACT) panic("unextracted directory %s\n", name); skipfile(); return (GOOD); } vprintf(stdout, "extract file %s\n", name); return (genliteraldir(name, curfile.ino)); case IFLNK: lnkbuf[0] = '\0'; pathlen = 0; buf = setupextattr(extsize); getfile(xtrlnkfile, xtrattr, xtrlnkskip); if (pathlen == 0) { vprintf(stdout, "%s: zero length symbolic link (ignored)\n", name); return (GOOD); } if (linkit(lnkbuf, name, SYMLINK) == GOOD) { if (extsize > 0) set_extattr_link(name, buf, extsize); (void) lchown(name, uid, gid); (void) lchmod(name, mode); (void) lutimes(name, ctimep); (void) lutimes(name, mtimep); (void) lchflags(name, flags); return (GOOD); } return (FAIL); case IFIFO: vprintf(stdout, "extract fifo %s\n", name); if (Nflag) { skipfile(); return (GOOD); } if (uflag) (void) unlink(name); if (mkfifo(name, 0600) < 0) { fprintf(stderr, "%s: cannot create fifo: %s\n", name, strerror(errno)); skipfile(); return (FAIL); } if (extsize == 0) { skipfile(); } else { buf = setupextattr(extsize); getfile(xtrnull, xtrattr, xtrnull); set_extattr_file(name, buf, extsize); } (void) chown(name, uid, gid); (void) chmod(name, mode); (void) utimes(name, ctimep); (void) utimes(name, mtimep); (void) chflags(name, flags); return (GOOD); case IFCHR: case IFBLK: vprintf(stdout, "extract special file %s\n", name); if (Nflag) { skipfile(); return (GOOD); } if (uflag) (void) unlink(name); if (mknod(name, (mode & (IFCHR | IFBLK)) | 0600, (int)curfile.rdev) < 0) { fprintf(stderr, "%s: cannot create special file: %s\n", name, strerror(errno)); skipfile(); return (FAIL); } if (extsize == 0) { skipfile(); } else { buf = setupextattr(extsize); getfile(xtrnull, xtrattr, xtrnull); set_extattr_file(name, buf, extsize); } (void) chown(name, uid, gid); (void) chmod(name, mode); (void) utimes(name, ctimep); (void) utimes(name, mtimep); (void) chflags(name, flags); return (GOOD); case IFREG: vprintf(stdout, "extract file %s\n", name); if (Nflag) { skipfile(); return (GOOD); } if (uflag) (void) unlink(name); if ((ofile = open(name, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0) { fprintf(stderr, "%s: cannot create file: %s\n", name, strerror(errno)); skipfile(); return (FAIL); } buf = setupextattr(extsize); getfile(xtrfile, xtrattr, xtrskip); if (extsize > 0) set_extattr_fd(ofile, name, buf, extsize); (void) fchown(ofile, uid, gid); (void) fchmod(ofile, mode); (void) futimes(ofile, ctimep); (void) futimes(ofile, mtimep); (void) fchflags(ofile, flags); (void) close(ofile); return (GOOD); } /* NOTREACHED */ }
static void convert_spamd_db(int dbformat) { char* tsfn = NULL; int r, fd = -1; u_int32_t count = 0; DB *db1, *db2; BTREEINFO btreeinfo; HASHINFO hashinfo_odb, hashinfo_ndb; DBT dbk, dbd; time_t t_start, t_end; if (verbose) /* print details for input database */ printf ("in : %-20s uid: %-4d gid: %-4d mode %04o format: %-5s " "size: %-10u (%.3f MiB)\n", PATH_SPAMD_DB, (int)statbuf_in.st_uid, (int)statbuf_in.st_gid, statbuf_in.st_mode & 0777, dbformat == DBHASH ? "hash" : "btree", (u_int)statbuf_in.st_size, (double)statbuf_in.st_size / (1024 * 1024)); if (dbformat == DBBTREE){ replace = 0; /* no replace if source db is in btree format */ /* try to open the db as a BTREE */ memset(&btreeinfo, 0, sizeof(btreeinfo)); db1 = dbopen(PATH_SPAMD_DB, O_EXLOCK|O_RDWR, 0600, DB_BTREE, &btreeinfo); } else { /* DB is already in hash format */ memset(&hashinfo_odb, 0, sizeof(hashinfo_odb)); db1 = dbopen(PATH_SPAMD_DB, O_EXLOCK|O_RDWR, 0600, DB_HASH, &hashinfo_odb); } if (db1 == NULL) { if (errno == EACCES) { syslog_r(LOG_ERR, &sdata, "can't open %s in RW mode for UID %d (%m)", PATH_SPAMD_DB, geteuid() ); err(1, "can't open %s in RW mode for UID %d", PATH_SPAMD_DB, geteuid() ); } else syslog_r(LOG_ERR, &sdata, "corrupt db in %s, remove and restart (%m)", PATH_SPAMD_DB); err(1, "corrupt db in %s, remove and restart", PATH_SPAMD_DB ); exit(1); } if ((fd = mkstemp(sfn)) == -1) { syslog_r(LOG_ERR, &sdata, "can't process %s: mkstemp failed. UID: %d (%m)", PATH_SPAMD_DB, geteuid()); err(1, "can't process %s: mkstemp failed. UID: %d", PATH_SPAMD_DB, geteuid()); } memset(&hashinfo_ndb, 0, sizeof(hashinfo_ndb)); db2 = dbopen(sfn, O_EXLOCK|O_RDWR|O_CREAT, 0600, DB_HASH, &hashinfo_ndb); if (db2 == NULL) { unlink(sfn); syslog_r(LOG_ERR, &sdata, "can't convert %s: can't dbopen %s (%m)", PATH_SPAMD_DB, sfn); db1->close(db1); exit(1); } if (verbose) { if (dbformat == DBBTREE) printf("convert %s from btree to hash format\n", PATH_SPAMD_DB); else printf("start reorganization of %s...\n", PATH_SPAMD_DB); } time(&t_start); memset(&dbk, 0, sizeof(dbk)); memset(&dbd, 0, sizeof(dbd)); for (r = db1->seq(db1, &dbk, &dbd, R_FIRST); !r; r = db1->seq(db1, &dbk, &dbd, R_NEXT)) { if (db2->put(db2, &dbk, &dbd, 0)) { db2->sync(db2, 0); db2->close(db2); db1->close(db1); unlink(sfn); syslog_r(LOG_ERR, &sdata, "can't convert %s - remove and restart", PATH_SPAMD_DB); exit(1); } count++; if (verbose){ if ((count % 100) == 0) { printf("\rprogress %7u records", count); fflush(stdout); } } } db2->sync(db2, 0); db2->close(db2); db1->sync(db1, 0); db1->close(db1); time(&t_end); syslog_r(LOG_INFO, &sdata, "progress %u records: in %.f second(s)", count, difftime(t_end, t_start) ); if (verbose) printf("\rprogress %7u records: -> finish in %.f second(s)\n", count, difftime(t_end, t_start) ); if (replace) { rename(sfn, PATH_SPAMD_DB); tsfn = PATH_SPAMD_DB; } else { rename(sfn, PATH_REORG_DB); tsfn = PATH_REORG_DB; } close(fd); /* change owner to _spamd */ if (pw && (chown(tsfn, pw->pw_uid, pw->pw_gid) == -1)) { syslog_r(LOG_ERR, &sdata, "chown %s failed (%m)", tsfn); exit(1); } /* restore file access mode */ if (lchmod(tsfn, statbuf_in.st_mode) == -1) { syslog_r(LOG_ERR, &sdata, "chmod %s failed (%m)", tsfn); printf ("chmod %s faild (%s)\n", tsfn, strerror(errno)); exit(1); } r = lstat(tsfn, &statbuf_out); if (r != -1) { if (replace) syslog_r(LOG_INFO, &sdata, "replace %s with reorganized db. " "old size %u (%.3f MiB), new size: %u (%.3f MiB)", PATH_SPAMD_DB, (u_int)statbuf_in.st_size, (double)statbuf_in.st_size / (1024 * 1024), (u_int)statbuf_out.st_size, (double)statbuf_out.st_size / (1024 * 1024)); else syslog_r(LOG_INFO, &sdata, "%s db finished, " "size %s : %u (%.3f MiB), new size %s: %u (%.3f MiB)", dbformat == DBHASH ? "reorganize" : "convert", PATH_SPAMD_DB, (u_int)statbuf_in.st_size, (double)statbuf_in.st_size / (1024 * 1024), tsfn, (u_int)statbuf_out.st_size, (double)statbuf_out.st_size / (1024 * 1024)); if (verbose) { /* print details for output database */ printf ("out: %-20s uid: %-4d gid: %-4d mode %04o format: %-5s " "size: %-10u (%.3f MiB)\n", tsfn, (int)statbuf_out.st_uid, (int)statbuf_out.st_gid, statbuf_out.st_mode & 0777, "hash", (u_int)statbuf_out.st_size, (double)statbuf_out.st_size / (1024 * 1024) ); } } }