/[gentoo-projects]/portage-utils/qmerge.c
Gentoo

Contents of /portage-utils/qmerge.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.116 - (show annotations) (download) (as text)
Mon Aug 13 22:23:35 2012 UTC (2 years, 1 month ago) by robbat2
Branch: MAIN
Changes since 1.115: +3 -3 lines
File MIME type: text/x-csrc
Fix compiler warnings for signedness.

1 /*
2 * Copyright 2005-2010 Gentoo Foundation
3 * Distributed under the terms of the GNU General Public License v2
4 * $Header: /var/cvsroot/gentoo-projects/portage-utils/qmerge.c,v 1.115 2011/12/19 04:58:09 vapier Exp $
5 *
6 * Copyright 2005-2010 Ned Ludd - <solar@gentoo.org>
7 * Copyright 2005-2010 Mike Frysinger - <vapier@gentoo.org>
8 */
9
10 #ifdef APPLET_qmerge
11
12 #include <fnmatch.h>
13 #include <glob.h>
14 #include <sys/stat.h>
15 /* This is a GNUlib hack, because GNUlib doesn't provide st_mtim members
16 * of struct stat, but instead provides wrappers to retrieve the time
17 * fields (stat-time module). We just define a macro in case people are
18 * building without autoconf. */
19 #ifdef _GL_SYS_STAT_H
20 # include "stat-time.h"
21 #else
22 # define get_stat_mtime(X) ((X)->st_mtim)
23 #endif
24
25 #ifndef GLOB_BRACE
26 # define GLOB_BRACE (1 << 10) /* Expand "{a,b}" to "a" "b". */
27 #endif
28
29 /*
30 --nofiles don't verify files in package
31 --noscript don't execute pkg_{pre,post}{inst,rm} (if any)
32 */
33
34 /* #define BUSYBOX "/bin/busybox" */
35 #define BUSYBOX ""
36
37 int old_repo = 0;
38
39 #define QMERGE_FLAGS "fFsKUpuyO5" COMMON_FLAGS
40 static struct option const qmerge_long_opts[] = {
41 {"fetch", no_argument, NULL, 'f'},
42 {"force", no_argument, NULL, 'F'},
43 {"search", no_argument, NULL, 's'},
44 {"install", no_argument, NULL, 'K'},
45 {"unmerge", no_argument, NULL, 'U'},
46 {"pretend", no_argument, NULL, 'p'},
47 {"update", no_argument, NULL, 'u'},
48 {"yes", no_argument, NULL, 'y'},
49 {"nodeps", no_argument, NULL, 'O'},
50 {"nomd5", no_argument, NULL, '5'},
51 COMMON_LONG_OPTS
52 };
53
54 static const char * const qmerge_opts_help[] = {
55 "Fetch package and newest Packages metadata",
56 "Fetch package (skipping Packages)",
57 "Search available packages",
58 "Install package",
59 "Uninstall package",
60 "Pretend only",
61 "Update only",
62 "Don't prompt before overwriting",
63 "Don't merge dependencies",
64 "Don't verify MD5 digest of files",
65 COMMON_OPTS_HELP
66 };
67
68 static const char qmerge_rcsid[] = "$Id: qmerge.c,v 1.115 2011/12/19 04:58:09 vapier Exp $";
69 #define qmerge_usage(ret) usage(ret, QMERGE_FLAGS, qmerge_long_opts, qmerge_opts_help, lookup_applet_idx("qmerge"))
70
71 char search_pkgs = 0;
72 char interactive = 1;
73 char install = 0;
74 char uninstall = 0;
75 char force_download = 0;
76 char follow_rdepends = 1;
77 char nomd5 = 0;
78 char qmerge_strict = 0;
79 char update_only = 0;
80 const char Packages[] = "Packages";
81
82 /*
83 "CHOST", "DEPEND", "DESCRIPTION", "EAPI",
84 "IUSE", "KEYWORDS", "LICENSE", "PDEPEND",
85 "PROVIDE", "RDEPEND", "SLOT", "USE"
86 */
87 struct pkg_t {
88 char PF[64];
89 char CATEGORY[64];
90 char DESC[126];
91 char LICENSE[64];
92 char RDEPEND[BUFSIZ];
93 char MD5[34];
94 char SHA1[42];
95 char SLOT[64];
96 size_t SIZE;
97 char USE[BUFSIZ];
98 char REPO[64];
99 } Pkg;
100
101 struct llist_char_t {
102 char *data;
103 struct llist_char_t *next;
104 };
105
106 typedef struct llist_char_t llist_char;
107
108 _q_static void pkg_fetch(int, const depend_atom *, const struct pkg_t *);
109 _q_static void pkg_merge(int, const depend_atom *, const struct pkg_t *);
110 _q_static int pkg_unmerge(const char *, const char *, queue *);
111 _q_static struct pkg_t *grab_binpkg_info(const char *);
112 _q_static char *find_binpkg(const char *);
113
114 _q_static void fetch(const char *destdir, const char *src)
115 {
116 char buf[BUFSIZ];
117
118 if (!binhost[0])
119 errf("PORTAGE_BINHOST= does not appear to be valid");
120
121 fflush(stdout);
122 fflush(stderr);
123
124 #if 0
125 if (getenv("FETCHCOMMAND") != NULL) {
126 snprintf(buf, sizeof(buf), "(export DISTDIR='%s' URI='%s/%s'; %s)",
127 destdir, binhost, src, getenv("FETCHCOMMAND"));
128 xsystem(buf);
129 } else
130 #endif
131 {
132 pid_t p;
133 int status;
134
135 char prog[] = "wget";
136 char argv_c[] = "-c";
137 char argv_P[] = "-P";
138 char argv_q[] = "-q";
139 char *argv_dir = xstrdup(destdir);
140 char *argv[] = {
141 prog,
142 argv_c,
143 argv_P,
144 argv_dir,
145 buf,
146 quiet ? argv_q : NULL,
147 NULL,
148 };
149 if (!(force_download || install) && pretend)
150 strcpy(prog, "echo");
151 snprintf(buf, sizeof(buf), "%s/%s", binhost, src);
152
153 p = vfork();
154 if (p == 0)
155 _exit(execvp(prog, argv));
156
157 free(argv_dir);
158
159 waitpid(p, &status, 0);
160 #if 0
161 if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
162 return;
163 #endif
164 }
165
166 fflush(stdout);
167 fflush(stderr);
168 }
169
170 _q_static void qmerge_initialize(void)
171 {
172 if (strlen(BUSYBOX))
173 if (access(BUSYBOX, X_OK) != 0)
174 err(BUSYBOX " must be installed");
175
176 if (access("/bin/sh", X_OK) != 0)
177 err("/bin/sh must be installed");
178
179 if (pkgdir[0] != '/')
180 errf("PKGDIR='%s' does not appear to be valid", pkgdir);
181
182 if (!search_pkgs && !pretend) {
183 if (mkdir_p(pkgdir, 0755))
184 errp("could not setup PKGDIR: %s", pkgdir);
185 mkdir_p(port_tmpdir, 0755);
186 }
187
188 xchdir(port_tmpdir);
189 xchdir("portage");
190
191 if (force_download && force_download != 2)
192 unlink(Packages);
193
194 if ((access(Packages, R_OK) != 0) && (force_download != 2)) {
195 char *tbuf = NULL;
196 xasprintf(&tbuf, "%s/portage/", port_tmpdir);
197 if (access(Packages, R_OK) != 0)
198 fetch(tbuf, Packages);
199 free(tbuf);
200 }
201 }
202
203 struct qmerge_bv_state {
204 const char *catname;
205 const char *pkgname;
206 char buf[4096];
207 char *retbuf;
208 };
209
210 _q_static int qmerge_filter_cat(q_vdb_cat_ctx *cat_ctx, void *priv)
211 {
212 struct qmerge_bv_state *state = priv;
213 return strcmp(cat_ctx->name, state->catname) == 0;
214 }
215
216 _q_static int qmerge_best_version_cb(q_vdb_pkg_ctx *pkg_ctx, void *priv)
217 {
218 struct qmerge_bv_state *state = priv;
219 if (qlist_match(pkg_ctx, state->buf, true))
220 strcpy(state->retbuf, state->buf);
221 return 0;
222 }
223
224 _q_static char *best_version(const char *catname, const char *pkgname)
225 {
226 static char retbuf[4096];
227 struct qmerge_bv_state state = {
228 .catname = catname,
229 .pkgname = pkgname,
230 .retbuf = retbuf,
231 };
232
233 snprintf(state.buf, sizeof(state.buf), "%s/%s", catname, pkgname);
234 retbuf[0] = '\0';
235 q_vdb_foreach_pkg(qmerge_best_version_cb, &state, qmerge_filter_cat);
236
237 return retbuf;
238 }
239
240 _q_static int
241 config_protected(const char *buf, int cp_argc, char **cp_argv,
242 int cpm_argc, char **cpm_argv)
243 {
244 int i;
245 char dest[_Q_PATH_MAX];
246 snprintf(dest, sizeof(dest), "%s%s", portroot, buf);
247
248 /* Check CONFIG_PROTECT_MASK */
249 for (i = 1; i < cpm_argc; ++i)
250 if (strncmp(cpm_argv[i], buf, strlen(cpm_argv[i])) == 0)
251 return 0;
252
253 /* Check CONFIG_PROTECT */
254 for (i = 1; i < cp_argc; ++i)
255 if (strncmp(cp_argv[i], buf, strlen(cp_argv[i])) == 0)
256 if (access(dest, R_OK) == 0)
257 return 1;
258
259 /* this would probably be bad */
260 if (strcmp("/bin/sh", buf) == 0)
261 return 1;
262
263 return 0;
264 }
265
266 _q_static void crossmount_rm(const char *fname, const struct stat st)
267 {
268 struct stat lst;
269
270 assert(pretend == 0);
271
272 if (lstat(fname, &lst) == -1)
273 return;
274 if (lst.st_dev != st.st_dev) {
275 warn("skipping crossmount install masking: %s", fname);
276 return;
277 }
278 qprintf("%s<<<%s %s\n", YELLOW, NORM, fname);
279 rm_rf(fname);
280 }
281
282 void install_mask_pwd(int iargc, char **iargv, const struct stat st);
283 void install_mask_pwd(int iargc, char **iargv, const struct stat st)
284 {
285 char buf[1024];
286 int i;
287
288 for (i = 1; i < iargc; i++) {
289
290 if (iargv[i][0] != '/')
291 continue;
292
293 snprintf(buf, sizeof(buf), ".%s", iargv[i]);
294
295 if ((strchr(iargv[i], '*') != NULL) || (strchr(iargv[i], '{') != NULL)) {
296 int g;
297 glob_t globbuf;
298
299 globbuf.gl_offs = 0;
300 if (glob(buf, GLOB_DOOFFS|GLOB_BRACE, NULL, &globbuf) == 0) {
301 for (g = 0; g < (int)globbuf.gl_pathc; g++) {
302 strncpy(buf, globbuf.gl_pathv[g], sizeof(buf));
303 /* qprintf("globbed: %s\n", globbuf.gl_pathv[g]); */
304 crossmount_rm(globbuf.gl_pathv[g], st);
305 }
306 globfree(&globbuf);
307 }
308 continue;
309 }
310 crossmount_rm(iargv[i], st);
311 }
312 }
313
314 _q_static char *
315 atom2str(const depend_atom *atom, char *buf, size_t size)
316 {
317 if (atom->PR_int)
318 snprintf(buf, size, "%s-%s-r%i", atom->PN, atom->PV, atom->PR_int);
319 else
320 snprintf(buf, size, "%s-%s", atom->PN, atom->PV);
321 return buf;
322 }
323
324 _q_static char
325 qprint_tree_node(int level, const depend_atom *atom, const struct pkg_t *pkg)
326 {
327 char buf[1024];
328 char *p;
329 int i, ret;
330
331 char install_ver[126] = "";
332 char c = 'N';
333
334 if (!pretend)
335 return 0;
336
337 p = best_version(pkg->CATEGORY, atom->PN);
338 if (strlen(p) < 1) {
339 c = 'N';
340 snprintf(buf, sizeof(buf), "%sN%s", GREEN, NORM);
341 } else {
342 depend_atom *subatom = atom_explode(p);
343 if (subatom != NULL) {
344 atom2str(subatom, buf, sizeof(buf));
345 atom2str(atom, install_ver, sizeof(install_ver));
346 ret = atom_compare_str(install_ver, buf);
347 switch (ret) {
348 case EQUAL: c = 'R'; break;
349 case NEWER: c = 'U'; break;
350 case OLDER: c = 'D'; break;
351 default: c = '?'; break;
352 }
353 strncpy(buf, subatom->P, sizeof(buf));
354 snprintf(install_ver, sizeof(install_ver), "[%s%s%s] ", DKBLUE, buf, NORM);
355 atom_implode(subatom);
356 }
357 if (update_only && c != 'U')
358 return c;
359 if ((c == 'R' || c == 'D') && update_only && level)
360 return c;
361 if (c == 'R')
362 snprintf(buf, sizeof(buf), "%s%c%s", YELLOW, c, NORM);
363 if (c == 'U' || c == 'D')
364 snprintf(buf, sizeof(buf), "%s%c%s", BLUE, c, NORM);
365 #if 0
366 if (level) {
367 switch (c) {
368 case 'N':
369 case 'U': break;
370 default:
371 qprintf("[%c] %d %s\n", c, level, pkg->PF); return;
372 break;
373 }
374 }
375 #endif
376 }
377 printf("[%s] ", buf);
378 for (i = 0; i < level; ++i)
379 putchar(' ');
380 if (verbose)
381 printf("%s%s/%s%s %s%s%s%s%s%s\n", DKGREEN, pkg->CATEGORY, pkg->PF, NORM,
382 install_ver, strlen(pkg->USE) > 0 ? "(" : "", RED, pkg->USE, NORM, strlen(pkg->USE) > 0 ? ")" : "");
383 else
384 printf("%s%s/%s%s\n", DKGREEN, pkg->CATEGORY, pkg->PF, NORM);
385 return c;
386 }
387
388 _q_static void pkg_run_func(const char *vdb_path, const char *phases, const char *func)
389 {
390 const char *phase;
391 char *script;
392
393 /* This assumes no func is a substring of another func.
394 * Today, that assumption is valid for all funcs ...
395 * The phases are the func with the "pkg_" chopped off. */
396 phase = func + 4;
397 if (strstr(phases, phase) == NULL) {
398 qprintf("--- %s\n", func);
399 return;
400 }
401
402 qprintf(">>> %s\n", func);
403
404 xasprintf(&script,
405 /* Provide funcs required by the PMS */
406 "EBUILD_PHASE=%3$s\n"
407 "debug-print() { :; }\n"
408 "debug-print-function() { :; }\n"
409 "debug-print-section() { :; }\n"
410 /* Not quite right */
411 "has_version() { qlist -ICq -e '$1' >/dev/null; }\n"
412 "use() { useq \"$@\"; }\n"
413 "useq() { hasq $1 $USE; }\n"
414 "has() { hasq \"$@\"; }\n"
415 "hasq() { local h=$1; shift; case \" $* \" in *\" $h \"*) return 0;; *) return 1;; esac; }\n"
416 "elog() { printf ' * %%b\\n' \"$*\"; }\n"
417 "einfo() { elog \"$@\"; }\n"
418 "ewarn() { elog \"$@\"; }\n"
419 "eerror() { elog \"$@\"; }\n"
420 "die() { eerror \"$@\"; exit 1; }\n"
421 "ebegin() { printf ' * %%b ...' \"$*\"; }\n"
422 "eend() { local r=${1:-$?}; [ $r -eq 0 ] && echo '[ ok ]' || echo '[ !! ]'; return $r; }\n"
423 /* Unpack the env if need be */
424 "[ -e '%1$s/environment' ] || { bzip2 -dc '%1$s/environment.bz2' > '%1$s/environment' || exit 1; }\n"
425 /* Load the env and run the func */
426 ". '%1$s/environment' && %2$s\n"
427 /* Ignore func return values (not exit values) */
428 ":",
429 vdb_path, func, phase);
430 xsystembash(script);
431 free(script);
432 }
433
434 /* Copy one tree (the single package) to another tree (ROOT) */
435 _q_static int
436 merge_tree_at(int fd_src, const char *src, int fd_dst, const char *dst,
437 FILE *contents, queue **objs, char **cpathp, int iargc, char **iargv,
438 int cp_argc, char **cp_argv, int cpm_argc, char **cpm_argv)
439 {
440 int i, ret, subfd_src, subfd_dst;
441 DIR *dir;
442 struct dirent *de;
443 struct stat st;
444 char *cpath;
445 size_t clen, nlen, mnlen;
446
447 ret = -1;
448
449 /* Get handles to these subdirs */
450 subfd_src = openat(fd_src, src, O_RDONLY|O_CLOEXEC);
451 if (subfd_src < 0)
452 return ret;
453 subfd_dst = openat(fd_dst, dst, O_RDONLY|O_CLOEXEC);
454 if (subfd_dst < 0) {
455 close(subfd_src);
456 return ret;
457 }
458
459 dir = fdopendir(subfd_src);
460 if (!dir)
461 goto done;
462
463 cpath = *cpathp;
464 clen = strlen(cpath);
465 cpath[clen] = '/';
466 nlen = mnlen = 0;
467
468 while ((de = readdir(dir)) != NULL) {
469 const char *name = de->d_name;
470
471 if (!strcmp(name, ".") || !strcmp(name, ".."))
472 continue;
473
474 /* Build up the full path for this entry */
475 nlen = strlen(name);
476 if (mnlen < nlen) {
477 cpath = *cpathp = xrealloc(*cpathp, clen + 1 + nlen + 1);
478 mnlen = nlen;
479 }
480 strcpy(cpath + clen + 1, name);
481
482 /* Check INSTALL_MASK */
483 for (i = 1; i < iargc; ++i) {
484 if (fnmatch(iargv[i], cpath, 0) == 0) {
485 unlinkat(subfd_src, name, 0);
486 unlinkat(subfd_dst, name, 0);
487 continue;
488 }
489 }
490
491 /* Find out what the source path is */
492 if (fstatat(subfd_src, name, &st, AT_SYMLINK_NOFOLLOW)) {
493 warnp("could not read %s", cpath);
494 continue;
495 }
496
497 /* Migrate a directory */
498 if (S_ISDIR(st.st_mode)) {
499 if (mkdirat(subfd_dst, name, st.st_mode)) {
500 if (errno != EEXIST) {
501 warnp("could not read %s", cpath);
502 continue;
503 }
504
505 /* XXX: update times of dir ? */
506 }
507
508 #if 0 /* We filter out "dir" as it's generally unnecessary cruft */
509 /* syntax: dir dirname */
510 fprintf(contents, "dir %s\n", cpath);
511 *objs = add_set(cpath, "", *objs);
512 qprintf("%s>>>%s %s%s%s/\n", GREEN, NORM, DKBLUE, cpath, NORM);
513 #endif
514
515 /* Copy all of these contents */
516 merge_tree_at(subfd_src, name, subfd_dst, name, contents, objs, cpathp,
517 iargc, iargv, cp_argc, cp_argv, cpm_argc, cpm_argv);
518 cpath = *cpathp;
519 mnlen = 0;
520
521 /* In case we didn't install anything, prune the empty dir */
522 unlinkat(subfd_dst, name, AT_REMOVEDIR);
523 }
524
525 /* Migrate a file */
526 else if (S_ISREG(st.st_mode)) {
527 struct timespec times[2];
528 int fd_srcf, fd_dstf;
529 unsigned char *hash;
530 const char *tmpname, *dname;
531
532 /* syntax: obj filename hash mtime */
533 hash = hash_file_at(subfd_src, name, HASH_MD5);
534 fprintf(contents, "obj %s %s %lu\n", cpath, hash, (unsigned long)st.st_mtime);
535
536 /* Check CONFIG_PROTECT */
537 if (config_protected(cpath, cp_argc, cp_argv, cpm_argc, cpm_argv)) {
538 /* ._cfg####_ */
539 char *num;
540 dname = num = alloca(nlen + 10 + 1);
541 *num++ = '.';
542 *num++ = '_';
543 *num++ = 'c';
544 *num++ = 'f';
545 *num++ = 'g';
546 strcpy(num + 5, name);
547 for (i = 0; i < 10000; ++i) {
548 sprintf(num, "%04i", i);
549 num[4] = '_';
550 if (faccessat(subfd_dst, dname, F_OK, AT_SYMLINK_NOFOLLOW))
551 break;
552 }
553 qprintf("%s>>>%s %s (%s)\n", GREEN, NORM, cpath, dname);
554 } else {
555 dname = name;
556 qprintf("%s>>>%s %s\n", GREEN, NORM, cpath);
557 }
558 *objs = add_set(cpath, "", *objs);
559
560 /* First try fast path -- src/dst are same device */
561 if (renameat(subfd_src, dname, subfd_dst, name) == 0)
562 continue;
563
564 /* Fall back to slow path -- manual read/write */
565 fd_srcf = openat(subfd_src, name, O_RDONLY|O_CLOEXEC);
566 if (fd_srcf < 0) {
567 warnp("could not read %s", cpath);
568 continue;
569 }
570
571 /* Do not write the file in place ...
572 * will fail with files that are in use.
573 * XXX: Should we make this random ?
574 */
575 tmpname = ".qmerge.update";
576 fd_dstf = openat(subfd_dst, tmpname, O_WRONLY|O_CLOEXEC|O_CREAT|O_TRUNC, st.st_mode);
577 if (fd_dstf < 0) {
578 warnp("could not write %s", cpath);
579 close(fd_srcf);
580 continue;
581 }
582
583 /* Make sure owner/mode is sane before we write out data */
584 if (fchown(fd_dstf, st.st_uid, st.st_gid)) {
585 warnp("could not set ownership %s", cpath);
586 continue;
587 }
588 if (fchmod(fd_dstf, st.st_mode)) {
589 warnp("could not set permission %s", cpath);
590 continue;
591 }
592
593 /* Do the actual data copy */
594 if (copy_file_fd(fd_srcf, fd_dstf)) {
595 warnp("could not write %s", cpath);
596 if (ftruncate(fd_dstf, 0)) {
597 /* don't care */;
598 }
599 close(fd_srcf);
600 close(fd_dstf);
601 continue;
602 }
603
604 /* Preserve the file times */
605 times[0] = get_stat_mtime(&st);
606 times[1] = get_stat_mtime(&st);
607 futimens(fd_dstf, times);
608
609 close(fd_srcf);
610 close(fd_dstf);
611
612 /* Move the new tmp dst file to the right place */
613 if (renameat(subfd_dst, tmpname, subfd_dst, dname)) {
614 warnp("could not rename %s to %s", tmpname, cpath);
615 continue;
616 }
617 }
618
619 /* Migrate a symlink */
620 else if (S_ISLNK(st.st_mode)) {
621 size_t len = st.st_size;
622 char *sym = alloca(len + 1);
623
624 /* Find out what we're pointing to */
625 if (readlinkat(subfd_src, name, sym, len) == -1) {
626 warnp("could not read link %s", cpath);
627 continue;
628 }
629 sym[len] = '\0';
630
631 /* syntax: sym src -> dst mtime */
632 fprintf(contents, "sym %s -> %s %lu\n", cpath, sym, (unsigned long)st.st_mtime);
633 qprintf("%s>>>%s %s%s -> %s%s\n", GREEN, NORM, CYAN, cpath, sym, NORM);
634 *objs = add_set(cpath, "", *objs);
635
636 /* Make it in the dest tree */
637 if (symlinkat(sym, subfd_dst, name)) {
638 /* If the symlink exists, unlink it and try again */
639 if (errno != EEXIST ||
640 unlinkat(subfd_dst, name, 0) ||
641 symlinkat(sym, subfd_dst, name)) {
642 warnp("could not create link %s to %s", cpath, sym);
643 continue;
644 }
645 }
646
647 struct timespec times[2];
648 times[0] = get_stat_mtime(&st);
649 times[1] = get_stat_mtime(&st);
650 utimensat(subfd_dst, name, times, AT_SYMLINK_NOFOLLOW);
651 }
652
653 /* WTF is this !? */
654 else {
655 warnp("unknown file type %s", cpath);
656 continue;
657 }
658 }
659
660 ret = 0;
661
662 done:
663 close(subfd_src);
664 close(subfd_dst);
665
666 return ret;
667 }
668
669 /* Copy one tree (the single package) to another tree (ROOT) */
670 _q_static int
671 merge_tree(const char *src, const char *dst, FILE *contents,
672 queue **objs, int iargc, char **iargv)
673 {
674 int ret;
675 int cp_argc, cpm_argc;
676 char **cp_argv, **cpm_argv;
677 char *cpath;
678
679 /* XXX: be nice to pull this out of the current func
680 * so we don't keep reparsing the same env var
681 * when unmerging multiple packages.
682 */
683 makeargv(config_protect, &cp_argc, &cp_argv);
684 makeargv(config_protect_mask, &cpm_argc, &cpm_argv);
685
686 cpath = xstrdup("");
687 ret = merge_tree_at(AT_FDCWD, src, AT_FDCWD, dst, contents, objs, &cpath,
688 iargc, iargv, cp_argc, cp_argv, cpm_argc, cpm_argv);
689 free(cpath);
690
691 freeargv(cp_argc, cp_argv);
692 freeargv(cpm_argc, cpm_argv);
693
694 return ret;
695 }
696
697 /* oh shit getting into pkg mgt here. FIXME: write a real dep resolver. */
698 _q_static void
699 pkg_merge(int level, const depend_atom *atom, const struct pkg_t *pkg)
700 {
701 queue *objs;
702 FILE *fp, *contents;
703 char buf[1024], phases[128];
704 char *tbz2, *p;
705 int i;
706 char **ARGV;
707 int ARGC;
708 struct stat st;
709 char **iargv;
710 char c;
711 int iargc;
712
713 if (!install || !pkg || !atom)
714 return;
715
716 if (!pkg->PF[0] || !pkg->CATEGORY) {
717 if (verbose) warn("CPF is really NULL at level %d", level);
718 return;
719 }
720
721 c = qprint_tree_node(level, atom, pkg);
722
723 if (0)
724 if (((c == 'R') || (c == 'D')) && update_only)
725 return;
726
727 if (pkg->RDEPEND[0] && follow_rdepends) {
728 const char *rdepend;
729
730 IF_DEBUG(fprintf(stderr, "\n+Parent: %s/%s\n", pkg->CATEGORY, pkg->PF));
731 IF_DEBUG(fprintf(stderr, "+Depstring: %s\n", pkg->RDEPEND));
732
733 /* <hack> */
734 if (strncmp(pkg->RDEPEND, "|| ", 3) == 0) {
735 if (verbose)
736 qfprintf(stderr, "fix this rdepend hack %s\n", pkg->RDEPEND);
737 rdepend = "";
738 } else
739 rdepend = pkg->RDEPEND;
740 /* </hack> */
741
742 makeargv(rdepend, &ARGC, &ARGV);
743 /* Walk the rdepends here. Merging what need be. */
744 for (i = 1; i < ARGC; i++) {
745 depend_atom *subatom, *ratom;
746 char *name = ARGV[i];
747 switch (*name) {
748 case '|':
749 case '!':
750 case '<':
751 case '>':
752 case '=':
753 if (verbose)
754 qfprintf(stderr, "Unhandled depstring %s\n", name);
755 case '\0':
756 break;
757 default:
758 if (*name == '~') {
759 name = ARGV[i] + 1;
760 /* warn("newname = %s", name); */
761 }
762 if ((subatom = atom_explode(name)) != NULL) {
763 char *dep;
764 struct pkg_t *subpkg;
765 char *resolved = NULL;
766
767 dep = find_binpkg(name);
768
769 if (strncmp(name, "virtual/", 8) == 0) {
770 if (virtuals == NULL)
771 virtuals = resolve_virtuals();
772 resolved = find_binpkg(virtual(name, virtuals));
773 if (resolved == NULL || !strlen(resolved))
774 resolved = find_binpkg(name);
775 } else
776 resolved = NULL;
777
778 if (resolved == NULL)
779 resolved = dep;
780
781 IF_DEBUG(fprintf(stderr, "+Atom: argv0(%s) dep(%s) resolved(%s)\n", name, dep, resolved));
782
783 if (strlen(resolved) < 1) {
784 warn("Cant find a binpkg for %s from rdepend(%s)", name, pkg->RDEPEND);
785 continue;
786 }
787
788 /* ratom = atom_explode(resolved); */
789 subpkg = grab_binpkg_info(resolved); /* free me later */
790
791 assert(subpkg != NULL);
792 IF_DEBUG(fprintf(stderr, "+Subpkg: %s/%s\n", subpkg->CATEGORY, subpkg->PF));
793
794 /* look at installed versions now. If NULL or < merge this pkg */
795 snprintf(buf, sizeof(buf), "%s/%s", subpkg->CATEGORY, subpkg->PF);
796
797 ratom = atom_explode(buf);
798
799 p = best_version(subpkg->CATEGORY, subpkg->PF);
800 /* we dont want to remerge equal versions here */
801 IF_DEBUG(fprintf(stderr, "+Installed: %s\n", p));
802 if (strlen(p) < 1)
803 if (!((strcmp(pkg->PF, subpkg->PF) == 0) && (strcmp(pkg->CATEGORY, subpkg->CATEGORY) == 0)))
804 pkg_fetch(level+1, ratom, subpkg);
805
806 atom_implode(subatom);
807 atom_implode(ratom);
808 free(subpkg);
809 } else {
810 qfprintf(stderr, "Cant explode atom %s\n", name);
811 }
812 break;
813 }
814 }
815 freeargv(ARGC, ARGV);
816 }
817 if (pretend)
818 return;
819
820 /* Set up our temp dir to unpack this stuff */
821 xasprintf(&p, "%s/qmerge/%s", port_tmpdir, pkg->PF);
822 mkdir_p(p, 0755);
823 xchdir(p);
824 free(p);
825
826 /* Doesn't actually remove $PWD, just everything under it */
827 rm_rf(".");
828
829 /* XXX: maybe some day we should have this step operate on the
830 * tarball directly rather than unpacking it first. */
831
832 /* split the tbz and xpak data */
833 xasprintf(&tbz2, "%s/%s/%s.tbz2", pkgdir, pkg->CATEGORY, pkg->PF);
834 assert(run_applet_l("qtbz2", "-s", tbz2, NULL) == 0);
835
836 mkdir("vdb", 0755);
837 sprintf(tbz2, "%s.xpak", pkg->PF);
838 assert(run_applet_l("qxpak", "-d", "vdb", "-x", tbz2, NULL) == 0);
839
840 free(tbz2);
841
842 /* extrct the binary package data */
843 mkdir("image", 0755);
844 snprintf(buf, sizeof(buf), BUSYBOX " tar -jx%sf %s.tar.bz2 -C image/", ((verbose > 1) ? "v" : ""), pkg->PF);
845 xsystem(buf);
846 fflush(stdout);
847
848 eat_file("vdb/DEFINED_PHASES", phases, sizeof(phases));
849 pkg_run_func("vdb", phases, "pkg_preinst");
850
851 /* XXX: kill this off */
852 xchdir("image");
853
854 if (stat(".", &st) == -1)
855 err("Cant stat pwd");
856
857 /* Initialize INSTALL_MASK and common stuff */
858 makeargv(install_mask, &iargc, &iargv);
859 /* XXX: Would be better if INSTALL_MASK deleted from image/
860 * so we didn't have to parse it while doing merge_tree() */
861 install_mask_pwd(iargc, iargv, st);
862
863 if (strstr(features, "noinfo")) rm_rf("./usr/share/info");
864 if (strstr(features, "noman" )) rm_rf("./usr/share/man");
865 if (strstr(features, "nodoc" )) rm_rf("./usr/share/doc");
866
867 /* we dont care about the return code */
868 rmdir("./usr/share");
869
870 /* XXX: Once we kill xchdir(image), this can die too */
871 xchdir("..");
872
873 if ((contents = fopen("vdb/CONTENTS", "w")) == NULL)
874 errf("come on wtf?");
875 objs = NULL;
876 merge_tree("image", portroot, contents, &objs, iargc, iargv);
877 fclose(contents);
878
879 freeargv(iargc, iargv);
880
881 /* run postinst */
882 pkg_run_func("vdb", phases, "pkg_postinst");
883
884 /* XXX: hmm, maybe we'll want to strip more ? */
885 unlink("vdb/environment");
886
887 /* FIXME */ /* move unmerging to around here ? */
888 /* check for an already installed pkg */
889 snprintf(buf, sizeof(buf), "%s/%s", atom->CATEGORY, pkg->PF);
890
891 /* Unmerge any stray pieces from the older version which we didn't replace */
892 p = best_version(atom->CATEGORY, atom->PN);
893 if (*p) {
894 /* XXX: Should see about merging with unmerge_packages() */
895 makeargv(p, &ARGC, &ARGV);
896 for (i = 1; i < ARGC; i++) {
897 int ret, u;
898 const char *pn;
899 char *pf;
900 char *slot = NULL;
901
902 pf = ARGV[i];
903 switch ((ret = atom_compare_str(buf, pf))) {
904 case ERROR:
905 case NOT_EQUAL:
906 continue;
907 case NEWER:
908 case OLDER:
909 case EQUAL:
910 u = 1;
911 pn = basename(pf);
912 slot = grab_vdb_item("SLOT", atom->CATEGORY, pn);
913 if (pkg->SLOT[0] && slot) {
914 if (strcmp(pkg->SLOT, slot) != 0)
915 u = 0;
916 }
917 /* We need to really set this unmerge pending after we look at contents of the new pkg */
918 if (u)
919 break;
920 continue;
921 default:
922 warn("no idea how we reached here.");
923 continue;
924 }
925
926 qprintf("%s+++%s %s %s %s\n", GREEN, NORM, buf, booga[ret], pf);
927
928 pkg_unmerge(atom->CATEGORY, pn, objs);
929 }
930 freeargv(ARGC, ARGV);
931 }
932
933 /* Clean up the package state */
934 while (objs) {
935 queue *q = objs;
936 objs = q->next;
937 free(q->name);
938 free(q->item);
939 free(q);
940 }
941
942 /* Update the magic counter */
943 if ((fp = fopen("vdb/COUNTER", "w")) != NULL) {
944 fputs("0", fp);
945 fclose(fp);
946 }
947
948 /* move the local vdb copy to the final place */
949 snprintf(buf, sizeof(buf), "%s%s/%s/", portroot, portvdb, pkg->CATEGORY);
950 mkdir_p(buf, 0755);
951 strcat(buf, pkg->PF);
952 if (rename("vdb", buf)) {
953 xasprintf(&p, "mv vdb '%s'", buf);
954 xsystem(p);
955 free(p);
956 }
957
958 /* clean up our local temp dir */
959 xchdir("..");
960 rm_rf(pkg->PF);
961 /* don't care about return */
962 rmdir("../qmerge");
963
964 printf("%s>>>%s %s%s%s/%s%s%s\n", YELLOW, NORM, WHITE, atom->CATEGORY, NORM, CYAN, atom->PN, NORM);
965 }
966
967 _q_static int
968 pkg_unmerge(const char *cat, const char *pkgname, queue *keep)
969 {
970 size_t buflen;
971 char *buf, *vdb_path, phases[128];
972 FILE *fp;
973 int ret, fd, vdb_fd, portroot_fd;
974 int cp_argc, cpm_argc;
975 char **cp_argv, **cpm_argv;
976 llist_char *dirs = NULL;
977
978 ret = 1;
979 buf = NULL;
980 vdb_path = NULL;
981 vdb_fd = portroot_fd = fd = -1;
982
983 if ((strchr(pkgname, ' ') != NULL) || (strchr(cat, ' ') != NULL)) {
984 qfprintf(stderr, "%s!!!%s '%s' '%s' (ambiguous name) specify fully-qualified pkgs\n", RED, NORM, cat, pkgname);
985 qfprintf(stderr, "%s!!!%s %s/%s (ambiguous name) specify fully-qualified pkgs\n", RED, NORM, cat, pkgname);
986 /* qfprintf(stderr, "%s!!!%s %s %s (ambiguous name) specify fully-qualified pkgs\n", RED, NORM, pkgname); */
987 return 1;
988 }
989 printf("%s<<<%s %s%s%s/%s%s%s\n", YELLOW, NORM, WHITE, cat, NORM, CYAN, pkgname, NORM);
990
991 if (pretend == 100)
992 return 0;
993
994 /* Get a handle to the root to play with */
995 portroot_fd = open(portroot, O_RDONLY | O_CLOEXEC);
996 if (portroot_fd == -1) {
997 warnp("unable to read %s", portroot);
998 goto done;
999 }
1000
1001 /* Get a handle on the vdb path which we'll use everywhere else */
1002 /* Note: This vdb_path must be absolute since we use it in pkg_run_func() */
1003 xasprintf(&vdb_path, "%s%s/%s/%s/", portroot, portvdb, cat, pkgname);
1004 vdb_fd = openat(portroot_fd, vdb_path, O_RDONLY | O_CLOEXEC);
1005 if (vdb_fd == -1) {
1006 warnp("unable to read %s", vdb_path);
1007 goto done;
1008 }
1009
1010 /* First execute the pkg_prerm step */
1011 if (!pretend) {
1012 eat_file_at(vdb_fd, "DEFINED_PHASES", phases, sizeof(phases));
1013 pkg_run_func(vdb_path, phases, "pkg_prerm");
1014 }
1015
1016 /* Now start removing all the installed files */
1017 fd = openat(vdb_fd, "CONTENTS", O_RDONLY | O_CLOEXEC);
1018 if (fd == -1) {
1019 warnp("unable to read %s", "CONTENTS");
1020 goto done;
1021 }
1022 fp = fdopen(fd, "r");
1023 if (fp == NULL)
1024 goto done;
1025
1026 /* XXX: be nice to pull this out of the current func
1027 * so we don't keep reparsing the same env var
1028 * when unmerging multiple packages.
1029 */
1030 makeargv(config_protect, &cp_argc, &cp_argv);
1031 makeargv(config_protect_mask, &cpm_argc, &cpm_argv);
1032
1033 while (getline(&buf, &buflen, fp) != -1) {
1034 queue *q;
1035 contents_entry *e;
1036 char zing[20];
1037 int protected = 0;
1038 struct stat st;
1039
1040 e = contents_parse_line(buf);
1041 if (!e)
1042 continue;
1043
1044 protected = config_protected(e->name, cp_argc, cp_argv, cpm_argc, cpm_argv);
1045 snprintf(zing, sizeof(zing), "%s%s%s", protected ? YELLOW : GREEN, protected ? "***" : "<<<" , NORM);
1046
1047 /* This should never happen ... */
1048 assert(e->name[0] == '/' && e->name[1] != '/');
1049
1050 /* Should we remove in order symlinks,objects,dirs ? */
1051 switch (e->type) {
1052 case CONTENTS_DIR:
1053 if (!protected) {
1054 /* since the dir contains files, we remove it later */
1055 llist_char *list = xmalloc(sizeof(llist_char));
1056 list->data = xstrdup(e->name);
1057 list->next = dirs;
1058 dirs = list;
1059 }
1060 continue;
1061
1062 case CONTENTS_OBJ:
1063 break;
1064
1065 case CONTENTS_SYM:
1066 if (fstatat(portroot_fd, e->name + 1, &st, AT_SYMLINK_NOFOLLOW)) {
1067 warnp("stat failed for %s -> '%s'", e->name, e->sym_target);
1068 continue;
1069 }
1070
1071 /* Hrm, if it isn't a symlink anymore, then leave it be */
1072 if (!S_ISLNK(st.st_mode))
1073 continue;
1074
1075 break;
1076
1077 default:
1078 warn("%s???%s %s%s%s (%d)", RED, NORM, WHITE, e->name, NORM, e->type);
1079 continue;
1080 }
1081
1082 if (protected) {
1083 qprintf("%s %s\n", zing, e->name);
1084 continue;
1085 }
1086
1087 /* See if this was updated */
1088 q = keep;
1089 while (q) {
1090 if (!strcmp(q->name, e->name)) {
1091 /* XXX: could remove this from the queue */
1092 strcpy(zing, "---");
1093 q = NULL;
1094 break;
1095 }
1096 q = q->next;
1097 }
1098
1099 /* No match, so unmerge it */
1100 if (!quiet)
1101 printf("%s %s\n", zing, e->name);
1102 if (!keep || q) {
1103 char *p;
1104
1105 unlinkat(portroot_fd, e->name + 1, 0);
1106
1107 p = strrchr(e->name, '/');
1108 if (p) {
1109 *p = '\0';
1110 rmdir_r_at(portroot_fd, e->name + 1);
1111 }
1112 }
1113 }
1114
1115 fclose(fp);
1116 fd = -1;
1117
1118 /* Then remove all dirs in reverse order */
1119 while (dirs != NULL) {
1120 llist_char *list = dirs;
1121 char *dir = list->data;
1122 int rm;
1123
1124 rm = pretend ? -1 : rmdir_r_at(portroot_fd, dir + 1);
1125 qprintf("%s%s%s %s%s%s/\n", rm ? YELLOW : GREEN, rm ? "---" : "<<<",
1126 NORM, DKBLUE, dir, NORM);
1127
1128 free(list->data);
1129 free(list);
1130 dirs = dirs->next;
1131 }
1132
1133 freeargv(cp_argc, cp_argv);
1134 freeargv(cpm_argc, cpm_argv);
1135
1136 if (!pretend) {
1137 /* Then execute the pkg_postrm step */
1138 pkg_run_func(vdb_path, phases, "pkg_postrm");
1139
1140 /* Finally delete the vdb entry */
1141 rm_rf_at(portroot_fd, vdb_path);
1142
1143 /* And prune any empty vdb dirs */
1144 rmdir_r_at(portroot_fd, vdb_path);
1145 }
1146
1147 ret = 0;
1148 done:
1149 if (fd != -1)
1150 close(fd);
1151 if (vdb_fd != -1)
1152 close(vdb_fd);
1153 if (portroot_fd != -1)
1154 close(portroot_fd);
1155 free(buf);
1156 free(vdb_path);
1157
1158 return ret;
1159 }
1160
1161 _q_static int unlink_empty(const char *buf)
1162 {
1163 struct stat st;
1164 if (stat(buf, &st) != -1)
1165 if (st.st_size == 0)
1166 return unlink(buf);
1167 return -1;
1168 }
1169
1170 _q_static int match_pkg(queue *ll, const struct pkg_t *pkg)
1171 {
1172 depend_atom *atom;
1173 char buf[255], buf2[255];
1174 int match = 0;
1175
1176 snprintf(buf, sizeof(buf), "%s/%s", pkg->CATEGORY, pkg->PF);
1177 if ((atom = atom_explode(buf)) == NULL)
1178 errf("%s/%s is not a valid atom", pkg->CATEGORY, pkg->PF);
1179
1180 /* verify this is the requested package */
1181 if (strcmp(ll->name, buf) == 0)
1182 match = 1;
1183
1184 if (strcmp(ll->name, pkg->PF) == 0)
1185 match = 2;
1186
1187 snprintf(buf2, sizeof(buf2), "%s/%s", pkg->CATEGORY, atom->PN);
1188
1189 if (strcmp(ll->name, buf2) == 0)
1190 match = 3;
1191
1192 if (strcmp(ll->name, atom->PN) == 0)
1193 match = 4;
1194
1195 if (match)
1196 goto match_done;
1197
1198 if (ll->item) {
1199 depend_atom *subatom = atom_explode(ll->name);
1200 if (subatom == NULL)
1201 goto match_done;
1202 if (strcmp(atom->PN, subatom->PN) == 0)
1203 match = 1;
1204 atom_implode(subatom);
1205 }
1206
1207 match_done:
1208 atom_implode(atom);
1209
1210 return match;
1211 }
1212
1213 _q_static int
1214 pkg_verify_checksums(char *fname, const struct pkg_t *pkg, const depend_atom *atom,
1215 int strict, int display)
1216 {
1217 char *hash = NULL;
1218 int ret = 0;
1219
1220 if (nomd5)
1221 return ret;
1222
1223 if (pkg->MD5[0]) {
1224 if ((hash = (char*) hash_file(fname, HASH_MD5)) == NULL) {
1225 errf("hash is NULL for %s", fname);
1226 }
1227 if (strcmp(hash, pkg->MD5) == 0) {
1228 if (display)
1229 printf("MD5: [%sOK%s] %s %s/%s\n", GREEN, NORM, hash, atom->CATEGORY, pkg->PF);
1230 } else {
1231 if (display)
1232 warn("MD5: [%sER%s] (%s) != (%s) %s/%s", RED, NORM, hash, pkg->MD5, atom->CATEGORY, pkg->PF);
1233 ret++;
1234 }
1235 }
1236
1237 if (pkg->SHA1[0]) {
1238 hash = (char*) hash_file(fname, HASH_SHA1);
1239 if (strcmp(hash, pkg->SHA1) == 0) {
1240 if (display)
1241 qprintf("SHA1: [%sOK%s] %s %s/%s\n", GREEN, NORM, hash, atom->CATEGORY, pkg->PF);
1242 } else {
1243 if (display)
1244 warn("SHA1: [%sER%s] (%s) != (%s) %s/%s", RED, NORM, hash, pkg->SHA1, atom->CATEGORY, pkg->PF);
1245 ret++;
1246 }
1247 }
1248
1249 if (!pkg->SHA1[0] && !pkg->MD5[0])
1250 return 1;
1251
1252 if (strict && ret)
1253 errf("strict is set in features");
1254
1255 return ret;
1256 }
1257
1258 _q_static
1259 void pkg_process(queue *todo, const struct pkg_t *pkg)
1260 {
1261 queue *ll;
1262 depend_atom *atom;
1263 char buf[255];
1264
1265 snprintf(buf, sizeof(buf), "%s/%s", pkg->CATEGORY, pkg->PF);
1266 if ((atom = atom_explode(buf)) == NULL)
1267 errf("%s/%s is not a valid atom", pkg->CATEGORY, pkg->PF);
1268
1269 ll = todo;
1270 while (ll) {
1271 if (ll->name[0] != '-' && match_pkg(ll, pkg)) {
1272 /* fetch all requested packages */
1273 pkg_fetch(0, atom, pkg);
1274 }
1275
1276 ll = ll->next;
1277 }
1278
1279 /* free the atom */
1280 atom_implode(atom);
1281 }
1282
1283 _q_static void
1284 pkg_fetch(int level, const depend_atom *atom, const struct pkg_t *pkg)
1285 {
1286 char buf[_Q_PATH_MAX], str[_Q_PATH_MAX];
1287
1288 /* qmerge -pv patch */
1289 if (pretend) {
1290 if (!install) install++;
1291 /* qprint_tree_node(level, atom, pkg); */
1292 pkg_merge(level, atom, pkg);
1293 return;
1294 }
1295
1296 /* check to see if file exists and it's checksum matches */
1297 snprintf(buf, sizeof(buf), "%s/%s/%s.tbz2", pkgdir, pkg->CATEGORY, pkg->PF);
1298 unlink_empty(buf);
1299
1300 snprintf(str, sizeof(str), "%s/%s", pkgdir, pkg->CATEGORY);
1301 mkdir(str, 0755);
1302
1303 /* XXX: should do a size check here for partial downloads */
1304
1305 if (force_download && (access(buf, R_OK) == 0) && (pkg->SHA1[0] || pkg->MD5[0])) {
1306 if (pkg_verify_checksums(buf, pkg, atom, 0, 0) != 0)
1307 unlink(buf);
1308 }
1309 if (access(buf, R_OK) == 0) {
1310 if (!pkg->SHA1[0] && !pkg->MD5[0]) {
1311 warn("No checksum data for %s", buf);
1312 return;
1313 } else {
1314 if (pkg_verify_checksums(buf, pkg, atom, qmerge_strict, !quiet) == 0) {
1315 pkg_merge(0, atom, pkg);
1316 return;
1317 }
1318 }
1319 }
1320 if (verbose)
1321 printf("Fetching %s/%s.tbz2\n", atom->CATEGORY, pkg->PF);
1322
1323 /* fetch the package */
1324 /* Check CATEGORY first */
1325 if (!old_repo) {
1326 snprintf(buf, sizeof(buf), "%s/%s.tbz2", atom->CATEGORY, pkg->PF);
1327 fetch(str, buf);
1328 }
1329 snprintf(buf, sizeof(buf), "%s/%s/%s.tbz2", pkgdir, atom->CATEGORY, pkg->PF);
1330 if (access(buf, R_OK) != 0) {
1331 snprintf(buf, sizeof(buf), "%s.tbz2", pkg->PF);
1332 fetch(str, buf);
1333 old_repo = 1;
1334 }
1335
1336 /* verify the pkg exists now. unlink if zero bytes */
1337 snprintf(buf, sizeof(buf), "%s/%s/%s.tbz2", pkgdir, atom->CATEGORY, pkg->PF);
1338 unlink_empty(buf);
1339
1340 if (access(buf, R_OK) != 0) {
1341 warn("Failed to fetch %s.tbz2 from %s", pkg->PF, binhost);
1342 fflush(stderr);
1343 return;
1344 }
1345
1346 snprintf(buf, sizeof(buf), "%s/%s/%s.tbz2", pkgdir, atom->CATEGORY, pkg->PF);
1347 if (pkg_verify_checksums(buf, pkg, atom, qmerge_strict, !quiet) == 0) {
1348 pkg_merge(0, atom, pkg);
1349 return;
1350 }
1351 }
1352
1353 _q_static void
1354 print_Pkg(int full, struct pkg_t *pkg)
1355 {
1356 char *p = NULL;
1357 char buf[512];
1358 depend_atom *atom = NULL;
1359
1360 if (!pkg->CATEGORY[0]) errf("CATEGORY is NULL");
1361 if (!pkg->PF[0]) errf("PF is NULL");
1362
1363 printf("%s%s/%s%s%s%s%s%s\n", BOLD, pkg->CATEGORY, BLUE, pkg->PF, NORM,
1364 !quiet ? " [" : "",
1365 !quiet ? make_human_readable_str(pkg->SIZE, 1, KILOBYTE) : "",
1366 !quiet ? "KB]" : "");
1367
1368 if (full == 0)
1369 return;
1370
1371 if (pkg->DESC[0])
1372 printf(" %sDesc%s:%s %s\n", DKGREEN, YELLOW, NORM, pkg->DESC);
1373 if (pkg->SHA1[0])
1374 printf(" %sSha1%s:%s %s\n", DKGREEN, YELLOW, NORM, pkg->SHA1);
1375 if (pkg->MD5[0])
1376 printf(" %sMd5%s:%s %s\n", DKGREEN, YELLOW, NORM, pkg->MD5);
1377 if (!pkg->MD5[0] && !pkg->SHA1[0])
1378 printf(" %sSums%s:%s %s(MISSING!)%s\n", DKGREEN, YELLOW, NORM, RED, NORM);
1379 if (pkg->SLOT[0])
1380 printf(" %sSlot%s:%s %s\n", DKGREEN, YELLOW, NORM, pkg->SLOT);
1381 if (pkg->LICENSE[0])
1382 printf(" %sLicense%s:%s %s\n", DKGREEN, YELLOW, NORM, pkg->LICENSE);
1383 if (pkg->RDEPEND[0])
1384 printf(" %sRdepend%s:%s %s\n", DKGREEN, YELLOW, NORM, pkg->RDEPEND);
1385 if (pkg->USE[0])
1386 printf(" %sUse%s:%s %s\n", DKGREEN, YELLOW, NORM, pkg->USE);
1387 if (pkg->REPO[0])
1388 if (strcmp(pkg->REPO, "gentoo") != 0)
1389 printf(" %sRepo%s:%s %s\n", DKGREEN, YELLOW, NORM, pkg->REPO);
1390
1391 snprintf(buf, sizeof(buf), "%s/%s", pkg->CATEGORY, pkg->PF);
1392 atom = atom_explode(buf);
1393 if ((atom = atom_explode(buf)) == NULL)
1394 return;
1395 if ((p = best_version(pkg->CATEGORY, atom->PN)) != NULL) {
1396 if (*p) {
1397 int ret;
1398 const char *icolor = RED;
1399 ret = atom_compare_str(buf, p);
1400 switch (ret) {
1401 case EQUAL: icolor = RED; break;
1402 case NEWER: icolor = YELLOW; break;
1403 case OLDER: icolor = BLUE; break;
1404 default: icolor = NORM; break;
1405 }
1406 printf(" %sInstalled%s:%s %s%s%s\n", DKGREEN, YELLOW, NORM, icolor, p, NORM);
1407 }
1408 }
1409 atom_implode(atom);
1410 }
1411
1412 _q_static int
1413 unmerge_packages(queue *todo)
1414 {
1415 depend_atom *atom;
1416 char *p;
1417 int i, argc;
1418 char **argv;
1419
1420 while (todo) {
1421 char buf[512];
1422
1423 if (todo->name[0] == '-')
1424 goto next;
1425
1426 p = best_version(NULL, todo->name);
1427 if (!*p)
1428 goto next;
1429
1430 makeargv(p, &argc, &argv);
1431 for (i = 1; i < argc; ++i) {
1432 if ((atom = atom_explode(argv[i])) == NULL)
1433 continue;
1434 if (atom->CATEGORY) {
1435 atom2str(atom, buf, sizeof(buf));
1436 pkg_unmerge(atom->CATEGORY, buf, NULL);
1437 }
1438 atom_implode(atom);
1439 }
1440 freeargv(argc, argv);
1441
1442 next:
1443 todo = todo->next;
1444 }
1445
1446 return 0;
1447 }
1448
1449 _q_static struct pkg_t *
1450 grab_binpkg_info(const char *name)
1451 {
1452 FILE *fp;
1453 char buf[BUFSIZ];
1454 char *p;
1455 depend_atom *atom;
1456
1457 struct pkg_t *pkg = xmalloc(sizeof(struct pkg_t));
1458 struct pkg_t *rpkg = xmalloc(sizeof(struct pkg_t));
1459
1460 static char best_match[sizeof(Pkg.PF)+2+sizeof(Pkg.CATEGORY)];
1461
1462 best_match[0] = 0;
1463
1464 memset(pkg, 0, sizeof(struct pkg_t));
1465 memset(rpkg, 0, sizeof(struct pkg_t));
1466 snprintf(buf, sizeof(buf), "%s/portage/Packages", port_tmpdir);
1467
1468 if ((fp = fopen(buf, "r")) == NULL)
1469 errp("Unable to open package file %s", buf);
1470
1471 while (fgets(buf, sizeof(buf), fp) != NULL) {
1472 if (*buf == '\n') {
1473 if (pkg->PF[0] && pkg->CATEGORY[0]) {
1474 int ret;
1475
1476 snprintf(buf, sizeof(buf), "%s/%s", pkg->CATEGORY, pkg->PF);
1477 if (strstr(buf, name) != NULL) {
1478 if (!best_match[0])
1479 strncpy(best_match, buf, sizeof(best_match));
1480
1481 atom = atom_explode(buf);
1482 snprintf(buf, sizeof(buf), "%s/%s-%s", atom->CATEGORY, atom->PN, atom->PV);
1483 if (atom->PR_int)
1484 snprintf(buf, sizeof(buf), "%s/%s-%s-r%i", atom->CATEGORY, atom->PN, atom->PV, atom->PR_int);
1485 ret = atom_compare_str(name, buf);
1486 IF_DEBUG(fprintf(stderr, "=== atom_compare(%s, %s) = %d %s\n", name, buf, ret, booga[ret])); /* buf(%s) depend(%s)\n", ret, pkg->CATEGORY, pkg->PF, name, pkg->RDEPEND); */
1487 switch (ret) {
1488 case EQUAL:
1489 case NEWER:
1490 snprintf(buf, sizeof(buf), "%s/%s", pkg->CATEGORY, pkg->PF);
1491 ret = atom_compare_str(buf, best_match);
1492 if (ret == NEWER || ret == EQUAL) {
1493 strncpy(best_match, buf, sizeof(best_match));
1494 memcpy(rpkg, pkg, sizeof(struct pkg_t));
1495 IF_DEBUG(fprintf(stderr, "--- %s/%s depend(%s)\n", rpkg->CATEGORY, rpkg->PF, rpkg->RDEPEND));
1496 }
1497 case OLDER: break;
1498 default:
1499 break;
1500 }
1501 atom_implode(atom);
1502 }
1503 memset(pkg, 0, sizeof(struct pkg_t));
1504 }
1505 continue;
1506 }
1507 if ((p = strchr(buf, '\n')) != NULL)
1508 *p = 0;
1509
1510 if ((p = strchr(buf, ':')) == NULL)
1511 continue;
1512 if ((p = strchr(buf, ' ')) == NULL)
1513 continue;
1514 *p = 0;
1515 ++p;
1516
1517 if (*buf) {
1518 /* we dont need all the info */
1519 if (strcmp(buf, "RDEPEND:") == 0)
1520 strncpy(pkg->RDEPEND, p, sizeof(Pkg.RDEPEND));
1521 if (strcmp(buf, "PF:") == 0)
1522 strncpy(pkg->PF, p, sizeof(Pkg.PF));
1523 if (strcmp(buf, "CATEGORY:") == 0)
1524 strncpy(pkg->CATEGORY, p, sizeof(Pkg.CATEGORY));
1525 if (strcmp(buf, "REPO:") == 0)
1526 strncpy(pkg->REPO, p, sizeof(Pkg.REPO));
1527
1528 if (strcmp(buf, "CPV:") == 0) {
1529 if ((atom = atom_explode(p)) != NULL) {
1530 snprintf(buf, sizeof(buf), "%s-%s", atom->PN, atom->PV);
1531 if (atom->PR_int)
1532 snprintf(buf, sizeof(buf), "%s-%s-r%i", atom->PN, atom->PV, atom->PR_int);
1533 strncpy(pkg->PF, buf, sizeof(Pkg.PF));
1534 strncpy(pkg->CATEGORY, atom->CATEGORY, sizeof(Pkg.CATEGORY));
1535 atom_implode(atom);
1536 }
1537 }
1538 if (strcmp(buf, "SLOT:") == 0)
1539 strncpy(pkg->SLOT, p, sizeof(Pkg.SLOT));
1540 if (strcmp(buf, "USE:") == 0)
1541 strncpy(pkg->USE, p, sizeof(Pkg.USE));
1542
1543 /* checksums. We must have 1 or the other unless --*/
1544 if (strcmp(buf, "MD5:") == 0)
1545 strncpy(pkg->MD5, p, sizeof(Pkg.MD5));
1546 if (strcmp(buf, "SHA1:") == 0)
1547 strncpy(pkg->SHA1, p, sizeof(Pkg.SHA1));
1548 }
1549 }
1550 fclose(fp);
1551 free(pkg);
1552 return rpkg;
1553 }
1554
1555 _q_static char *
1556 find_binpkg(const char *name)
1557 {
1558 FILE *fp;
1559 char buf[BUFSIZ];
1560 char *p;
1561 char PF[sizeof(Pkg.PF)];
1562 char CATEGORY[sizeof(Pkg.CATEGORY)];
1563
1564 static char best_match[sizeof(Pkg.PF)+2+sizeof(Pkg.CATEGORY)];
1565
1566 best_match[0] = 0;
1567 if (NULL == name)
1568 return best_match;
1569
1570 snprintf(buf, sizeof(buf), "%s/portage/Packages", port_tmpdir);
1571
1572 if ((fp = fopen(buf, "r")) == NULL)
1573 errp("Unable to open package file %s", buf);
1574
1575 while (fgets(buf, sizeof(buf), fp) != NULL) {
1576 if (*buf == '\n') {
1577 if (PF[0] && CATEGORY[0]) {
1578 int ret;
1579 snprintf(buf, sizeof(buf), "%s/%s", CATEGORY, PF);
1580 if (strstr(buf, name) != NULL) {
1581 depend_atom *atom;
1582
1583 if (!best_match[0])
1584 strncpy(best_match, buf, sizeof(best_match));
1585
1586 atom = atom_explode(buf);
1587 snprintf(buf, sizeof(buf), "%s/%s", atom->CATEGORY, atom->PN);
1588 ret = atom_compare_str(name, buf);
1589 switch (ret) {
1590 case OLDER: break;
1591 case NEWER:
1592 case EQUAL:
1593 snprintf(buf, sizeof(buf), "%s/%s", CATEGORY, PF);
1594 ret = atom_compare_str(buf, best_match);
1595 if (ret == NEWER || ret == EQUAL)
1596 strncpy(best_match, buf, sizeof(best_match));
1597 /* printf("[%s == %s] = %d; %s/%s\n", name, buf, ret, CATEGORY, PF); */
1598 default:
1599 break;
1600 }
1601 atom_implode(atom);
1602 }
1603 }
1604 continue;
1605 }
1606 if ((p = strchr(buf, '\n')) != NULL)
1607 *p = 0;
1608
1609 if ((p = strchr(buf, ':')) == NULL)
1610 continue;
1611 if ((p = strchr(buf, ' ')) == NULL)
1612 continue;
1613 *p = 0;
1614 ++p;
1615
1616 if (*buf) {
1617 if (strcmp(buf, "CPV:") == 0) {
1618 depend_atom *atom;
1619 if ((atom = atom_explode(p)) != NULL) {
1620 snprintf(buf, sizeof(buf), "%s-%s", atom->PN, atom->PV);
1621 if (atom->PR_int)
1622 snprintf(buf, sizeof(buf), "%s-%s-r%i", atom->PN, atom->PV, atom->PR_int);
1623 strncpy(PF, buf, sizeof(PF));
1624 strncpy(CATEGORY, atom->CATEGORY, sizeof(CATEGORY));
1625 atom_implode(atom);
1626 }
1627 }
1628 if (strcmp(buf, "PF:") == 0)
1629 strncpy(PF, p, sizeof(PF));
1630 if (strcmp(buf, "CATEGORY:") == 0)
1631 strncpy(CATEGORY, p, sizeof(CATEGORY));
1632 }
1633 }
1634 fclose(fp);
1635 return best_match;
1636 }
1637
1638 _q_static int
1639 parse_packages(queue *todo)
1640 {
1641 FILE *fp;
1642 size_t buflen;
1643 char *buf, *p;
1644 long lineno = 0;
1645
1646 if ((fp = fopen(Packages, "r")) == NULL)
1647 errp("Unable to open package file %s", Packages);
1648
1649 memset(&Pkg, 0, sizeof(Pkg));
1650
1651 buf = NULL;
1652 while (getline(&buf, &buflen, fp) != -1) {
1653 lineno++;
1654 if (*buf == '\n') {
1655 if ((strlen(Pkg.PF) > 0) && (strlen(Pkg.CATEGORY) > 0)) {
1656 struct pkg_t *pkg = xmalloc(sizeof(*pkg));
1657 *pkg = Pkg;
1658
1659 if (search_pkgs) {
1660 if (todo) {
1661 queue *ll = todo;
1662 while (ll) {
1663 if ((match_pkg(ll, pkg) > 0) || (strcmp(ll->name, pkg->CATEGORY) == 0))
1664 print_Pkg(verbose, pkg);
1665 ll = ll->next;
1666 }
1667 } else
1668 print_Pkg(verbose, pkg);
1669 } else
1670 pkg_process(todo, pkg);
1671
1672 free(pkg);
1673 }
1674 memset(&Pkg, 0, sizeof(Pkg));
1675 continue;
1676 }
1677 if ((p = strchr(buf, '\n')) != NULL)
1678 *p = 0;
1679
1680 if ((p = strchr(buf, ':')) == NULL)
1681 continue;
1682 if ((p = strchr(buf, ' ')) == NULL)
1683 continue;
1684 *p = 0;
1685 ++p;
1686
1687 switch (*buf) {
1688 case 'U':
1689 if (strcmp(buf, "USE:") == 0) strncpy(Pkg.USE, p, sizeof(Pkg.USE));
1690 break;
1691 case 'P':
1692 if (strcmp(buf, "PF:") == 0) strncpy(Pkg.PF, p, sizeof(Pkg.PF));
1693 break;
1694 case 'S':
1695 if (strcmp(buf, "SIZE:") == 0) Pkg.SIZE = atol(p);
1696 if (strcmp(buf, "SLOT:") == 0) strncpy(Pkg.SLOT, p, sizeof(Pkg.SLOT));
1697 if (strcmp(buf, "SHA1:") == 0) strncpy(Pkg.SHA1, p, sizeof(Pkg.SHA1));
1698 break;
1699 case 'M':
1700 if (strcmp(buf, "MD5:") == 0) strncpy(Pkg.MD5, p, sizeof(Pkg.MD5));
1701 break;
1702 case 'R':
1703 if (strcmp(buf, "REPO:") == 0) strncpy(Pkg.REPO, p, sizeof(Pkg.REPO));
1704 if (strcmp(buf, "RDEPEND:") == 0) strncpy(Pkg.RDEPEND, p, sizeof(Pkg.RDEPEND));
1705 break;
1706 case 'L':
1707 if (strcmp(buf, "LICENSE:") == 0) strncpy(Pkg.LICENSE, p, sizeof(Pkg.LICENSE));
1708 break;
1709 case 'C':
1710 if (strcmp(buf, "CATEGORY:") == 0) strncpy(Pkg.CATEGORY, p, sizeof(Pkg.CATEGORY));
1711 if (strcmp(buf, "CPV:") == 0) {
1712 depend_atom *atom;
1713 if ((atom = atom_explode(p)) != NULL) {
1714 if (atom->PR_int)
1715 snprintf(Pkg.PF, sizeof(Pkg.PF), "%s-%s-r%i", atom->PN, atom->PV, atom->PR_int);
1716 else
1717 snprintf(Pkg.PF, sizeof(Pkg.PF), "%s-%s", atom->PN, atom->PV);
1718 strncpy(Pkg.CATEGORY, atom->CATEGORY, sizeof(Pkg.CATEGORY));
1719 atom_implode(atom);
1720 }
1721 }
1722 break;
1723 case 'D':
1724 if (strcmp(buf, "DESC:") == 0) strncpy(Pkg.DESC, p, sizeof(Pkg.DESC));
1725 break;
1726 default:
1727 break;
1728 }
1729 }
1730
1731 free(buf);
1732 fclose(fp);
1733
1734 return 0;
1735 }
1736
1737 _q_static queue *
1738 qmerge_add_set_atom(char *satom, queue *set)
1739 {
1740 char *p;
1741 const char *slot;
1742
1743 if ((p = strchr(satom, ':')) != NULL) {
1744 *p = 0;
1745 slot = p + 1;
1746 } else
1747 slot = "0";
1748
1749 return add_set(satom, slot, set);
1750 }
1751
1752 _q_static queue *
1753 qmerge_add_set_file(const char *dir, const char *file, queue *set)
1754 {
1755 FILE *fp;
1756 size_t buflen;
1757 char *buf, *fname;
1758
1759 /* Find the file to read */
1760 xasprintf(&fname, "%s%s/%s", portroot, dir, file);
1761
1762 if ((fp = fopen(fname, "r")) == NULL) {
1763 warnp("unable to read set file %s", fname);
1764 free(fname);
1765 return NULL;
1766 }
1767 free(fname);
1768
1769 /* Load each entry */
1770 buf = NULL;
1771 while (getline(&buf, &buflen, fp) != -1) {
1772 rmspace(buf);
1773 set = qmerge_add_set_atom(buf, set);
1774 }
1775 free(buf);
1776
1777 fclose(fp);
1778
1779 return set;
1780 }
1781
1782 _q_static void *
1783 qmerge_add_set_system(void *data, char *buf)
1784 {
1785 queue *set = data;
1786 char *s;
1787
1788 s = strchr(buf, '#');
1789 if (s)
1790 *s = '\0';
1791 rmspace(buf);
1792
1793 s = buf;
1794 if (*s == '*')
1795 set = add_set(s + 1, "", set);
1796 else if (s[0] == '-' && s[1] == '*') {
1797 int ok;
1798 set = del_set(s + 2, set, &ok);
1799 }
1800
1801 return set;
1802 }
1803
1804 /* XXX: note, this doesn't handle more complicated set files like
1805 * the portage .ini files in /usr/share/portage/sets/ */
1806 /* XXX: this code does not combine duplicate dependencies */
1807 _q_static queue *
1808 qmerge_add_set(char *buf, queue *set)
1809 {
1810 if (strcmp(buf, "world") == 0)
1811 return qmerge_add_set_file("/var/lib/portage", "world", set);
1812 else if (strcmp(buf, "all") == 0)
1813 return get_vdb_atoms(0);
1814 else if (strcmp(buf, "system") == 0)
1815 return q_profile_walk("packages", qmerge_add_set_system, set);
1816 else if (buf[0] == '@')
1817 return qmerge_add_set_file("/etc/portage", buf+1, set);
1818 else
1819 return qmerge_add_set_atom(buf, set);
1820 }
1821
1822 _q_static int
1823 qmerge_run(queue *todo)
1824 {
1825 if (uninstall)
1826 return unmerge_packages(todo);
1827 else
1828 return parse_packages(todo);
1829 }
1830
1831 int qmerge_main(int argc, char **argv)
1832 {
1833 int i, ret;
1834 queue *todo;
1835
1836 if (argc < 2)
1837 qmerge_usage(EXIT_FAILURE);
1838
1839 while ((i = GETOPT_LONG(QMERGE, qmerge, "")) != -1) {
1840 switch (i) {
1841 case 'f': force_download = 1; break;
1842 case 'F': force_download = 2; break;
1843 case 's': search_pkgs = 1; break;
1844 /* case 'i': case 'g': */
1845 case 'K': install = 1; break;
1846 case 'U': uninstall = 1; break;
1847 case 'p': pretend = 1; break;
1848 case 'u': update_only = 1;
1849 case 'y': interactive = 0; break;
1850 case 'O': follow_rdepends = 0; break;
1851 case '5': nomd5 = 1; break;
1852 COMMON_GETOPTS_CASES(qmerge)
1853 }
1854 }
1855
1856 qmerge_strict = (strstr("strict", features) == 0) ? 1 : 0;
1857
1858 /* Short circut this. */
1859 if ((install || uninstall) && !pretend) {
1860 if (follow_rdepends && getenv("QMERGE") == NULL) {
1861 uninstall = 0;
1862 install = 0;
1863 warn("Using these options are likely to break your system at this point. export QMERGE=1; if you think you know what your doing.");
1864 }
1865 }
1866
1867 /* Expand any portage sets on the command line */
1868 todo = NULL;
1869 for (i = optind; i < argc; ++i)
1870 todo = qmerge_add_set(argv[i], todo);
1871
1872 if (!uninstall)
1873 qmerge_initialize();
1874
1875 /* Make sure the user wants to do it */
1876 if (interactive) {
1877 int save_pretend = pretend;
1878 int save_verbose = verbose;
1879 int save_quiet = quiet;
1880
1881 pretend = 100;
1882 verbose = 0;
1883 quiet = 1;
1884 ret = qmerge_run(todo);
1885 if (ret || save_pretend)
1886 return ret;
1887
1888 if (uninstall) {
1889 if (!prompt("OK to unmerge these packages"))
1890 return 0;
1891 } else {
1892 if (!prompt("OK to merge these packages"))
1893 return 0;
1894 }
1895
1896 pretend = save_pretend;
1897 verbose = save_verbose;
1898 quiet = save_quiet;
1899 }
1900
1901 ret = qmerge_run(todo);
1902 free_sets(todo);
1903 return ret;
1904 }
1905
1906 #else
1907 DEFINE_APPLET_STUB(qmerge)
1908 #endif

  ViewVC Help
Powered by ViewVC 1.1.20