X-Git-Url: https://pd.if.org/git/?a=blobdiff_plain;f=zpm-syncfs.c;h=4aa792d887a89b941efeb476bd59cbf0beca14bf;hb=de3ce49c093f0c274d2921fa90ad829e1fc4a5f9;hp=94297a044a02e0bec4855a0268d2542897b6fb6d;hpb=cabe4437cdb5b40b55397608d0199ce31b0f3155;p=zpackage diff --git a/zpm-syncfs.c b/zpm-syncfs.c index 94297a0..4aa792d 100644 --- a/zpm-syncfs.c +++ b/zpm-syncfs.c @@ -30,7 +30,7 @@ struct config { int errabort, errors, verbose, dryrun, conflicts; int setuser, setgroup; int reverse, exitonerror; - int overwrite, absorb; + int overwrite, accept, acceptdir, ignoredirmd; }; struct nitem { @@ -47,7 +47,7 @@ struct nitem { time_t mtime; mode_t mode; int ftype; - int configuration; + int configuration, oldwasconf; struct timespec times[2]; }; @@ -247,106 +247,178 @@ static int report_conflicts(void *f, int ncols, char **vals, char **cols) { return 0; } -static int check_existing(void *f, int ncols, char **vals, char **cols) { - struct config *conf = f; - char *path; - struct stat st; +static int read_item(struct config *conf, int ncols, char **vals, char **cols, + struct nitem *n) { + char *val; + long lval; + struct passwd *pw; + struct group *gr; + struct nitem zero = { 0 }; - path = COL("dest"); - if (!path) { - return seterror(conf, "no path"); + *n = zero; + + val = COL("op"); + if (!val) { + seterror(conf, "can't determine op"); + return 0; + } + n->opstr = val; + n->op = getop(val); + if (!n->op) { + seterror(conf, "can't determine op"); + return 0; } - if (conf->dryrun) { - printf("checkfor %s\n", path); - fflush(stdout); + n->path = COL("path"); + if (!n->path) { + seterror(conf, "no file path"); + return 0; + } + if (strlen(n->path) == 0) { + seterror(conf, "zero length path not allowed"); return 0; } - if (conf->verbose) { - fprintf(stderr, "check for existing %s\n", path); + /* TODO config to dishonor setuid/setgid */ + n->dest = COL("dest"); + if (!n->dest) { + seterror(conf, "no file dest"); + return 0; } - if (lstat(path, &st) == 0) { - fprintf(stderr, "%s exists\n", path); - conf->errors++; - } else { - switch(errno) { - /* not an error, file shouldn't exist*/ - case ENOENT: break; - default: - fprintf(stderr, "unable to check %s: %s\n", - path, strerror(errno)); - conf->errors++; - break; - } + if (strlen(n->dest) == 0) { + seterror(conf, "zero length dest not allowed"); + return 0; } - return 0; -} -static int remove_files(void *f, int ncols, char **vals, char **cols) { - struct config *conf = f; - char *dest; - struct stat st; - int flags = 0; + val = COL("mode"); - dest = COL("dest"); - if (!dest) return seterror(conf,"no file dest"); + if (!val) { + seterror(conf, "can't determine mode"); + return 0; + } - if (conf->dryrun) { - char *ftype = COL("filetype"); - int t = *ftype; + n->mode = strtoul(val, NULL, 8); - switch(t) { - case 'd': printf("rmdir %s\n", dest); break; - default: printf("unlink %s\n", dest); break; - } - fflush(stdout); + val = COL("configuration"); + if (!val) { + seterror(conf, "can't determine config status"); return 0; } + lval = strtol(val, NULL, 10); - if (lstat(dest, &st) == -1) { - return seterror(conf,"can't stat"); - } + n->configuration = ((lval & 1) != 0); + n->oldwasconf = ((lval & 2) != 0); - if (S_ISDIR(st.st_mode)) { - flags = AT_REMOVEDIR; + val = COL("filetype"); + if (!val || strlen(val) == 0) { + seterror(conf, "can't determine file type"); + return 0; } - /* TODO check that expected filetype matches actual filetype */ + n->ftype = *val; - if (conf->verbose) { - fprintf(stderr, "%s(%s)\n", flags ? "rmdir" : "unlink", dest); + /* these can be null */ + n->ohash = COL("ohash"); + n->mds = COL("mds"); + n->omds = COL("omds"); + n->pkglist = COL("pkglist"); + + if (n->ftype == 'r') { + n->hash = COL("hash"); + if (!n->hash) { + seterror(conf, "can't get hash"); + return 0; + } + } else if (n->ftype == 'l') { + n->target = COL("target"); + if (!n->target) { + seterror(conf, "can't get target"); + return 0; + } + if (strlen(n->target) == 0) { + seterror(conf, "zero length target not allowed"); + return 0; + } + n->hash = n->target; } - errno = 0; + if (conf->setuser) { + val = COL("username"); + if (!val) { + seterror(conf, "no username"); + return 0; + } + pw = getpwnam(val); + if (!pw) { + seterror(conf, "no passwd entry"); + return 0; + } + n->uid = pw->pw_uid; + } else { + n->uid = geteuid(); + } - if (unlinkat(AT_FDCWD, dest, flags) == -1) { - switch (errno) { - case ENOENT: - break; - default: - return seterror(conf, "can't unlink"); + if (conf->setgroup) { + val = COL("groupname"); + if (!val) { + seterror(conf, "no groupname"); + return 0; } + gr = getgrnam(val); + if (!gr) { + seterror(conf, "no group entry for %s", val); + return 0; + } + n->gid = gr->gr_gid; + } else { + n->gid = getegid(); } - - return 0; -} -#define MARK fprintf(stderr, "%s %d: mark\n", __func__, __LINE__) + errno = 0; + double mtime = strtod(COL("mtime"),NULL); + if (errno) { + mtime = (double)time(NULL); + } + + n->mtime = (time_t)mtime; + + n->times[0].tv_sec = 0; + n->times[0].tv_nsec = UTIME_OMIT; + n->times[1].tv_sec = (time_t)llrint(floor(mtime)); + n->times[1].tv_nsec = lrint(floor(fmod(mtime,1.0)*1000000000)); + return 1; +} + +/* file does not exist */ #define D_NOEXIST 0x1 +/* files are different types */ #define D_TYPE 0x2 +/* metadata is different */ #define D_MD 0x4 +/* content or link target is different */ #define D_HASH 0x8 +/* file to be installed is a directory */ #define D_ISDIR 0x10 +/* path on disk is a directory */ #define D_EISDIR 0x20 +/* usernames different */ #define D_UID 0x40 +/* group names different */ #define D_GID 0x80 +/* file mode is different */ #define D_MODE 0x100 +/* mtimes are different */ #define D_MTIME 0x200 +/* the hash of the file we are supposedly replacing is different than + * the the hash of the file on disk + */ #define D_OHASH 0x400 +/* an error occurred trying to compare the file (other than it doesn't exist */ #define D_ERROR 0x1000 +/* there was a stat error */ #define D_STATERROR 0x2000 +/* there was an error calling readlink */ #define D_RLERROR 0x4000 /* 1 = file doesn't exist, 2 = file is a directory, target isn't */ @@ -388,11 +460,15 @@ static unsigned int file_compare(struct nitem *n, struct stat *st) { } if (n->hash && etype == S_IFLNK && stat_type == S_IFLNK) { lsize = readlink(n->dest, link, sizeof link); + if (lsize == -1 || lsize == sizeof link) { diff |= D_RLERROR; diff |= D_ERROR; - } else if (strcmp(n->target, link) != 0) { - diff |= D_HASH; + } else { + link[lsize] = 0; + if (strcmp(n->target, link) != 0) { + diff |= D_HASH; + } } } if (n->uid != st->st_uid) { @@ -417,145 +493,154 @@ static unsigned int file_compare(struct nitem *n, struct stat *st) { return diff; } -static int read_item(struct config *conf, int ncols, char **vals, char **cols, - struct nitem *n) { - char *val; - struct passwd *pw; - struct group *gr; - struct nitem zero = { 0 }; - *n = zero; +/* 0 = not acceptable + * 1 = accept and create/update/remove + * 2 = accept as is + * 3 = remove and overwrite + * 4 = update metadata + */ +static int acceptable(struct config *conf, unsigned int diffs, int op) { + int exist = (!(diffs & D_NOEXIST)); + int sametype = (!(diffs & D_TYPE)); + int mdsame = (!(diffs & D_MD)); + int hashsame = (!(diffs & D_HASH)); + int isdir = (diffs & D_ISDIR); - val = COL("op"); - if (!val) { - seterror(conf, "can't determine op"); - return 0; - } - n->opstr = val; - n->op = getop(val); - if (!n->op) { - seterror(conf, "can't determine op"); - return 0; + if (!exist) { + return op == OP_REMOVE ? 2 : 1; } - n->path = COL("path"); - if (!n->path) { - seterror(conf, "no file path"); - return 0; + if (op == OP_UPDATE) { + return sametype ? 4 : 3; } - if (strlen(n->path) == 0) { - seterror(conf, "zero length path not allowed"); - return 0; + + if (op == OP_REMOVE) { + return 1; } - /* TODO config to dishonor setuid/setgid */ - n->dest = COL("dest"); - if (!n->dest) { - seterror(conf, "no file dest"); - return 0; + /* the hard cases, should be installing new, but already exists */ + + if (!sametype) { + return conf->overwrite ? 3 : 0; } - if (strlen(n->dest) == 0) { - seterror(conf, "zero length dest not allowed"); - return 0; + if (mdsame && (conf->accept || conf->overwrite)) { + return 1; } - val = COL("mode"); + if (isdir) { + if (mdsame || conf->ignoredirmd) { + return conf->acceptdir ? 2 : 0; + } + if (conf->overwrite) { + return 4; + } + } - if (!val) { - seterror(conf, "can't determine mode"); - return 0; + if (hashsame && (conf->accept || conf->overwrite)) { + return 1; } - n->mode = strtoul(val, NULL, 8); + return conf->overwrite ? 3 : 0; +} - val = COL("configuration"); - if (!val) { - seterror(conf, "can't determine config status"); - return 0; +static int check_existing(void *f, int ncols, char **vals, char **cols) { + struct config *conf = f; + struct stat st; + struct nitem nitem; + + if (!read_item(conf, ncols, vals, cols, &nitem)) { + fprintf(stderr, "can't read item\n"); + return conf->errabort; } - n->configuration = strtoul(val, NULL, 10); - val = COL("filetype"); - if (!val || strlen(val) == 0) { - seterror(conf, "can't determine file type"); + if (conf->verbose > 1) { + fprintf(stderr, "check for existing %s\n", nitem.path); + } + + if (lstat(nitem.path, &st) == -1) { + switch(errno) { + /* not an error, file shouldn't exist*/ + case ENOENT: break; + default: + fprintf(stderr, "unable to check %s: %s\n", + nitem.path, strerror(errno)); + conf->errors++; + break; + } return 0; } - n->ftype = *val; - /* these can be null */ - n->ohash = COL("ohash"); - n->mds = COL("mds"); - n->omds = COL("omds"); - n->pkglist = COL("pkglist"); + unsigned int diffs = file_compare(&nitem, &st); + if (diffs >= D_ERROR) { + return seterror(conf, "can't check %s", nitem.dest); + } - if (n->ftype == 'r') { - n->hash = COL("hash"); - if (!n->hash) { - seterror(conf, "can't get hash"); - return 0; - } - } else if (n->ftype == 'l') { - n->target = COL("target"); - if (!n->target) { - seterror(conf, "can't get target"); - return 0; - } - if (strlen(n->target) == 0) { - seterror(conf, "zero length target not allowed"); - return 0; + int action = acceptable(conf, diffs, nitem.op); + if (!action) { + if (conf->accept) { + fprintf(stderr, "%s exists and is not acceptable\n", nitem.path); + } else { + fprintf(stderr, "%s exists\n", nitem.path); } - n->hash = n->target; + conf->errors++; } - if (conf->setuser) { - val = COL("username"); - if (!val) { - seterror(conf, "no username"); - return 0; - } - pw = getpwnam(val); - if (!pw) { - seterror(conf, "no passwd entry"); - return 0; + return 0; +} + +static int remove_files(void *f, int ncols, char **vals, char **cols) { + struct config *conf = f; + char *dest; + struct stat st; + int flags = 0; + + dest = COL("dest"); + if (!dest) return seterror(conf,"no file dest"); + + if (conf->dryrun) { + char *ftype = COL("filetype"); + int t = *ftype; + + switch(t) { + case 'd': printf("rmdir %s\n", dest); break; + default: printf("unlink %s\n", dest); break; } - n->uid = pw->pw_uid; - } else { - n->uid = geteuid(); + fflush(stdout); + return 0; } - if (conf->setgroup) { - val = COL("groupname"); - if (!val) { - seterror(conf, "no groupname"); - return 0; - } - gr = getgrnam(val); - if (!gr) { - seterror(conf, "no group entry"); - return 0; - } - n->gid = gr->gr_gid; - } else { - n->gid = getegid(); + if (lstat(dest, &st) == -1) { + return seterror(conf,"can't stat"); } - errno = 0; - double mtime = strtod(COL("mtime"),NULL); - if (errno) { - mtime = (double)time(NULL); + if (S_ISDIR(st.st_mode)) { + flags = AT_REMOVEDIR; } + /* TODO check that expected filetype matches actual filetype */ - n->mtime = (time_t)mtime; + if (conf->verbose) { + fprintf(stderr, "%s(%s)\n", flags ? "rmdir" : "unlink", dest); + } - n->times[0].tv_sec = 0; - n->times[0].tv_nsec = UTIME_OMIT; - n->times[1].tv_sec = (time_t)llrint(floor(mtime)); - n->times[1].tv_nsec = lrint(floor(fmod(mtime,1.0)*1000000000)); + errno = 0; - return 1; + if (unlinkat(AT_FDCWD, dest, flags) == -1) { + switch (errno) { + case ENOENT: + break; + default: + return seterror(conf, "can't unlink"); + } + } + + return 0; } +#define MARK fprintf(stderr, "%s %d: mark\n", __func__, __LINE__) + + static int remove_dir(struct config *conf, char *path) { int rv; @@ -583,9 +668,11 @@ static int set_md(struct config *conf, struct nitem *item) { int success = 0; if (conf->dryrun) { - printf("chmod %o %s\n", item->mode, item->dest); + if (item->ftype != 'l') { + printf("chmod %o %s\n", item->mode, item->dest); + } if (conf->setuser && conf->setgroup) { - printf("chown %d:%d %s\n", item->uid, item->gid, + printf("lchown %d:%d %s\n", item->uid, item->gid, item->dest); } printf("mtime %.0f %s\n", (double)item->mtime, item->dest); @@ -593,17 +680,20 @@ static int set_md(struct config *conf, struct nitem *item) { return success; } - rv = chmod(item->dest, item->mode); + /* can't chmod a symlink */ + if (item->ftype != 'l') { + rv = chmod(item->dest, item->mode); - if (rv == -1) { - setsyserr(conf, "can't chmod %o %s", item->mode, item->dest); - return conf->errabort; + if (rv == -1) { + setsyserr(conf, "can't chmod %o %s", item->mode, item->dest); + return conf->errabort; + } } if (conf->setuser && conf->setgroup) { - rv = chown(item->dest, item->uid, item->gid); + rv = lchown(item->dest, item->uid, item->gid); if (rv == -1) { - setsyserr(conf, "can't chown %s", item->dest); + setsyserr(conf, "can't lchown %s", item->dest); return conf->errabort; } } @@ -652,9 +742,13 @@ static int install(struct config *conf, struct nitem *item, unsigned int flags) printf("rmdir %s\n", item->dest); } - printf("install %c%o %d:%d %s -> %s\n", item->ftype, - item->mode, item->uid, item->gid, item->path, + printf("install %c%o %d:%d %s", item->ftype, + item->mode, item->uid, item->gid, item->dest); + if (item->ftype == 'l') { + printf(" -> %s", item->target); + } + printf("\n"); fflush(stdout); return success; } @@ -709,12 +803,126 @@ static int install(struct config *conf, struct nitem *item, unsigned int flags) return success; } +/* + * figure out what the difference is for a config file, only called + * for an update of a configuration file + * return -1 on an error + * return 1 if the new file should not be installed + * return 0 if the new file should be installed + */ +static int adjust_for_config(struct config *conf, struct nitem *n, unsigned int + diffs) { + + if (!n->oldwasconf) { + return 0; + } + + /* TODO what if old was a directory? */ + if (!n->configuration) { + /* replacing conf with non-conf */ + /* absorb file, mark todo */ + char hash[ZPM_HASH_STRLEN+1]; + if (!conf->dryrun) { + if (conf->verbose) { + fprintf(stderr, "importing old conf file\n"); + } + if (zpm_import(conf->log, n->dest, 0, hash)) { + zpm_note_add(conf->log, n->pkglist, n->dest, hash, + "replaced config file with non-config. zpm-cat %.8s", hash); + } else { + fprintf(stderr, "unable to import existing config file %s\n", n->dest); + return -1; + } + } else { + fprintf(stderr, "dry-run: would replace config file %s with non-config file\n", n->dest); + } + return 0; + } + + int sametype = (!(diffs & D_TYPE)); + int isdir = (diffs & D_ISDIR); + int eisdir = (diffs & D_EISDIR); + + /* both old and new are config files */ + if (isdir && sametype) { + /* both config directories, can only be changing + * metadata, so no adjustment needed + */ + if (conf->verbose) { + fprintf(stderr, "both config dirs, ok to update\n"); + } + return 0; + } + + if (isdir) { + char hash[ZPM_HASH_STRLEN+1]; + + /* replacing old file with new directory */ + /* absorb, make note */ + if (!conf->dryrun) { + if (zpm_import(conf->log, n->dest, 0, hash)) { + zpm_note_add(conf->log, n->pkglist, n->dest, hash, + "replaced config file with config directory. zpm-cat %.8s", hash); + } else { + fprintf(stderr, "unable to import existing config file %s\n", n->dest); + return -1; + } + } else { + fprintf(stderr, "dry-run: would replace config file %s with config directory\n", n->dest); + } + return 0; + } + + if (eisdir) { + /* replacing old conf directory with a conf file. + * nothing needs to be done, if the directory + * is empty, it's ok to remove. if it's not empty, + * the install will fail + */ + return 0; + } + + /* replacing old file with new file */ + /* new is same as on disk */ + if (!(diffs & D_HASH)) { + if (conf->verbose) { + fprintf(stderr, "new config file is already on disk, probably shouldn't happen\n"); + } + return 0; + } + + /* new is different than on disk, but on disk is same as old */ + if (!(diffs & D_OHASH)) { + if (conf->verbose) { + fprintf(stderr, "old config file not changed from default, replacing with new default\n"); + } + /* ok to do the update, since same as default */ + fprintf(stderr, "updating default config %s\n", n->dest); + return 0; + } + + /* new is different than on disk, and disk different than old */ + /* log */ + if (conf->verbose) { + fprintf(stderr, "new default config file is different than on disk, and old default was changed, should keep on-disk config\n"); + } + if (!conf->dryrun) { + zpm_note_add(conf->log, n->pkglist, n->dest, n->hash, + "default config file update. zpm-cat %.8s", n->hash); + /* TODO check for note error */ + } else { + fprintf(stderr, "dry-run: default config file %s update\n", + n->dest); + } + return 1; + +} + static int install_files(void *f, int ncols, char **vals, char **cols) { struct config *conf = f; struct nitem nitem; struct stat existing; int update = 0; - char dest[4096]; /* TODO put the result row in a hash table. May not actually * be faster @@ -724,6 +932,12 @@ static int install_files(void *f, int ncols, char **vals, char **cols) { return conf->errabort; } +#if 0 + int64_t used, high; + used = sqlite3_memory_used()/1024/1024; + high = sqlite3_memory_highwater(0)/1024/1024; + fprintf(stderr, "memory = %ld MB / %ld MB\n", used, high); +#endif if (conf->verbose && !conf->dryrun) { fprintf(stderr, "%s '%c' %s\n", nitem.opstr, nitem.ftype, nitem.dest); @@ -764,7 +978,7 @@ static int install_files(void *f, int ncols, char **vals, char **cols) { int hashsame = (!(diffs & D_HASH)); int isdir = (diffs & D_ISDIR); int eisdir = (diffs & D_EISDIR); - int accept = conf->absorb; + int accept = conf->accept; int overwrite = conf->overwrite; int installing = (nitem.op == OP_NEW); update = (nitem.op == OP_UPDATE); @@ -776,28 +990,12 @@ static int install_files(void *f, int ncols, char **vals, char **cols) { return install(conf, &nitem, 3); } - if (nitem.configuration) { - /* ohash == nhash, not an update */ - /* fhash == ohash, just update */ - /* fhash != ohash, install as dest.zpmnew, warn */ - /* TODO handle replacing config file - * with config directory */ - /* We don't have the information as to which - * package this is a config file for, so - * we'll need to look it up. - */ - if (diffs & D_OHASH) { - zpm_note_add(conf->log, nitem.pkglist, - nitem.path, nitem.hash, - "default config file update installed as %s.zpmnew", nitem.dest); - - if (strlen(nitem.dest) > sizeof dest - 8) { - return seterror(conf,"config file path too long for install as %s.zpmnew", nitem.dest); - } - fprintf(stderr, "installing as .zpmnew\n"); - sprintf(dest, "%s.zpmnew", nitem.dest); - nitem.dest = dest; - } + switch (adjust_for_config(conf, &nitem, diffs)) { + case -1: return conf->errabort; break; + case 1: + fprintf(stderr, "skipping changed default config file: %s\n", nitem.dest); + return 0; break; + default: break; } /* file exists in filesystem */ @@ -861,6 +1059,7 @@ static int install_files(void *f, int ncols, char **vals, char **cols) { return install(conf, &nitem, 7); } /* error, should not be possible, assert(0)? */ + fprintf(stderr,"impossible state: %s:%d\n", __func__, __LINE__); } if (installing) { @@ -873,23 +1072,58 @@ static int install_files(void *f, int ncols, char **vals, char **cols) { if (mdsame && hashsame && (accept || overwrite)) { /* do nothing */ if (conf->dryrun || conf->verbose) { - fprintf(stderr, "accepting existing file: %s\n", nitem.dest); + fprintf(stderr, "accept %s: %s\n", + eisdir ? "directory" : "file", nitem.dest); } return 0; } + + if (mdsame && isdir && conf->acceptdir) { + return 0; + } + + if (!mdsame && isdir && conf->ignoredirmd) { + /* TODO warn ignoring dir md */ + return 0; + } + if (mdsame && hashsame && !(accept || overwrite)) { /* error */ - return seterror(conf, "will not accept or overwrite existing file: %s", nitem.dest); + return seterror(conf, "file exists: %s", nitem.dest); } + if (mdsame && !hashsame && overwrite) { /* install */ return install(conf, &nitem, eisdir ? 11 : 7); } + + if (nitem.configuration && accept) { + /* accept a changed config file */ + if (conf->dryrun || conf->verbose) { + fprintf(stderr, "accept %smodified config %s: %s\n", (!mdsame || !hashsame) ? "" : "un", + eisdir ? "directory" : "file", nitem.dest); + } + return 0; + } + if (mdsame && !hashsame && !overwrite) { /* accept doesn't matter, since it's * not an acceptable file */ /* error */ - return seterror(conf, "%s (hashdiff): %s", accept ? "existing file not acceptable" : "file exists", nitem.dest); + if (nitem.ftype == 'l') { + char link[1024]; + ssize_t lsize; + lsize = readlink(nitem.dest, link, sizeof link); + if (lsize == -1 || (size_t)lsize >= sizeof link) { + return seterror(conf, "%s (linkdiff): expecting %s -> %s, unable to read link", accept ? "existing file not acceptable" : "file exists", nitem.dest, nitem.target, link); + } else { + link[lsize] = 0; + /* links must be different */ + return seterror(conf, "%s (linkdiff): expecting %s -> %s, have -> %s", accept ? "existing file not acceptable" : "file exists", nitem.dest, nitem.target, link); + } + } else { + return seterror(conf, "%s (hashdiff): %s", accept ? "existing file not acceptable" : "file exists", nitem.dest); + } } if (!mdsame && hashsame && overwrite) { /* fix md */ @@ -1087,7 +1321,8 @@ int main(int ac, char **av){ conf.rootdir = 0; conf.reverse = 0; conf.overwrite = 0; - conf.absorb = 0; + conf.accept = 0; + conf.acceptdir = 1; if (geteuid() != 0) { conf.setuser = 0; @@ -1114,7 +1349,7 @@ int main(int ac, char **av){ * args are pkgid triple, but will do a pkg find on the pkgdb */ - while ((opt = getopt(ac, av, "f:d:c:nCR:vOA")) != -1) { + while ((opt = getopt(ac, av, "f:d:c:nCR:vOAMD")) != -1) { switch (opt) { case 'd': localdbfile = optarg; break; case 'f': pkgdbfile = optarg; break; @@ -1124,7 +1359,9 @@ int main(int ac, char **av){ case 'R': conf.rootdir = optarg; break; case 'N': conf.setuser = 0; conf.setgroup = 0; break; case 'O': conf.overwrite = 1; break; - case 'A': conf.absorb = 1; break; + case 'A': conf.accept = 1; break; + case 'M': conf.ignoredirmd = 1; + case 'D': conf.acceptdir = 0; default: usage(); exit(EXIT_FAILURE); @@ -1144,6 +1381,7 @@ int main(int ac, char **av){ conf.log = &localdb; if (pkgdbfile) { + /* TODO open read-only */ if (!zpm_open(&pkgdb, pkgdbfile)) { fprintf(stderr, "can't open src db %s\n", localdbfile); exit(EXIT_FAILURE); @@ -1173,7 +1411,7 @@ int main(int ac, char **av){ /* no point in running it if we're just going to * overwrite everything */ - if (!conf.overwrite && !conf.absorb && !conf.dryrun) { + if (!conf.overwrite && !conf.accept && !conf.dryrun) { runstage(&conf, "new", check_existing); }