1 #define _POSIX_C_SOURCE 200809L
15 /* needed for S_IFMT and AT_FDCWD */
24 struct zpm *log; /* logging db will be attached as "log" */
29 int errcontinue, errors, verbose, dryrun;
30 int setuser, setgroup;
31 int reverse, exitonerror;
35 printf("usage: zpm $scriptname [-fncC] args ...\n");
38 static int exists(char *path, mode_t *mode) {
41 if (lstat(path, &st) == -1) {
44 if (mode) *mode = st.st_mode;
48 /* TODO maintain a list of already created directories */
49 static int create_leading_dirs(char *path) {
52 char pcopy[ZPM_PATH_MAX];
57 delim = strrchr(pcopy, '/');
58 if (!delim) return 1; /* not an error, but no leading dirs */
60 /* cut off last component */
69 delim = strchr(s, '/');
75 /* try to create the directory, if it exists
76 * and is a directory or a symlink, that's ok
78 if (mkdir(pcopy, 0755) == -1) {
81 if (lstat(pcopy, &st) == -1) {
85 switch (st.st_mode & S_IFMT) {
106 char *column(char *col, int ncols, char **vals, char **cols) {
110 for (i=0; i < ncols; i++) {
111 // fprintf(stderr, "checking '%s' = '%s'\n", cols[i], vals[i]);
113 if (!strcmp(col, cols[i])) {
121 #define IERR(x) do { conf->log->errmsg = strdup(x); return !conf->errcontinue; } while (0)
122 #define COL(x) column(x, ncols, vals, cols)
123 #define SYSERR(x) do { conf->log->error = 2; return conf->errcontinue; } while (0)
125 static char *ops[] = { "new", "remove", "update", 0 };
127 static int getop(char *opstr) {
130 if (!opstr) return 0;
131 for (i=0;ops[i];i++) {
132 if (!strcmp(opstr, ops[i])) {
139 static int report_conflicts(void *f, int ncols, char **vals, char **cols) {
140 struct config *conf = f;
148 fprintf(stderr, "%s owned by %s\n", path, pkg);
152 static int check_existing(void *f, int ncols, char **vals, char **cols) {
153 struct config *conf = f;
158 if (!path) IERR("can't check for existing");
161 printf("checkfor %s\n", path);
165 if (lstat(path, &st) == 0) {
166 fprintf(stderr, "%s exists \n", path);
170 /* not an error, file shouldn't exist*/
173 fprintf(stderr, "unable to check %s: %s\n",
174 path, strerror(errno));
182 static int update_files(void *f, int ncols, char **vals, char **cols) {
183 struct config *conf = f;
189 if (!pkg) IERR("can't get pkgid");
191 if (!path) IERR("can't get path");
193 if (!dest) IERR("no file dest");
195 /* hash is different, so no different than install,
196 * but we don't need to create leading directories
200 fprintf(stderr, "update %s\n", dest);
204 fprintf(stderr, "update not implemented: %s", dest);
210 static int remove_files(void *f, int ncols, char **vals, char **cols) {
211 struct config *conf = f;
216 if (!dest) IERR("no file dest");
219 char *ftype = COL("filetype");
223 case 'd': printf("rmdir %s\n", dest); break;
224 default: printf("unlink %s\n", dest); break;
229 if (lstat(dest, &st) == -1) {
233 if (S_ISDIR(st.st_mode)) {
234 fprintf(stderr, "rmdir %s\n", dest);
236 } else if (S_ISREG(st.st_mode)) {
237 /* TODO conf to import before removal */
239 fprintf(stderr, "unlink(%s)\n", dest);
249 static int install_files(void *f, int ncols, char **vals, char **cols) {
250 struct config *conf = f;
264 /* TODO put the result row in a hash table. May not actually
269 if (op == 0) IERR("invalid operation");
271 /* TODO config to dishonor setuid/setgid */
273 if (!path) IERR("no file path");
275 if (!dest) IERR("no file dest");
279 if (!val) IERR("can't determine mode");
280 mode = strtoul(val, NULL, 8);
282 val = COL("filetype");
284 IERR("can't determine file type");
290 if (!hash) IERR("can't get hash");
297 val = COL("username");
298 if (!val) IERR("no username");
300 if (!pw) IERR("no passwd entry");
303 if (conf->setgroup) {
304 val = COL("groupname");
305 if (!val) IERR("no groupname");
307 if (!gr) IERR("no group entry");
312 //printf("cld %s\n", path);
313 printf("new %c%o %d:%d %s -> %s\n", ftype, mode, uid, gid, path, dest);
317 /* TODO should these be owned by the path owner if they don't exist? */
318 /* probably, though they then belong to the package, sort of */
319 if (!create_leading_dirs(dest)) {
320 fprintf(stderr, "unable to create leading directories for %s\n",
326 if (mkdir(dest, mode) == -1) {
329 } else if (ftype == 'r') {
331 source = conf->src ? conf->src : conf->log;
332 if (conf->verbose > 1) {
333 fprintf(stderr, "extracting %8.8s to %s with mode %o\n",
336 if (!zpm_extract(source, hash, dest, mode)) {
337 IERR("can't extract file");
341 if (conf->setuser && conf->setgroup) {
342 if (chown(dest, uid, gid) == -1) {
347 struct timespec times[2] = { 0 };
348 double mtime = strtod(COL("mtime"),NULL);
350 times[0].tv_nsec = UTIME_OMIT;
351 times[1].tv_sec = (time_t)llrint(floor(mtime));
352 times[1].tv_nsec = lrint(floor(fmod(mtime,1.0)*1000000000));
354 utimensat(AT_FDCWD, dest, times, AT_SYMLINK_NOFOLLOW);
357 printf("%s\n", path);
363 static void runstage(struct config *conf, char *stage,
364 int (callback)(void *, int, char **, char **)) {
370 s = sqlite3_str_new(conf->log->db);
371 sqlite3_str_appendall(s, "select *, ");
373 sqlite3_str_appendf(s, "printf('%%s/%%s',rtrim(%Q,'/'),ltrim(path,'/'))", conf->rootdir);
375 sqlite3_str_appendf(s, "printf('/%%s', trim(path, '/'))");
377 sqlite3_str_appendall(s, " as dest from install_status");
380 sqlite3_str_appendf(s," where op = %Q", stage);
383 sqlite3_str_appendall(s," order by length(path) desc, path desc");
386 sql = sqlite3_str_value(s);
387 if (conf->verbose > 2) {
388 fprintf(stderr, "stage query: %s\n", sql);
391 rv = zpm_exec(conf->log, sql, callback, conf, &errmsg);
393 sqlite3_str_finish(s);
396 fprintf(stderr, "exec fail: %s\n", sqlite3_errstr(rv));
398 fprintf(stderr, "database error: %s\n", errmsg);
401 if (conf->log->error == 1) {
402 fprintf(stderr, "unable to allocate memory\n");
404 fprintf(stderr, "zpm_exec failure: %s\n",
405 conf->log->errmsg ? conf->log->errmsg : "unknown");
408 if (conf->log->errmsg) {
409 fprintf(stderr, "error: %s\n", conf->log->errmsg);
411 if (conf->errors && conf->exitonerror) {
412 zpm_close(conf->log);
413 zpm_close(conf->src);
416 /* TODO final report function in conf var */
419 int main(int ac, char **av){
423 char *pkgdbfile = 0, *localdbfile = 0;
428 conf.errcontinue = 0;
439 if (geteuid() != 0) {
444 localdbfile = ZPM_LOCAL_DB;
445 if ((s = getenv("ZPMDB"))) {
446 /* TODO does this need to be copied ? */
450 if ((s = getenv("ZPM_ROOT_DIR"))) {
451 /* TODO does this need to be copied ? */
456 * -d localdb or ZPMDB * or /var/lib/zpm/zpm.db, or die
457 * -f 'package database', otherwise regular default of env
458 * ZPM_PACKAGE_FILE, or use pkgdb if otherwise not found
459 * -R root of pkg, will just chdir there
461 * args are pkgid triple, but will do a pkg find on the pkgdb
464 while ((opt = getopt(ac, av, "f:d:c:nCR:v")) != -1) {
466 case 'd': localdbfile = optarg; break;
467 case 'f': pkgdbfile = optarg; break;
468 case 'n': conf.dryrun = 1; break;
469 case 'v': conf.verbose++; break;
470 case 'C': conf.errcontinue = 1; break;
471 case 'R': conf.rootdir = optarg; break;
472 case 'N': conf.setuser = 0; conf.setgroup = 0; break;
480 /* verify root dir exists */
481 if (conf.rootdir && !exists(conf.rootdir, NULL)) {
482 fprintf(stderr, "rootdir %s does not exist\n", conf.rootdir);
487 conf.pkgid = av[argn];
490 fprintf(stderr, "must specify pkgid\n");
495 if (!zpm_open(&localdb, localdbfile)) {
496 fprintf(stderr, "can't open zpm db %s\n", localdbfile);
502 if (!zpm_open(&pkgdb, pkgdbfile)) {
503 fprintf(stderr, "can't open src db %s\n", localdbfile);
510 /* TODO find pkgid from arg */
512 /* TODO set conf var to finalize error reporting */
514 fprintf(stderr, "installing %s (ldb %s) from %s\n",
515 conf.pkgid, localdbfile, pkgdbfile);
519 conf.exitonerror = 0;
520 runstage(&conf, "conflict", report_conflicts);
521 runstage(&conf, "new", check_existing);
524 conf.exitonerror = 1;
525 runstage(&conf, "new", install_files);
526 runstage(&conf, "update", update_files);
528 runstage(&conf, "remove", remove_files);
534 return conf.errors ? 1 : 0;