pm

barely a pack manager
git clone git://z3bra.org/pm
Log | Files | Refs | README | LICENSE

pm.c (20112B)


      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, 0)) {
    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, 0);
    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 		sprintf(version, "(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);
    945 	strncat(rootfs, "/", PATH_MAX);
    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 }