1 #define _POSIX_C_SOURCE 200809L
16 #include "sqlite/sqlite3.h"
19 char *package, *version;
21 int complete, addcontent, isconfig, opt_l, recursive, verbose;
27 char *cltype, *clhash, *clmtime, *prefix, *strip, *cltarget;
28 char *clgroup, *cluser;
32 static void warn(char *fmt, ...) {
36 vfprintf(stderr, fmt, args);
38 fprintf(stderr, "\n");
42 static int dieval = EXIT_FAILURE;
44 static void die(char *fmt, ...) {
48 vfprintf(stderr, fmt, args);
50 fprintf(stderr, "\n");
54 char *cleanpath(char *path, char *strip, char *prefix) {
62 if (strncmp(path, strip, len)) {
63 /* strip is not a prefix */
80 /* path is only stripped */
86 t = new + strlen(prefix);
89 /* skip leading curdir */
90 if (*s && *s == '.' && s[1] && s[1] == '/') {
94 /* skip leading slashes */
104 /* skip multiple slashes */
105 if (*s == '/' && s[1] && s[1] == '/') {
108 /* skip trailing slash */
109 if (*s == '/' && !s[1]) {
114 if (*s == '/' && s[1] && s[1] == '.' && s[2] && s[2] == '/') {
119 if (*s == '/' && s[1] && s[1] == '.' && s[2] == 0) {
131 char *getuser(uid_t uid) {
136 return strdup(pw->pw_name);
141 char *getgroup(uid_t uid) {
146 return strdup(pw->pw_name);
151 void free_file(struct zpm_file *file) {
156 file->path = file->owner = file->group = file->target = 0;
159 int stat_file(struct zpm_file *file, char *path, struct opts *opt) {
166 if (opt->followsymlinks) {
167 rv = stat(path, &st);
169 rv = lstat(path, &st);
176 switch (st.st_mode & S_IFMT) {
177 case S_IFBLK: file->type = 'b'; break;
178 case S_IFCHR: file->type = 'c'; break;
179 case S_IFDIR: file->type = 'd'; break;
180 case S_IFIFO: file->type = 'p'; break;
181 case S_IFLNK: file->type = 'l'; break;
182 case S_IFREG: file->type = 'r'; break;
183 case S_IFSOCK: file->type = 's'; break;
184 default: file->type = 0; break;
187 file->configuration = opt->isconfig;
189 if (file->type == 0) {
193 if (file->type == 'l') {
195 file->target = strdup(opt->cltarget);
199 n = readlink(path, linkval, sizeof linkval);
200 if (n >= sizeof linkval) {
204 file->target = strdup(linkval);
208 /* strip and prefix */
209 file->path = cleanpath(path, opt->strip, opt->prefix);
210 if (file->path == 0) {
216 file->mode = opt->clmode & 07777;
218 file->mode = st.st_mode & 07777;
222 file->owner = strdup(opt->cluser);
224 file->owner = getuser(st.st_uid);
227 if (file->owner == 0) {
233 file->group = strdup(opt->clgroup);
235 file->group = getgroup(st.st_gid);
237 if (file->group == 0) {
242 file->mtime = st.st_mtime;
247 int add_file(struct zpm *zpm, struct zpm_file *file, struct opts *opt);
249 char *pathcat(char *dir, char *path) {
250 size_t dirlen = 0, pathlen = 0;
253 /* chop off trailing / on dir */
255 dirlen = strlen(dir);
256 while (dirlen && dir[dirlen-1] == '/') {
262 pathlen = strlen(path);
263 while (*path && *path == '/') {
269 cat = malloc(dirlen + pathlen + 2);
271 strncpy(cat, dir, dirlen);
273 strcpy(cat+dirlen+1, path);
278 int add_dir(struct zpm *zpm, char *path, struct opts *opt) {
281 struct zpm_file file = { 0 };
289 zpm_seterror(zpm, "can't open dir %s: %s", path, strerror(errno));
293 while ((de = readdir(dir))) {
294 if (!strcmp(de->d_name, ".")) {
297 if (!strcmp(de->d_name, "..")) {
301 dpath = pathcat(path, de->d_name);
303 zpm_seterror(zpm, "pathcat failed");
308 if (!stat_file(&file, dpath, opt)) {
309 zpm_seterror(zpm, "stat %s failed: %s",
310 dpath, strerror(errno));
315 if (!add_file(zpm, &file, opt)) {
327 int add_file(struct zpm *zpm, struct zpm_file *file, struct opts *opt) {
328 char hash[ZPM_HASH_STRLEN+1];
330 if (file->path[0] != 0) {
331 if (file->type == 'r') {
332 if (opt->addcontent) {
333 if (zpm_import(zpm, file->data, 0, hash)) {
334 strcpy(file->hash, hash);
339 zpm_hash(file->data, hash, 0);
340 strcpy(file->hash, hash);
344 zpm_db_run(zpm, "insert or replace into packagefiles "
345 "(package,version,release,path,mode,mtime,username,"
346 "groupname,filetype,hash,configuration,target)"
348 "(%Q, %Q, %d, %Q, %o, %d, %Q, %Q, '%c', %Q, %d, %Q)",
349 opt->package, opt->version, opt->release, file->path,
350 file->mode, (int)file->mtime, file->owner, file->group,
352 file->type == 'r' ? file->hash : NULL,
354 file->type == 'l' ? file->target : NULL
361 if (opt->verbose > 1) {
362 printf("%c%o %s:%s %s\n", file->type, file->mode, file->owner, file->group, file->path);
363 } else if (opt->verbose > 0) {
365 printf("%s\n", file->path);
370 if (opt->recursive && file->type == 'd') {
371 if (!add_dir(zpm, file->data, opt)) {
379 int main(int ac, char **av) {
381 struct opts opt = { 0 };
385 char hash[ZPM_HASH_STRLEN+1];
387 char *dbfile = getenv("ZPMDB");
390 dbfile = "/var/lib/zpm/local.db";
395 while ((option = getopt(ac, av, "CF:H:M:NP:S:T:cf:g:hlm:ru:vxz")) != -1) {
397 case 'C': opt.complete = 1; break;
398 case 'F': opt.cltype = optarg; break;
399 case 'H': opt.clhash = optarg; break;
400 case 'M': opt.clmtime = optarg; break;
401 case 'N': opt.addcontent = 0; break;
402 case 'P': opt.prefix = optarg; break;
403 case 'S': opt.strip = optarg; break;
404 case 's': opt.striparg = 1; break;
405 case 'T': opt.cltarget = optarg; break;
406 case 'c': opt.isconfig = 1; break;
407 case 'f': dbfile = optarg; break;
408 case 'g': opt.clgroup = optarg; break;
409 case 'h': opt.followsymlinks = 1; break;
410 case 'l': opt.opt_l = 1; break;
411 case 'm': opt.clmode = strtol(optarg, NULL, 8); break;
412 case 'r': opt.recursive = 1; break;
413 case 'u': opt.cluser = optarg; break;
414 case 'v': opt.verbose++; break;
415 case 'x': opt.xargs = 1; dieval = 255; break;
416 case 'z': opt.noclear = 1; break;
427 if (!zpm_open(&zpm, dbfile)) {
428 die("can't open zpm db %s", dbfile);
432 i = sqlite3_config(SQLITE_CONFIG_MMAP_SIZE,98222080);
433 if (i != SQLITE_OK) {
438 /* package is first arg */
441 pkgstr = av[optind++];
442 pkgid = zpm_findpkg(&zpm, pkgstr, NULL);
443 /* TODO if not found, error */
445 die("package %s not found\n", pkgstr);
452 zpm_parse_package(pkgid, package, version, &release);
453 opt.package = package;
454 opt.version = version;
455 opt.release = release;
458 printf("adding to %s %s\n", dbfile, pkgid);
464 struct zpm_file file;
465 for (i=optind; av[i]; i++) {
466 if (!stat_file(&file, av[i], &opt)) {
467 die("can't stat %s: %s", av[i], strerror(errno));
474 if (add_file(&zpm, &file, &opt)) {
477 die("error: %s", zpm.errmsg);
482 zpm_db_run(&zpm, "update packages set build_time = %d where package = %Q and version = %Q and release = %d", time(NULL), package, version, release);
483 zpm_package_hash(&zpm, pkgid, hash);
484 zpm_package_sethash(&zpm, pkgid, hash);
485 } else if (!opt.noclear) {
486 zpm_db_run(&zpm, "update packages set build_time = null, hash = null where package = %Q and version = %Q and release = %d", package, version, release);
488 /* TODO error check */