tpm.c - pm - barely a pack manager
 (HTM) git clone git://z3bra.org/pm
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       tpm.c (20146B)
       ---
            1 #include <errno.h>
            2 #include <dirent.h>
            3 #include <fcntl.h>
            4 #include <limits.h>
            5 #include <regex.h>
            6 #include <stdio.h>
            7 #include <stdlib.h>
            8 #include <string.h>
            9 #include <sys/mman.h>
           10 #include <sys/stat.h>
           11 #include <sys/types.h>
           12 #include <sys/wait.h>
           13 
           14 #include <archive.h>
           15 #include <archive_entry.h>
           16 
           17 #include "arg.h"
           18 #include "config.h"
           19 
           20 #define log(l,...) if(verbose>=l){printf(__VA_ARGS__);}
           21 
           22 struct pack {
           23         char *path;
           24         char *name;
           25         char *version;
           26 };
           27 
           28 /* possible actions */
           29 enum {
           30         ACTION_INVALID     = -1,
           31         ACTION_INSTALL     = 0,
           32         ACTION_DELETE      = 1,
           33         ACTION_UPDATE      = 2,
           34         ACTION_INSPECT     = 3,
           35         ACTION_DEFAULT     = ACTION_INSPECT,
           36 };
           37 
           38 /* error codes */
           39 enum {
           40         ERR_INVALID_ACTION = 1,
           41         ERR_METADATA       = 2,
           42         ERR_PACK_LOAD      = 3,
           43         ERR_DELETE         = 4,
           44         ERR_INSPECT        = 5,
           45         ERR_UNPACK         = 6,
           46 };
           47 
           48 enum {
           49         LOG_NONE    = 0,
           50         LOG_INFO    = 1,
           51         LOG_VERBOSE = 2,
           52         LOG_DEBUG   = 3
           53 };
           54 
           55 void usage(char *name);
           56 int is_empty(char *dir);
           57 int mkdir_parents(char *dir, mode_t mode);
           58 char *base_name(char *path);
           59 int re_match(const char *re, const char *str);
           60 
           61 struct pack *pack_load_tarball(char *path);
           62 struct pack *pack_load_metadata(const char *datadir, char *name);
           63 void pack_free(struct pack *p);
           64 #ifdef REPOAWARE
           65 int  pack_find(char *, char *);
           66 #endif
           67 int pack_extract(const char *rootfs, const char *datadir, struct pack *p);
           68 int pack_install(const char *rootfs, const char *datadir, struct pack *p);
           69 int pack_delete(const char *rootfs, const char *datadir, struct pack *p);
           70 
           71 int inspect_installed(const char *datadir, const char *name);
           72 int inspect_version(const char *datadir, const char *name, char version[]);
           73 int inspect_collision(const char *rootfs, struct pack *p);
           74 int inspect_files(int fd, const char *datadir, const char *name);
           75 int inspect_system(int fd, const char *datadir);
           76 
           77 int write_metadata(const char *datadir, struct pack *pack);
           78 int write_entry(struct archive *a, struct archive *w);
           79 int delete_node(char *path);
           80 int delete_content(const char *rootfs, char *map, size_t size);
           81 int delete_metadata(const char *datadir, char *name);
           82 
           83 /* action wrappers around CLI arguments */
           84 int install(const char *rootfs, const char *datadir, char *path);
           85 int update(const char *rootfs, const char *datadir, char *path);
           86 int delete(const char *rootfs, const char *datadir, char *name);
           87 int inspect(const char *datadir, const char *name);
           88 
           89 int verbose = LOG_NONE;
           90 int overwrite = 0;
           91 
           92 void
           93 usage(char *name)
           94 {
           95         fprintf(stderr, "usage: %s -adfiuv [PACK..]\n" , name);
           96 }
           97 
           98 
           99 /*
          100  * Returns 0 if a directory is empty, -1 otherwise
          101  */
          102 int
          103 is_empty(char *path)
          104 {
          105         DIR *d;
          106         struct dirent *p;
          107 
          108         if (!(d = opendir(path))) {
          109                 perror(path);
          110                 return -1;
          111         }
          112 
          113         while ((p = readdir(d))) {
          114                 if (strcmp(p->d_name, ".") && strcmp(p->d_name, "..")) {
          115                         closedir(d);
          116                         return -1;
          117                 }
          118         }
          119 
          120         closedir(d);
          121         return 0;
          122 }
          123 
          124 
          125 /*
          126  * Recursive mkdir, taken from the ii project
          127  * http://nion.modprobe.de/blog/archives/357-Recursive-directory-creation.html
          128  */
          129 int
          130 mkdir_parents(char *path, mode_t mode)
          131 {
          132         char tmp[PATH_MAX] = "";
          133         char *p = NULL;
          134         size_t len;
          135 
          136         snprintf(tmp, sizeof(tmp), "%s", path);
          137         len = strlen(tmp);
          138         if(tmp[len - 1] == '/')
          139                 tmp[len - 1] = 0;
          140         for(p = tmp + 1; *p; p++)
          141                 if(*p == '/') {
          142                         *p = 0;
          143                         mkdir(tmp, mode);
          144                         *p = '/';
          145                 }
          146         return mkdir(tmp, mode);
          147 }
          148 
          149 
          150 /*
          151  * Return a pointer to the basename, or NULL if path ends with '/'
          152  */
          153 char *
          154 base_name(char *path)
          155 {
          156         char *b = strrchr(path, '/');
          157         return b ? b + 1 : path;
          158 }
          159 
          160 
          161 /*
          162  * Check wether a string matches a regular expression
          163  */
          164 int
          165 re_match(const char *re, const char *str)
          166 {
          167         int retval = -1;
          168         regex_t preg;
          169         regmatch_t sub[1];
          170 
          171         if (regcomp(&preg, re, REG_EXTENDED)) {
          172                 fprintf(stderr, "%s: Not a valid expression\n", re);
          173                 return -1;
          174         }
          175 
          176         retval = regexec(&preg, str, 1, sub, 0);
          177         regfree(&preg);
          178 
          179         return retval;
          180 }
          181 
          182 
          183 /*
          184  * Load a pack from a tarball and return a pack structure
          185  */
          186 struct pack *
          187 pack_load_tarball(char *path)
          188 {
          189         struct stat st;
          190         struct pack *pack = NULL;
          191         char *fn, *regex = PACK_FORMAT;
          192         regex_t preg;
          193         regmatch_t sub[3];
          194         size_t i, nmatch = 3, sublen[3];
          195 
          196         fn = base_name(path);
          197         if (stat(path, &st) < 0) {
          198                 perror(path);
          199                 return NULL;
          200         }
          201 
          202         regcomp(&preg, regex, REG_EXTENDED);
          203         regexec(&preg, fn, nmatch, sub, 0);
          204 
          205         if (!(pack = malloc(sizeof(struct pack)))) {
          206                 perror(path);
          207                 regfree(&preg);
          208                 return NULL;
          209         }
          210 
          211         for (i=0; i<nmatch; i++)
          212                 sublen[i] = sub[i].rm_eo - sub[i].rm_so;
          213 
          214         pack->path    = strdup(path);
          215         pack->name    = malloc(sublen[1] + 1);
          216         pack->version = malloc(sublen[2] + 1);
          217 
          218         strncpy(pack->name, fn+sub[1].rm_so, sublen[1]);
          219         strncpy(pack->version, fn+sub[2].rm_so, sublen[2]);
          220 
          221         pack->name[sublen[1]] = 0;
          222         pack->version[sublen[2]] = 0;
          223 
          224         regfree(&preg);
          225 
          226         return pack;
          227 }
          228 
          229 
          230 /*
          231  * Load a pack from a metadata directory and return a pack structure
          232  */
          233 struct pack *
          234 pack_load_metadata(const char *datadir, char *name)
          235 {
          236         struct pack *pack = NULL;
          237         char tmp[PATH_MAX] = "";
          238 
          239         snprintf(tmp, PATH_MAX, "%s/%s", datadir, name);
          240 
          241         if (inspect_installed(datadir, name)) {
          242                 fprintf(stderr, "%s: Not installed\n", name);
          243                 return NULL;
          244         }
          245 
          246         if (!(pack = malloc(sizeof(struct pack)))) {
          247                 perror("malloc");
          248                 return NULL;
          249         }
          250 
          251         pack->name = strdup(name);
          252         pack->path = strdup(tmp);
          253         pack->version = malloc(LINE_MAX);
          254         inspect_version(datadir, pack->name, pack->version);
          255 
          256         return pack;
          257 }
          258 
          259 
          260 /*
          261  * Free a pack structure
          262  */
          263 void
          264 pack_free(struct pack *p)
          265 {
          266         if (!p)
          267                 return;
          268 
          269         if (p->path)
          270                 free(p->path);
          271         if (p->name)
          272                 free(p->name);
          273         if (p->version)
          274                 free(p->version);
          275 
          276         free(p);
          277 }
          278 
          279 
          280 #ifdef REPOAWARE
          281 /*
          282  * Find a pack filename using an external tool writing the path to the
          283  * pack to stdout.
          284  * The tool should be called as:
          285  *
          286  *        tool <name>
          287  */
          288 int
          289 pack_find(char *name, char *out)
          290 {
          291         int fd[2], status;
          292         size_t len = 0;
          293 
          294         pipe(fd);
          295         if (!fork()) {
          296                 close(1);
          297                 close(fd[0]);
          298                 dup2(fd[1], 1);
          299                 execlp(REPO_EXEC, REPO_EXEC, name, NULL);
          300         }
          301 
          302         close(fd[1]);
          303 
          304         wait(&status);
          305         if (status)
          306                 exit(1);
          307 
          308         len = read(fd[0], out, PATH_MAX);
          309         close(fd[0]);
          310 
          311         if (len < 1)
          312                 return -1;
          313 
          314         out[len - 1] = 0;
          315 
          316         return 0;
          317 }
          318 #endif
          319 
          320 
          321 /*
          322  * Extract a tarball to the given directory
          323  */
          324 int
          325 pack_extract(const char *rootfs, const char *datadir, struct pack *p)
          326 {
          327         int r, fd;
          328         struct archive *a;
          329         struct archive *w;
          330         struct archive_entry *e;
          331         char cwd[PATH_MAX] = "";
          332         char tmp[PATH_MAX] = "";
          333 
          334         int mask = ARCHIVE_EXTRACT_PERM
          335                   |ARCHIVE_EXTRACT_SECURE_NODOTDOT;
          336 
          337         snprintf(tmp, PATH_MAX, "%s/%s/files", datadir, p->name);
          338 
          339         log(LOG_DEBUG, "+ %s\n", tmp);
          340         if ((fd = open(tmp, O_WRONLY|O_CREAT|O_TRUNC, 0644)) < 0) {
          341                 perror(tmp);
          342                 return -1;
          343         }
          344 
          345         a = archive_read_new();
          346         archive_read_support_filter_gzip(a);
          347         archive_read_support_filter_bzip2(a);
          348         archive_read_support_filter_xz(a);
          349         archive_read_support_format_tar(a);
          350 
          351         /* try and open the tarball of our pack */
          352         if ((r = archive_read_open_filename(a, p->path, 0)) != ARCHIVE_OK) {
          353                 fprintf(stderr, "%s: %s\n", p->path, archive_error_string(a));
          354                 archive_read_free(a);
          355                 close(fd);
          356                 return r;
          357         }
          358 
          359         w = archive_write_disk_new();
          360         archive_write_disk_set_options(w, mask);
          361 
          362         getcwd(cwd, PATH_MAX);
          363         chdir(rootfs);
          364         log(LOG_VERBOSE, "extracting pack\n");
          365         while ((r = archive_read_next_header(a, &e)) != ARCHIVE_EOF) {
          366                 if (r != ARCHIVE_OK) {
          367                         fprintf(stderr, "%s: %s\n", archive_entry_pathname(e),
          368                                                     archive_error_string(a));
          369                         break;
          370                 }
          371 
          372                 if ((r = archive_write_header(w, e)) != ARCHIVE_OK) {
          373                         fprintf(stderr, "%s: %s\n", archive_entry_pathname(e),
          374                                                     archive_error_string(w));
          375                         break;
          376                 }
          377 
          378                 log(LOG_DEBUG, "+ %s%s\n", rootfs, archive_entry_pathname(e));
          379                 if ((r = write_entry(a, w)) != ARCHIVE_OK) {
          380                         fprintf(stderr, "%s: %s\n", archive_entry_pathname(e),
          381                                                     archive_error_string(w));
          382                         break;
          383                 }
          384 
          385                 dprintf(fd, "%s\n", archive_entry_pathname(e));
          386                 archive_write_finish_entry(w);
          387         }
          388         close(fd);
          389         chdir(cwd);
          390 
          391         archive_write_free(w);
          392         archive_read_free(a);
          393 
          394         return r == ARCHIVE_EOF ? ARCHIVE_OK : r;
          395 }
          396 
          397 
          398 /*
          399  * Install a pack to rootfs, writing metadata to datadir
          400  * If overwrite is set to 1, it will overwrite all files
          401  */
          402 int
          403 pack_install(const char *rootfs, const char *datadir, struct pack *p)
          404 {
          405         int r;
          406         char tmp[PATH_MAX] = "";
          407 
          408         if (overwrite == 0) {
          409                 snprintf(tmp, PATH_MAX, "%s/%s", datadir, p->name);
          410                 if (inspect_installed(datadir, p->name) == 0) {
          411                         fprintf(stderr, "%s: Already installed\n", p->name);
          412                         return -1;
          413                 }
          414                 if (inspect_collision(rootfs, p) != 0)
          415                         return -1;
          416         }
          417 
          418         log(LOG_VERBOSE, "writing metadata\n");
          419         if (write_metadata(datadir, p) < 0) {
          420                 delete_metadata(datadir, p->name);
          421                 return -1;
          422         }
          423 
          424         r = pack_extract(rootfs, datadir, p);
          425 
          426         if (r != 0) {
          427                 fprintf(stderr, "%s: Extraction failed\n", p->path);
          428                 pack_delete(rootfs, datadir, p);
          429         }
          430 
          431         return r;
          432 }
          433 
          434 
          435 /*
          436  * Delete a pack from the system.
          437  * This will read the file datadir/name/files, change directory to rootfs
          438  * and call delete_content()
          439  */
          440 int
          441 pack_delete(const char *rootfs, const char *datadir, struct pack *p)
          442 {
          443         int fd, r = 0;
          444         char *addr = NULL;
          445         char tmp[PATH_MAX];
          446         struct stat st;
          447 
          448         snprintf(tmp, PATH_MAX, "%s/%s/files", datadir, p->name);
          449         if (stat(tmp, &st) < 0) {
          450                 perror(tmp);
          451                 return -1;
          452         }
          453         if ((fd = open(tmp, O_RDONLY)) < 0) {
          454                 perror(tmp);
          455                 return ERR_DELETE;
          456         }
          457 
          458         if (st.st_size > 0) {
          459                 addr = mmap(0, st.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
          460                 if (addr == MAP_FAILED) {
          461                         perror("mmap");
          462                         close(fd);
          463                         return ERR_DELETE;
          464                 }
          465         
          466                 log(LOG_VERBOSE, "cleaning installed files\n");
          467                 /* ignore errors so everything gets deleted */
          468                 if (delete_content(rootfs, addr, st.st_size) < 0) {
          469                         close(fd);
          470                         r = ERR_DELETE;
          471                 }
          472                 munmap(addr, st.st_size);
          473         }
          474         close(fd);
          475 
          476         log(LOG_VERBOSE, "cleaning metadata\n");
          477         if (delete_metadata(datadir, p->name) < 0) {
          478                 fprintf(stderr, "%s/%s: %s\n", datadir, p->name, strerror(errno));
          479                 r = ERR_DELETE;
          480         }
          481 
          482         return r;
          483 }
          484 
          485 
          486 /*
          487  * Returns 0 if "name" is installed, non-zero otherwise
          488  */
          489 int
          490 inspect_installed(const char *datadir, const char *name)
          491 {
          492         char tmp[PATH_MAX] = "";
          493         struct stat st;
          494 
          495         snprintf(tmp, PATH_MAX, "%s/%s", datadir, name);
          496         log(LOG_VERBOSE, "checking existence of %s\n", tmp);
          497         return stat(tmp, &st) || !S_ISDIR(st.st_mode);
          498 }
          499 
          500 
          501 /*
          502  * Read the version file for a pack and fill the given pointer with it
          503  */
          504 int
          505 inspect_version(const char *datadir, const char *name, char version[LINE_MAX])
          506 {
          507         FILE *stream;
          508         char tmp[PATH_MAX] = "", *lf = NULL;
          509 
          510         snprintf(tmp, PATH_MAX, "%s/%s/version", datadir, name);
          511         if ((stream = fopen(tmp, "r")) == NULL) {
          512                 snprintf(version, 10, "(unknown)");
          513                 return 1;
          514         } else {
          515                 fgets(version, LINE_MAX, stream);
          516                 if ((lf = strchr(version, '\n')) != NULL)
          517                         *lf = 0;
          518         }
          519 
          520         fclose(stream);
          521 
          522         return 0;
          523 }
          524 
          525 
          526 /*
          527  * Check for collisions between the filesystem and the tarball
          528  */
          529 int
          530 inspect_collision(const char *rootfs, struct pack *p)
          531 {
          532         int r = 0;
          533         char cwd[PATH_MAX] = "";
          534         struct stat st;
          535         struct archive *a;
          536         struct archive_entry *e;
          537 
          538         a = archive_read_new();
          539         archive_read_support_filter_gzip(a);
          540         archive_read_support_filter_bzip2(a);
          541         archive_read_support_filter_xz(a);
          542         archive_read_support_format_tar(a);
          543 
          544         r = archive_read_open_filename(a, p->path, 0);
          545         if (r != ARCHIVE_OK) {
          546                 fprintf(stderr, "%s: %s\n", p->path, archive_error_string(a));
          547                 return -1;
          548         }
          549 
          550         getcwd(cwd, PATH_MAX);
          551         chdir(rootfs);
          552         while (archive_read_next_header(a, &e) == ARCHIVE_OK) {
          553                 if (stat(archive_entry_pathname(e), &st) == 0 && !S_ISDIR(st.st_mode)) {
          554                         fprintf(stderr, "%s: file exists\n", archive_entry_pathname(e));
          555                         r++;
          556                         break;
          557                 }
          558                 archive_read_data_skip(a);
          559         }
          560 
          561         archive_read_free(a);
          562         chdir(cwd);
          563 
          564         return r;
          565 }
          566 
          567 
          568 /*
          569  * Write files installed by a pack to a file descriptor
          570  */
          571 int
          572 inspect_files(int fd, const char *datadir, const char *name)
          573 {
          574         int meta;
          575         char tmp[PATH_MAX] = "";
          576         size_t len;
          577 
          578         snprintf(tmp, PATH_MAX, "%s/%s/files", datadir, name);
          579         if ((meta = open(tmp, O_RDONLY)) < 0) {
          580                 perror(tmp);
          581                 return -1;
          582         }
          583 
          584         while ((len = read(meta, tmp, PATH_MAX)) > 0) {
          585                 tmp[len] = 0;
          586                 dprintf(fd, "%s", tmp);
          587         }
          588 
          589         return 0;
          590 }
          591 
          592 
          593 /*
          594  * Write packs installed in datadir to a file descriptor
          595  */
          596 int
          597 inspect_system(int fd, const char *datadir)
          598 {
          599         DIR *d;
          600         struct dirent *p;
          601         char ver[LINE_MAX];
          602 
          603         if (!(d = opendir(datadir))) {
          604                 perror(datadir);
          605                 return -1;
          606         }
          607 
          608         while ((p = readdir(d)))
          609                 if (p->d_name[0] != '.') {
          610                         inspect_version(datadir, p->d_name, ver);
          611                         dprintf(fd, "%s", p->d_name);
          612                         if (verbose)
          613                                 dprintf(fd, "\t%s", ver);
          614                         write(fd, "\n", 1);
          615                 }
          616 
          617         closedir(d);
          618         return 0;
          619 }
          620 
          621 
          622 /*
          623  * Write metadata about a pack file:
          624  * + datadir/packname/version - version of the pack installed
          625  */
          626 int
          627 write_metadata(const char *datadir, struct pack *p)
          628 {
          629         int fd, r;
          630         struct stat st;
          631         char tmp[PATH_MAX];
          632 
          633         snprintf(tmp, PATH_MAX, "%s/%s", datadir, p->name);
          634 
          635         if (stat(tmp, &st) < 0 && errno == ENOENT) {
          636                 log(LOG_DEBUG, "+ %s\n", tmp);
          637                 if ((r = mkdir_parents(tmp, 0755)) < 0)
          638                         return r;
          639         }
          640 
          641         snprintf(tmp, PATH_MAX, "%s/%s/version", datadir, p->name);
          642 
          643         log(LOG_DEBUG, "+ %s\n", tmp);
          644         if ((fd = open(tmp, O_CREAT|O_WRONLY|O_TRUNC, 0644)) < 0) {
          645                 perror(tmp);
          646                 return -1;
          647         }
          648 
          649         r  = write(fd, p->version, strnlen(p->version, LINE_MAX));
          650         r += write(fd, "\n", 1);
          651 
          652         if (r < 1) {
          653                 perror(tmp);
          654                 close(fd);
          655                 return -1;
          656         }
          657 
          658         close(fd);
          659         return 0;
          660 }
          661 
          662 
          663 /*
          664  * Write an archive entry on the disk, thus creating the file
          665  */
          666 int
          667 write_entry(struct archive *a, struct archive *w)
          668 {
          669         int r;
          670         const void *buf;
          671         size_t len;
          672         off_t off;
          673 
          674         for (;;) {
          675                 r = archive_read_data_block(a, &buf, &len, &off);
          676                 switch (r) {
          677                 case ARCHIVE_EOF: return 0;
          678                 case ARCHIVE_OK: break;
          679                 default: return r;
          680                 }
          681 
          682                 r = archive_write_data_block(w, buf, len, off);
          683                 if (r != ARCHIVE_OK)
          684                         return r;
          685         }
          686 }
          687 
          688 
          689 /*
          690  * Deletes a node, be it a file or a directory.
          691  * In case the node doesn't exists, we're done
          692  */
          693 int
          694 delete_node(char *path)
          695 {
          696         int r = 0;
          697         struct stat st;
          698         size_t len = 0;
          699 
          700         len = strnlen(path, PATH_MAX);
          701         /* remove potential trailing '/' */
          702         if (path[len - 1] == '/')
          703                 path[--len] = 0;
          704 
          705         log(LOG_DEBUG, "- %s\n", path);
          706 
          707         /*
          708          * if path doesn't exist anymore, it's all good :)
          709          * we use lstat here so that dangling links can be delt with too
          710          */
          711         if (lstat(path, &st) < 0 && errno == ENOENT)
          712                 return 0;
          713 
          714         if (S_ISDIR(st.st_mode) && is_empty(path) == 0) {
          715                 if ((r = rmdir(path)) < 0) {
          716                         perror(path);
          717                         return r;
          718                 }
          719         }
          720 
          721         if (!S_ISDIR(st.st_mode) && (r = unlink(path)) < 0) {
          722                 perror(path);
          723                 return r;
          724         }
          725 
          726         return 0;
          727 }
          728 
          729 
          730 /*
          731  * Delete all entries listed in the given file.
          732  * if the entry doesn't exist, it will be ignored
          733  */
          734 int
          735 delete_content(const char *rootfs, char *map, size_t size)
          736 {
          737         char *path = NULL;
          738         char tmp[PATH_MAX] = "";
          739         size_t off;
          740 
          741         if (size < 1)
          742                 return -1;
          743 
          744         do {
          745                 /*
          746                  * it is assumed here that the file is POSIX and thus that
          747                  * the last char will be \n.
          748                  * This might sound stupid; but this is what pack_extract() will do.
          749                  * We read the mmap file backward until we encounter \n or the
          750                  * beginning of the file. If it's an \n, we replace it by 0 and
          751                  * process to the deletion of the inode, either with rmdir or
          752                  * unlink.
          753                  *
          754                  * When setting the path, the current offset is either at the
          755                  * start of the file, or on a 0 (freshly replaced \n). In case
          756                  * We are on a 0, the path should be set to the string just
          757                  * after (&map[off] + 1). This doesn't apply to start of file.
          758                  */
          759                 for (off=size-1; off>0 && map[off] != '\n'; off--);
          760                 map[off] = (off > 0 ? 0 : *map);
          761                 path     = (off < size-1 ? &map[off] + (off>0?1:0) : NULL);
          762 
          763                 if (path != NULL && strnlen(path, PATH_MAX) > 0) {
          764                         snprintf(tmp, PATH_MAX, "%s%s", rootfs, path);
          765                         if (delete_node(tmp) < 0)
          766                                 return ERR_DELETE;
          767                 }
          768         } while (off > 0);
          769 
          770         return 0;
          771 }
          772 
          773 
          774 /*
          775  * Delete the metadata stored for a given pack name
          776  */
          777 int
          778 delete_metadata(const char *datadir, char *name)
          779 {
          780         int i;
          781         char path[PATH_MAX] = "";
          782         char *meta[] = { "files", "version", NULL };
          783         
          784         for (i = 0; meta[i] != NULL; i++) {
          785                 snprintf(path, PATH_MAX, "%s/%s/%s", datadir, name, meta[i]);
          786                 log(LOG_DEBUG, "- %s\n", path);
          787                 if (unlink(path) < 0) {
          788                         perror(path);
          789                         return ERR_DELETE;
          790                 }
          791         }
          792 
          793         /* remove metadata directory, no matter what */
          794         snprintf(path, PATH_MAX, "%s/%s", datadir, name);
          795         log(LOG_DEBUG, "- %s\n", path);
          796         return rmdir(path);
          797 }
          798 
          799 
          800 /*
          801  * Install a pack from the given path. This wraps load/install of a pack
          802  */
          803 int
          804 install(const char *rootfs, const char *datadir, char *name)
          805 {
          806         int r = 0;
          807         char path[PATH_MAX];
          808         struct pack *p = NULL;
          809 
          810         if (re_match(PACK_FORMAT, name) != 0) {
          811 #ifdef REPOAWARE
          812                 pack_find(name, path);
          813 #else
          814                 fprintf(stderr, "%s: invalid filename\n", name);
          815                 exit(1);
          816 #endif
          817         } else {
          818                 snprintf(path, PATH_MAX, "%s", name);
          819         }
          820 
          821         if ((p = pack_load_tarball(path)) == NULL)
          822                 return ERR_PACK_LOAD;
          823 
          824         r += pack_install(rootfs, datadir, p);
          825 
          826         if (r == 0)
          827                 log(LOG_INFO, "installed %s (%s)\n", p->name, p->version);
          828 
          829         pack_free(p);
          830 
          831         return r;
          832 }
          833 
          834 
          835 /*
          836  * Update a pack. This should be as easy as delete/install.
          837  * Deletion is required in case the file structure changes
          838  */
          839 int
          840 update(const char *rootfs, const char *datadir, char *name)
          841 {
          842         int r = 0, tmp = overwrite;
          843         char path[PATH_MAX], ver[LINE_MAX];
          844         struct pack *p = NULL;
          845 
          846         if (re_match(PACK_FORMAT, name) != 0) {
          847 #ifdef REPOAWARE
          848                 pack_find(name, path);
          849 #else
          850                 fprintf(stderr, "%s: invalid filename\n", name);
          851                 exit(1);
          852 #endif
          853         } else {
          854                 snprintf(path, PATH_MAX, "%s", name);
          855         }
          856 
          857         if ((p = pack_load_tarball(path)) == NULL)
          858                 return ERR_PACK_LOAD;
          859 
          860         if (inspect_installed(datadir, p->name)) {
          861                 fprintf(stderr, "%s: not installed\n", p->name);
          862                 pack_free(p);
          863                 return ERR_DELETE;
          864         }
          865 
          866         inspect_version(datadir, p->name, ver);
          867         if (!overwrite && !strncmp(p->version, ver, LINE_MAX)) {
          868                 fprintf(stderr, "%s: already at version %s\n", p->name, p->version);
          869                 pack_free(p);
          870                 return ERR_DELETE;
          871         }
          872 
          873         if (pack_delete(rootfs, datadir, p) != 0) {
          874                 pack_free(p);
          875                 return ERR_DELETE;
          876         }
          877 
          878         overwrite = 1;
          879         r += pack_install(rootfs, datadir, p);
          880         overwrite = tmp;
          881 
          882         if (r == 0)
          883                 log(LOG_INFO, "updated %s (%s -> %s)\n", p->name, ver, p->version);
          884 
          885         pack_free(p);
          886 
          887         return r;
          888 }
          889 
          890 
          891 /*
          892  * Delete a currently installed pack. This wraps load/delete functions
          893  */
          894 int
          895 delete(const char *rootfs, const char *datadir, char *name)
          896 {
          897         int r = 0;
          898         struct pack *p = NULL;
          899 
          900         if (inspect_installed(datadir, name)) {
          901                 fprintf(stderr, "%s: not installed\n", name);
          902                 return ERR_DELETE;
          903         }
          904 
          905         if ((p = pack_load_metadata(datadir, name)) == NULL)
          906                 return ERR_PACK_LOAD;
          907 
          908         r += pack_delete(rootfs, datadir, p);
          909 
          910         if (r == 0)
          911                 log(LOG_INFO, "deleted %s (%s)\n", p->name, p->version);
          912 
          913         pack_free(p);
          914 
          915         return r;
          916 }
          917 
          918 
          919 /*
          920  * Inspect the system, either by looking into a pack, checking installed
          921  * files, or listing packs actually installed
          922  */
          923 int
          924 inspect(const char *datadir, const char *packname)
          925 {
          926         /* name is NULL, list packs installed */
          927         if (!packname)
          928                 return inspect_system(1, datadir);
          929 
          930         /* otherwise, list files installed by a pack */
          931         return inspect_files(1, datadir, packname);
          932 }
          933 
          934 
          935 int
          936 main (int argc, char **argv)
          937 {
          938         int r = 0;
          939         char *n = NULL, *argv0;
          940         uint8_t action = ACTION_DEFAULT;
          941         char rootfs[PATH_MAX] = "";
          942         char datadir[PATH_MAX] = "";
          943 
          944         strncpy(rootfs, PACK_ROOT, PATH_MAX -1);
          945         strncat(rootfs, "/", PATH_MAX - 1);
          946         strncpy(datadir, PACK_DATA, PATH_MAX);
          947 
          948         ARGBEGIN{
          949         case 'a':
          950                 action = ACTION_INSTALL;
          951                 break;
          952         case 'd':
          953                 action = ACTION_DELETE;
          954                 break;
          955         case 'f':
          956                 overwrite = 1;
          957                 break;
          958         case 'i':
          959                 action = ACTION_INSPECT;
          960                 if (argc > 1)
          961                         n = ARGF();
          962                 break;
          963         case 'u':
          964                 action = ACTION_UPDATE;
          965                 break;
          966         case 'v':
          967                 verbose++;
          968                 break;
          969         default:
          970                 action = ACTION_INVALID;
          971         }ARGEND;
          972 
          973         switch (action) {
          974         case ACTION_INSTALL:
          975         case ACTION_UPDATE:
          976         case ACTION_DELETE:
          977                 while(*argv) {
          978                         if (action == ACTION_INSTALL)
          979                                 r += install(rootfs, datadir, *argv);
          980                         if (action == ACTION_UPDATE)
          981                                 r += update(rootfs, datadir, *argv);
          982                         if (action == ACTION_DELETE)
          983                                 r += delete(rootfs, datadir, *argv);
          984                         argv++;
          985                 }
          986                 break;
          987         case ACTION_INSPECT:
          988                 if (inspect(datadir, n) != 0)
          989                         return ERR_INSPECT;
          990                 break;
          991         default:
          992                 usage(argv0);
          993                 return ERR_INVALID_ACTION;
          994         }
          995 
          996         return r;
          997 }