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

Contents of /portage-utils/qmerge.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.119 - (show annotations) (download) (as text)
Mon Apr 22 03:55:18 2013 UTC (12 months ago) by vapier
Branch: MAIN
Changes since 1.118: +4 -3 lines
File MIME type: text/x-csrc
qmerge: create tmpdirs before trying to use them

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

  ViewVC Help
Powered by ViewVC 1.1.20