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

Contents of /portage-utils/qmerge.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.139 - (show annotations) (download) (as text)
Tue Feb 18 07:26:14 2014 UTC (6 months, 1 week ago) by vapier
Branch: MAIN
Changes since 1.138: +4 -17 lines
File MIME type: text/x-csrc
drop support for old style virtuals as the tree has not carried them in a long time

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

  ViewVC Help
Powered by ViewVC 1.1.20