]> pd.if.org Git - zpackage/blobdiff - zpm-syncfs.c
fix chmod and chown ordering
[zpackage] / zpm-syncfs.c
index aac86b576c4a0dc33fa942fc742eb89a3d93e579..3c0eebb0ff84bc43175d528f13e08c79e0514ce6 100644 (file)
@@ -32,6 +32,9 @@ struct config {
        int reverse, exitonerror;
        int overwrite, accept, acceptdir, ignoredirmd;
        int ops_total, ops_completed;
+       int ops_remove, ops_remove_completed;
+       int ops_update, ops_update_completed;
+       int ops_install, ops_install_completed;
        int progress; /* type of progress meter */
 };
 
@@ -57,6 +60,18 @@ static void usage() {
        printf("usage: zpm $scriptname [-fncC] args ...\n");
 }
 
+static void pdots(int len, int ch, int was, int now, int total) {
+       was = len * was / total;
+       if (now > total) {
+               now = total;
+       }
+       now = len * now / total;
+       while (was++ < now) {
+               putchar(ch);
+       }
+       fflush(stdout);
+}
+
 static int seterror(struct config *conf, char *msgfmt, ...) {
        char msg[1024];
        va_list ap;
@@ -613,8 +628,31 @@ static int remove_files(void *f, int ncols, char **vals, char **cols) {
                return 0;
        }
 
+       if (conf->verbose) {
+               if (conf->progress == 2) {
+                       fprintf(stderr, "%s(%s)\n", flags ? "rmdir" : "unlink", dest);
+               } else if (conf->progress == 1) {
+                       /* overwrite */
+                       pdots(50, '.', conf->ops_completed, conf->ops_completed + 1, conf->ops_total);
+                       conf->ops_completed++;
+                       conf->ops_completed++;
+               } else {
+                       pdots(50, '.', conf->ops_completed, conf->ops_completed + 1, conf->ops_total);
+                       conf->ops_completed++;
+               }
+       }
+
+       errno = 0;
+
        if (lstat(dest, &st) == -1) {
-               return seterror(conf,"can't stat");
+               switch (errno) {
+                       case ENOENT:
+                               /* TODO chatter if verbose */
+                               break;
+                       default:
+                               return seterror(conf, "can't stat %s: %s", dest, strerror(errno));
+               }
+               return 0;
        }
 
        if (S_ISDIR(st.st_mode)) {
@@ -622,9 +660,6 @@ static int remove_files(void *f, int ncols, char **vals, char **cols) {
        }
        /* TODO check that expected filetype matches actual filetype */
 
-       if (conf->verbose) {
-               fprintf(stderr, "%s(%s)\n", flags ? "rmdir" : "unlink", dest);
-       }
 
        errno = 0;
 
@@ -632,8 +667,12 @@ static int remove_files(void *f, int ncols, char **vals, char **cols) {
                switch (errno) {
                        case ENOENT:
                                break;
+                       case ENOTEMPTY: /* fall through */
+                       case EEXIST:
+                               /* TODO chatter, or possibly require */
+                               break;
                        default:
-                               return seterror(conf, "can't unlink");
+                               return seterror(conf, "can't unlink %s: %s", dest, strerror(errno));
                }
        }
        
@@ -682,6 +721,17 @@ static int set_md(struct config *conf, struct nitem *item) {
                return success;
        }
 
+       if (conf->setuser && conf->setgroup) {
+               rv = lchown(item->dest, item->uid, item->gid);
+               if (rv == -1) {
+                       setsyserr(conf, "can't lchown %s", item->dest);
+                       return conf->errabort;
+               }
+       }
+
+       /* have to chmod after the chown, setuid bits may (and will)
+        * be cleared after a chown
+        */
        /* can't chmod a symlink */
        if (item->ftype != 'l') {
                rv = chmod(item->dest, item->mode);
@@ -692,13 +742,6 @@ static int set_md(struct config *conf, struct nitem *item) {
                }
        }
 
-       if (conf->setuser && conf->setgroup) {
-               rv = lchown(item->dest, item->uid, item->gid);
-               if (rv == -1) {
-                       setsyserr(conf, "can't lchown %s", item->dest);
-                       return conf->errabort;
-               }
-       }
 
        rv = utimensat(AT_FDCWD, item->dest, item->times, AT_SYMLINK_NOFOLLOW);
        if (rv == -1) {
@@ -775,16 +818,11 @@ static int install(struct config *conf, struct nitem *item, unsigned int flags)
                }
        }
 
-       if (item->ftype == 'r') {
-               rv = zpm_extract(source, item->hash, item->dest, item->mode);
-               if (rv == 0) {
-                       seterror(conf, "can't extract %s", item->dest);
-                       return failure;
-               }
-               return success;
-       }
-
+       errno = 0;
        switch (item->ftype) {
+               case 'r': rv = zpm_extract(source, item->hash, item->dest, item->mode);
+                         if (rv == 0) rv = -1;
+                         break;
                case 'd': rv = mkdir(item->dest, item->mode);
                          break;
                case 'l': rv = symlink(item->target, item->dest);
@@ -794,6 +832,17 @@ static int install(struct config *conf, struct nitem *item, unsigned int flags)
        }
 
        if (rv == -1) {
+               switch (item->ftype) {
+                       case 'r':
+                               seterror(conf, "can't extract %s", item->dest);
+                               break;
+                       case 'd':
+                               setsyserr(conf, "install mkdir(\"%s\") failed", item->dest);
+                               break;
+                       case 'l':
+                               setsyserr(conf, "install symlink(\"%s\") failed", item->dest);
+                               break;
+               }
                setsyserr(conf, "installing %s failed", item->dest);
                return failure;
        }
@@ -946,20 +995,11 @@ static int install_files(void *f, int ncols, char **vals, char **cols) {
                                        nitem.dest);
                } else if (conf->progress == 1) {
                        /* overwrite */
-                       /* one dot per 2% */
-                       int was = 50 * conf->ops_completed / conf->ops_total;
-                       int now = 50 * (conf->ops_completed+1) / conf->ops_total;
-                       while (was++ < now) {
-                               fprintf(stderr, ".");
-                       }
+                       pdots(50, '.', conf->ops_completed, conf->ops_completed + 1, conf->ops_total);
+                       conf->ops_completed++;
                        conf->ops_completed++;
                } else {
-                       /* one dot per 2% */
-                       int was = 50 * conf->ops_completed / conf->ops_total;
-                       int now = 50 * (conf->ops_completed+1) / conf->ops_total;
-                       while (was++ < now) {
-                               fprintf(stderr, ".");
-                       }
+                       pdots(50, '.', conf->ops_completed, conf->ops_completed + 1, conf->ops_total);
                        conf->ops_completed++;
                }
        }
@@ -1321,8 +1361,11 @@ static void runstage(struct config *conf, char *stage,
        /* TODO final report function in conf var */
 }
 
-static int count_ops(struct config *conf) {
-       return zpm_db_int(conf->log, "select count(*) from syncinfo where op in ('remove', 'update', 'new')");
+static void count_ops(struct config *conf) {
+       conf->ops_remove = zpm_db_int(conf->log, "select count(*) from syncinfo where op = 'remove'");
+       conf->ops_update = zpm_db_int(conf->log, "select count(*) from syncinfo where op = 'update'");
+       conf->ops_install = zpm_db_int(conf->log, "select count(*) from syncinfo where op = 'new'");
+       conf->ops_total = conf->ops_remove + conf->ops_update + conf->ops_install;
 }
 
 int main(int ac, char **av) {
@@ -1452,25 +1495,48 @@ int main(int ac, char **av) {
                if (!conf.errors) {
                        conf.exitonerror = conf.dryrun ? 0 : 1;
                        conf.errabort = conf.dryrun ? 0 : 1;
-                       conf.reverse = 1;
-                       conf.ops_total = count_ops(&conf);
+                       count_ops(&conf);
                        fprintf(stderr, "file ops: %d\n", conf.ops_total);
-                       if (conf.verbose) {
-                               fprintf(stderr, "removing old files\n");
-                       }
-                       runstage(&conf, "remove", remove_files);
-                       conf.reverse = 0;
-                       if (conf.verbose) {
-                               fprintf(stderr, "updating files\n");
+                       if (conf.ops_remove > 0) {
+                               if (conf.verbose) {
+                                       fprintf(stderr, "removing %d file%s\n", conf.ops_remove, conf.ops_remove > 0 ? "s" : "");
+                               }
+                               conf.reverse = 1;
+                               conf.ops_completed = 0;
+                               conf.ops_total = conf.ops_remove;
+                               runstage(&conf, "remove", remove_files);
+                               if (conf.verbose && conf.progress < 2) {
+                                       fprintf(stderr, " done\n");
+                                       fflush(stderr);
+                               }
                        }
-                       runstage(&conf, "update", install_files);
-                       if (conf.verbose) {
-                               fprintf(stderr, "installing %d files\n", conf.ops_total);
+
+                       if (conf.ops_update > 0) {
+                               if (conf.verbose) {
+                                       fprintf(stderr, "updating %d file%s\n", conf.ops_update, conf.ops_update > 0 ? "s" : "");
+                               }
+                               conf.reverse = 0;
+                               conf.ops_completed = 0;
+                               conf.ops_total = conf.ops_update;
+                               runstage(&conf, "update", install_files);
+                               if (conf.verbose && conf.progress < 2) {
+                                       fprintf(stderr, " done\n");
+                                       fflush(stderr);
+                               }
                        }
-                       runstage(&conf, "new", install_files);
-                       if (conf.verbose && conf.progress < 2) {
-                               fprintf(stderr, " done\n");
-                               fflush(stderr);
+
+                       if (conf.ops_install > 0) {
+                               if (conf.verbose) {
+                                       fprintf(stderr, "installing %d file%s\n", conf.ops_install, conf.ops_install > 0 ? "s" : "");
+                               }
+                               conf.reverse = 0;
+                               conf.ops_completed = 0;
+                               conf.ops_total = conf.ops_install;
+                               runstage(&conf, "new", install_files);
+                               if (conf.verbose && conf.progress < 2) {
+                                       fprintf(stderr, " done\n");
+                                       fflush(stderr);
+                               }
                        }
                }
        }