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

Contents of /portage-utils/main.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.227 - (show annotations) (download) (as text)
Thu May 23 03:19:00 2013 UTC (19 months ago) by vapier
Branch: MAIN
Changes since 1.226: +4 -1 lines
File MIME type: text/x-csrc
use 64bit file interfaces even with 32bit processes #471024

1 /*
2 * Copyright 2005-2008 Gentoo Foundation
3 * Distributed under the terms of the GNU General Public License v2
4 * $Header: /var/cvsroot/gentoo-projects/portage-utils/main.c,v 1.226 2013/04/03 18:39:22 vapier Exp $
5 *
6 * Copyright 2005-2008 Ned Ludd - <solar@gentoo.org>
7 * Copyright 2005-2008 Mike Frysinger - <vapier@gentoo.org>
8 */
9
10 #ifdef HAVE_CONFIG_H
11 # include "config.h" /* make sure we have EPREFIX, if set */
12 #endif
13
14 #ifndef _GNU_SOURCE
15 #define _GNU_SOURCE
16 #endif
17 #ifndef _FILE_OFFSET_BITS
18 #define _FILE_OFFSET_BITS 64 /* #471024 */
19 #endif
20 #ifdef _AIX
21 #define _LINUX_SOURCE_COMPAT
22 #endif
23
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <stdbool.h>
28 #include <sys/types.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <sys/stat.h>
32 #include <time.h>
33 #include <sys/time.h>
34 #include <ctype.h>
35 #include <dirent.h>
36 #include <getopt.h>
37 #include <regex.h>
38 #include <errno.h>
39 #include <libgen.h>
40 #include <limits.h>
41 #include <assert.h>
42 #include "main.h"
43
44 /* prototypes and such */
45 static char eat_file(const char *file, char *buf, const size_t bufsize);
46 int rematch(const char *, const char *, int);
47 static char *rmspace(char *);
48
49 void initialize_portage_env(void);
50 void initialize_ebuild_flat(void);
51 void reinitialize_ebuild_flat(void);
52 void reinitialize_as_needed(void);
53 void cleanup(void);
54 int lookup_applet_idx(const char *);
55
56 /* variables to control runtime behavior */
57 char *module_name = NULL;
58 char *modpath = NULL;
59 int verbose = 0;
60 int quiet = 0;
61 int portcachedir_type = 0;
62 char pretend = 0;
63 char reinitialize = 0;
64 char reinitialize_metacache = 0;
65 static char *portdir;
66 static char *portarch;
67 static char *portvdb;
68 const char portcachedir_pms[] = "metadata/cache";
69 const char portcachedir_md5[] = "metadata/md5-cache";
70 static char *portroot;
71 static char *eprefix;
72 static char *config_protect, *config_protect_mask;
73
74 static char *pkgdir;
75 static char *port_tmpdir;
76
77 static char *binhost;
78 static char *features;
79 static char *accept_license;
80 static char *install_mask;
81 static char *pkg_install_mask;
82
83 const char err_noapplet[] = "Sorry this applet was disabled at compile time";
84
85 /* helper functions for showing errors */
86 static const char *argv0;
87
88 #ifdef EBUG
89 # include <sys/resource.h>
90 void init_coredumps(void);
91 void init_coredumps(void)
92 {
93 struct rlimit rl;
94 rl.rlim_cur = RLIM_INFINITY;
95 rl.rlim_max = RLIM_INFINITY;
96 setrlimit(RLIMIT_CORE, &rl);
97 }
98 #endif
99
100 /* include common library code */
101 #include "libq/libq.c"
102
103 void no_colors(void);
104 void no_colors()
105 {
106 /* echo $(awk '{print $4,"="}' libq/colors.c | grep ^* |cut -c 2-| grep ^[A-Z] |tr '\n' ' ') = \"\"\; */
107 BOLD = NORM = BLUE = DKBLUE = CYAN = GREEN = DKGREEN = MAGENTA = RED = YELLOW = BRYELLOW = WHITE = "";
108 setenv("NOCOLOR", "true", 1);
109 }
110
111 /* include common applet defs */
112 #include "applets.h"
113
114 /* Common usage for all applets */
115 #define COMMON_FLAGS "vqChV"
116 #define COMMON_LONG_OPTS \
117 {"verbose", no_argument, NULL, 'v'}, \
118 {"quiet", no_argument, NULL, 'q'}, \
119 {"nocolor", no_argument, NULL, 'C'}, \
120 {"help", no_argument, NULL, 'h'}, \
121 {"version", no_argument, NULL, 'V'}, \
122 {NULL, no_argument, NULL, 0x0}
123 #define COMMON_OPTS_HELP \
124 "Make a lot of noise", \
125 "Tighter output; suppress warnings", \
126 "Don't output color", \
127 "Print this help and exit", \
128 "Print version and exit", \
129 NULL
130 #define COMMON_GETOPTS_CASES(applet) \
131 case 'v': ++verbose; break; \
132 case 'q': ++quiet; if (freopen("/dev/null", "w", stderr)) { /* ignore errors */ } break; \
133 case 'V': version_barf( applet ## _rcsid ); break; \
134 case 'h': applet ## _usage(EXIT_SUCCESS); break; \
135 case 'C': no_colors(); break; \
136 default: applet ## _usage(EXIT_FAILURE); break;
137
138 /* display usage and exit */
139 static void usage(int status, const char *flags, struct option const opts[],
140 const char * const help[], int blabber)
141 {
142 unsigned long i;
143 if (status != EXIT_SUCCESS)
144 dup2(STDERR_FILENO, STDOUT_FILENO);
145 if (blabber == 0) {
146 printf("%sUsage:%s %sq%s %s<applet> <args>%s : %s"
147 "invoke a portage utility applet\n\n", GREEN,
148 NORM, YELLOW, NORM, DKBLUE, RED, NORM);
149 printf("%sCurrently defined applets:%s\n", GREEN, NORM);
150 for (i = 0; applets[i].desc; ++i)
151 if (applets[i].func)
152 printf(" %s%8s%s %s%-16s%s%s:%s %s\n",
153 YELLOW, applets[i].name, NORM,
154 DKBLUE, applets[i].opts, NORM,
155 RED, NORM, _(applets[i].desc));
156 } else if (blabber > 0) {
157 printf("%sUsage:%s %s%s%s <opts> %s%s%s %s:%s %s\n", GREEN, NORM,
158 YELLOW, applets[blabber].name, NORM,
159 DKBLUE, applets[blabber].opts, NORM,
160 RED, NORM, _(applets[blabber].desc));
161 }
162 if (module_name != NULL)
163 printf("%sLoaded module:%s\n%s%8s%s %s<args>%s\n", GREEN, NORM, YELLOW, module_name, NORM, DKBLUE, NORM);
164
165 printf("\n%sOptions:%s -[%s]\n", GREEN, NORM, flags);
166 for (i = 0; opts[i].name; ++i) {
167 /* this assert is a life saver when adding new applets. */
168 assert(help[i] != NULL);
169
170 /* first output the short flag if it has one */
171 if (opts[i].val > '~')
172 printf(" ");
173 else
174 printf(" -%c, ", opts[i].val);
175
176 /* then the long flag + help text */
177 if (opts[i].has_arg == no_argument)
178 printf("--%-15s%s*%s %s\n", opts[i].name,
179 RED, NORM, _(help[i]));
180 else
181 printf("--%-8s %s<arg>%s %s*%s %s\n", opts[i].name,
182 DKBLUE, NORM, RED, NORM, _(help[i]));
183 }
184 exit(status);
185 }
186
187 static void version_barf(const char *Id)
188 {
189 #ifndef VERSION
190 # define VERSION "cvs"
191 #endif
192 printf("portage-utils-%s: compiled on %s\n%s\n"
193 "%s written for Gentoo by <solar and vapier @ gentoo.org>\n",
194 VERSION, __DATE__, Id, argv0);
195 exit(EXIT_SUCCESS);
196 }
197
198 static char eat_file_fd(int fd, char *buf, const size_t bufsize)
199 {
200 struct stat s;
201
202 buf[0] = '\0';
203 if (fstat(fd, &s) != 0)
204 return 0;
205 if (s.st_size) {
206 if (bufsize < (size_t)s.st_size)
207 return 0;
208 if (read(fd, buf, s.st_size) != (ssize_t)s.st_size)
209 return 0;
210 buf[s.st_size] = '\0';
211 } else {
212 if (read(fd, buf, bufsize) == 0)
213 return 0;
214 buf[bufsize - 1] = '\0';
215 }
216
217 return 1;
218 }
219
220 static char eat_file_at(int dfd, const char *file, char *buf, const size_t bufsize)
221 {
222 int fd;
223 char ret;
224
225 if ((fd = openat(dfd, file, O_CLOEXEC|O_RDONLY)) == -1) {
226 buf[0] = '\0';
227 return 0;
228 }
229
230 ret = eat_file_fd(fd, buf, bufsize);
231
232 close(fd);
233 return ret;
234 }
235
236 static char eat_file(const char *file, char *buf, const size_t bufsize)
237 {
238 return eat_file_at(AT_FDCWD, file, buf, bufsize);
239 }
240
241 static bool prompt(const char *p)
242 {
243 printf("%s? [Y/n] ", p);
244 fflush(stdout);
245 switch (getc(stdin)) {
246 case '\n':
247 case 'y':
248 case 'Y':
249 return true;
250 default:
251 return false;
252 }
253 }
254
255 int rematch(const char *re, const char *match, int cflags)
256 {
257 regex_t preg;
258 int ret;
259
260 if ((match == NULL) || (re == NULL))
261 return EXIT_FAILURE;
262
263 if (wregcomp(&preg, re, cflags))
264 return EXIT_FAILURE;
265 ret = regexec(&preg, match, 0, NULL, 0);
266 regfree(&preg);
267
268 return ret;
269 }
270
271 /* removes adjacent extraneous white space */
272 static char *remove_extra_space(char *str);
273 static char *remove_extra_space(char *str)
274 {
275 char *p, c = ' ';
276 size_t len, pos = 0;
277 char *buf;
278
279 if (str == NULL)
280 return NULL;
281 len = strlen(str);
282 buf = xzalloc(len+1);
283 for (p = str; *p != 0; ++p) {
284 if (!isspace(*p)) c = *p; else {
285 if (c == ' ') continue;
286 c = ' ';
287 }
288 buf[pos] = c;
289 pos++;
290 }
291 if (pos > 0 && buf[pos-1] == ' ') buf[pos-1] = '\0';
292 strcpy(str, buf);
293 free(buf);
294 return str;
295 }
296
297 static void freeargv(int argc, char **argv)
298 {
299 while (argc--)
300 free(argv[argc]);
301 free(argv);
302 }
303
304 static void makeargv(const char *string, int *argc, char ***argv)
305 {
306 int curc = 2;
307 char *q, *p, *str;
308 (*argv) = xmalloc(sizeof(char **) * curc);
309
310 *argc = 1;
311 (*argv)[0] = xstrdup(argv0);
312 q = xstrdup(string);
313 str = q;
314
315 remove_extra_space(str);
316 rmspace(str);
317
318 while (str) {
319 if ((p = strchr(str, ' ')) != NULL)
320 *(p++) = '\0';
321
322 if (*argc == curc) {
323 curc *= 2;
324 (*argv) = xrealloc(*argv, sizeof(char **) * curc);
325 }
326 (*argv)[*argc] = xstrdup(str);
327 (*argc)++;
328 str = p;
329 }
330 free(q);
331 }
332
333 /*
334 * Parse a line of CONTENTS file and provide access to the individual fields
335 */
336 typedef enum {
337 CONTENTS_DIR, CONTENTS_OBJ, CONTENTS_SYM
338 } contents_type;
339 typedef struct {
340 contents_type type;
341 char *_data;
342 char *name;
343 char *sym_target;
344 char *digest;
345 char *mtime_str;
346 long mtime;
347 } contents_entry;
348
349 contents_entry *contents_parse_line(char *line);
350 contents_entry *contents_parse_line(char *line)
351 {
352 static contents_entry e;
353 char *p;
354
355 if (!line || !*line || *line == '\n')
356 return NULL;
357
358 /* chop trailing newline */
359 if ((p = strrchr(line, '\n')) != NULL)
360 *p = '\0';
361
362 /* ferringb wants to break portage/vdb by using tabs vs spaces
363 * so filenames can have lame ass spaces in them..
364 * (I smell Windows near by)
365 * Anyway we just convert that crap to a space so we can still
366 * parse quickly */
367 p = line;
368 while ((p = strchr(p, '\t')) != NULL)
369 *p = ' ';
370
371 memset(&e, 0x00, sizeof(e));
372 e._data = line;
373
374 if (!strncmp(e._data, "obj ", 4))
375 e.type = CONTENTS_OBJ;
376 else if (!strncmp(e._data, "dir ", 4))
377 e.type = CONTENTS_DIR;
378 else if (!strncmp(e._data, "sym ", 4))
379 e.type = CONTENTS_SYM;
380 else
381 return NULL;
382
383 e.name = e._data + 4;
384
385 switch (e.type) {
386 /* dir /bin */
387 case CONTENTS_DIR:
388 break;
389
390 /* obj /bin/bash 62ed51c8b23866777552643ec57614b0 1120707577 */
391 case CONTENTS_OBJ:
392 if ((e.mtime_str = strrchr(e.name, ' ')) == NULL)
393 return NULL;
394 *e.mtime_str++ = '\0';
395 if ((e.digest = strrchr(e.name, ' ')) == NULL)
396 return NULL;
397 *e.digest++ = '\0';
398 break;
399
400 /* sym /bin/sh -> bash 1120707577 */
401 case CONTENTS_SYM:
402 if ((e.mtime_str = strrchr(e.name, ' ')) == NULL)
403 return NULL;
404 *e.mtime_str++ = '\0';
405 if ((e.sym_target = strstr(e.name, " -> ")) == NULL)
406 return NULL;
407 *e.sym_target = '\0';
408 e.sym_target += 4;
409 break;
410 }
411
412 if (e.mtime_str) {
413 e.mtime = strtol(e.mtime_str, NULL, 10);
414 if (e.mtime == LONG_MAX) {
415 e.mtime = 0;
416 e.mtime_str = NULL;
417 }
418 }
419
420 return &e;
421 }
422
423 static void strincr_var(const char *name, const char *s, char **value, size_t *value_len)
424 {
425 size_t len;
426 char *buf, *p, *nv;
427
428 len = strlen(s);
429 *value = xrealloc(*value, *value_len + len + 2);
430 nv = &(*value)[*value_len];
431 if (*value_len)
432 *nv++ = ' ';
433 memcpy(nv, s, len + 1);
434
435 while ((p = strstr(nv, "-*")) != NULL)
436 memset(*value, ' ', p - *value + 2);
437
438 /* This function is mainly used by the startup code for parsing
439 make.conf and stacking variables remove.
440 variables can be in the form of ${v} or $v
441 works:
442 FEATURES="${FEATURES} foo"
443 FEATURES="$FEATURES foo"
444 FEATURES="baz bar -* foo"
445
446 wont work:
447 FEATURES="${OTHERVAR} foo"
448 FEATURES="-nls nls -nls"
449 FEATURES="nls nls nls"
450 */
451
452 len = strlen(name);
453 buf = alloca(len + 3 + 1);
454
455 sprintf(buf, "${%s}", name);
456 if ((p = strstr(nv, buf)) != NULL)
457 memset(p, ' ', len + 3);
458
459 sprintf(buf, "$%s", name);
460 if ((p = strstr(nv, buf)) != NULL)
461 memset(p, ' ', len + 1);
462
463 remove_extra_space(*value);
464 *value_len = strlen(*value);
465 /* we should sort here */
466 }
467
468 typedef enum { _Q_BOOL, _Q_STR, _Q_ISTR } var_types;
469 typedef struct {
470 const char *name;
471 const size_t name_len;
472 const var_types type;
473 union {
474 char **s;
475 bool *b;
476 } value;
477 size_t value_len;
478 const char *default_value;
479 } env_vars;
480
481 _q_static env_vars *get_portage_env_var(env_vars *vars, const char *name)
482 {
483 size_t i;
484
485 for (i = 0; vars[i].name; ++i)
486 if (!strcmp(vars[i].name, name))
487 return &vars[i];
488
489 return NULL;
490 }
491
492 _q_static void set_portage_env_var(env_vars *var, const char *value)
493 {
494 switch (var->type) {
495 case _Q_BOOL:
496 *var->value.b = 1;
497 break;
498 case _Q_STR:
499 free(*var->value.s);
500 *var->value.s = xstrdup_len(value, &var->value_len);
501 break;
502 case _Q_ISTR:
503 strincr_var(var->name, value, var->value.s, &var->value_len);
504 break;
505 }
506 }
507
508 /* Helper to read a portage env file (e.g. make.conf) */
509 _q_static void read_portage_env_file(const char *configroot, const char *file, env_vars vars[])
510 {
511 size_t i, buflen, line, configroot_len, file_len;
512 FILE *fp;
513 char *buf, *s, *p;
514
515 IF_DEBUG(fprintf(stderr, "profile %s\n", file));
516
517 configroot_len = strlen(configroot);
518 file_len = strlen(file);
519 buflen = configroot_len + file_len + 1;
520 buf = xmalloc(buflen);
521
522 memcpy(buf, configroot, configroot_len);
523 memcpy(buf + configroot_len, file, file_len);
524 buf[buflen - 1] = '\0';
525
526 fp = fopen(buf, "r");
527 if (fp == NULL)
528 goto done;
529
530 line = 0;
531 while (getline(&buf, &buflen, fp) != -1) {
532 ++line;
533 rmspace(buf);
534 if (*buf == '#' || *buf == '\0')
535 continue;
536
537 /* Handle "source" keyword */
538 if (!strncmp(buf, "source ", 7)) {
539 const char *sfile = buf + 7;
540
541 if (sfile[0] != '/') {
542 /* handle relative paths */
543 size_t file_path_len, source_len;
544
545 s = strrchr(file, '/');
546 file_path_len = s - file + 1;
547 source_len = strlen(sfile);
548
549 if (buflen <= source_len + file_path_len)
550 buf = xrealloc(buf, buflen = source_len + file_path_len + 1);
551 memmove(buf + file_path_len, buf + 7, source_len + 1);
552 memcpy(buf, file, file_path_len);
553 sfile = buf;
554 }
555
556 read_portage_env_file(configroot, sfile, vars);
557 continue;
558 }
559
560 /* look for our desired variables and grab their value */
561 for (i = 0; vars[i].name; ++i) {
562 if (buf[vars[i].name_len] != '=' && buf[vars[i].name_len] != ' ')
563 continue;
564 if (strncmp(buf, vars[i].name, vars[i].name_len))
565 continue;
566
567 /* make sure we handle spaces between the varname, the =, and the value:
568 * VAR=val VAR = val VAR="val"
569 */
570 s = buf + vars[i].name_len;
571 if ((p = strchr(s, '=')) != NULL)
572 s = p + 1;
573 while (isspace(*s))
574 ++s;
575 if (*s == '"' || *s == '\'') {
576 char *endq;
577 char q = *s;
578
579 /* make sure we handle spacing/comments after the quote */
580 endq = strchr(s + 1, q);
581 if (!endq) {
582 /* If the last char is not a quote, then we span lines */
583 size_t abuflen;
584 char *abuf;
585
586 abuf = NULL;
587 while (getline(&abuf, &abuflen, fp) != -1) {
588 buf = xrealloc(buf, buflen + abuflen);
589 endq = strchr(abuf, q);
590 if (endq)
591 *endq = '\0';
592
593 strcat(buf, abuf);
594 buflen += abuflen;
595
596 if (endq)
597 break;
598 }
599 free(abuf);
600
601 if (!endq)
602 warn("%s:%zu: %s: quote mismatch", file, line, vars[i].name);
603
604 s = buf + vars[i].name_len + 2;
605 } else {
606 *endq = '\0';
607 ++s;
608 }
609 } else {
610 /* no quotes, so chop the spacing/comments ourselves */
611 size_t off = strcspn(s, "# \t\n");
612 s[off] = '\0';
613 }
614
615 set_portage_env_var(&vars[i], s);
616 }
617 }
618
619 fclose(fp);
620 done:
621 free(buf);
622 }
623
624 /* Helper to recursively read stacked make.defaults in profiles */
625 static void read_portage_profile(const char *configroot, const char *profile, env_vars vars[])
626 {
627 size_t configroot_len, profile_len, sub_len;
628 char *profile_file, *sub_file;
629 char buf[BUFSIZE], *s;
630
631 /* initialize the base profile path */
632 configroot_len = strlen(configroot);
633 profile_len = strlen(profile);
634 sub_len = 1024; /* should be big enough for longest line in "parent" */
635 profile_file = xmalloc(configroot_len + profile_len + sub_len + 2);
636
637 memcpy(profile_file, configroot, configroot_len);
638 memcpy(profile_file + configroot_len, profile, profile_len);
639 sub_file = profile_file + configroot_len + profile_len + 1;
640 sub_file[-1] = '/';
641
642 /* first consume the profile's make.defaults */
643 strcpy(sub_file, "make.defaults");
644 read_portage_env_file("", profile_file, vars);
645
646 /* now walk all the parents */
647 strcpy(sub_file, "parent");
648 if (eat_file(profile_file, buf, sizeof(buf)) == 0)
649 goto done;
650 rmspace(buf);
651
652 s = strtok(buf, "\n");
653 while (s) {
654 strncpy(sub_file, s, sub_len);
655 read_portage_profile("", profile_file, vars);
656 s = strtok(NULL, "\n");
657 }
658
659 done:
660 free(profile_file);
661 }
662
663 void initialize_portage_env(void)
664 {
665 size_t i;
666 const char *s;
667
668 bool nocolor = 0;
669
670 env_vars *var;
671 env_vars vars_to_read[] = {
672 #define _Q_EV(t, V, set, lset, d) \
673 { \
674 .name = #V, \
675 .name_len = strlen(#V), \
676 .type = _Q_##t, \
677 set, \
678 lset, \
679 .default_value = d, \
680 },
681 #define _Q_EVS(t, V, v, d) _Q_EV(t, V, .value.s = &v, .value_len = strlen(d), d)
682 #define _Q_EVB(t, V, v, d) _Q_EV(t, V, .value.b = &v, .value_len = 0, d)
683
684 _Q_EVS(STR, ROOT, portroot, "/")
685 _Q_EVS(STR, ACCEPT_LICENSE, accept_license, "")
686 _Q_EVS(ISTR, INSTALL_MASK, install_mask, "")
687 _Q_EVS(ISTR, PKG_INSTALL_MASK, pkg_install_mask, "")
688 _Q_EVS(STR, ARCH, portarch, "")
689 _Q_EVS(ISTR, CONFIG_PROTECT, config_protect, CONFIG_EPREFIX "etc")
690 _Q_EVS(ISTR, CONFIG_PROTECT_MASK, config_protect_mask, "")
691 _Q_EVB(BOOL, NOCOLOR, nocolor, 0)
692 _Q_EVS(ISTR, FEATURES, features, "noman noinfo nodoc")
693 _Q_EVS(STR, EPREFIX, eprefix, CONFIG_EPREFIX)
694 _Q_EVS(STR, PORTDIR, portdir, CONFIG_EPREFIX "usr/portage")
695 _Q_EVS(STR, PORTAGE_BINHOST, binhost, DEFAULT_PORTAGE_BINHOST)
696 _Q_EVS(STR, PORTAGE_TMPDIR, port_tmpdir, CONFIG_EPREFIX "var/tmp/portage/")
697 _Q_EVS(STR, PKGDIR, pkgdir, CONFIG_EPREFIX "usr/portage/packages/")
698 _Q_EVS(STR, Q_VDB, portvdb, CONFIG_EPREFIX "var/db/pkg")
699 { NULL, 0, _Q_BOOL, { NULL }, 0, NULL, }
700
701 #undef _Q_EV
702 };
703
704 /* initialize all the strings with their default value */
705 for (i = 0; vars_to_read[i].name; ++i) {
706 var = &vars_to_read[i];
707 if (var->type != _Q_BOOL)
708 *var->value.s = xstrdup(var->default_value);
709 }
710
711 /* figure out where to find our config files */
712 s = getenv("PORTAGE_CONFIGROOT");
713 if (!s)
714 s = "/";
715
716 /* walk all the stacked profiles */
717 read_portage_profile(s, CONFIG_EPREFIX "etc/make.profile", vars_to_read);
718 read_portage_profile(s, CONFIG_EPREFIX "etc/portage/make.profile", vars_to_read);
719
720 /* now read all the config files */
721 read_portage_env_file("", CONFIG_EPREFIX "usr/share/portage/config/make.globals", vars_to_read);
722 read_portage_env_file(s, CONFIG_EPREFIX "etc/make.conf", vars_to_read);
723 read_portage_env_file(s, CONFIG_EPREFIX "etc/portage/make.conf", vars_to_read);
724
725 /* finally, check the env */
726 for (i = 0; vars_to_read[i].name; ++i) {
727 var = &vars_to_read[i];
728 s = getenv(var->name);
729 if (s != NULL)
730 set_portage_env_var(var, s);
731 }
732
733 /* expand any nested variables e.g. PORTDIR=${EPREFIX}/usr/portage */
734 for (i = 0; vars_to_read[i].name; ++i) {
735 char *svar;
736
737 var = &vars_to_read[i];
738 if (var->type == _Q_BOOL)
739 continue;
740
741 while ((svar = strchr(*var->value.s, '$'))) {
742 env_vars *evar;
743 bool brace;
744 const char *sval;
745 size_t slen, pre_len, var_len, post_len;
746 char byte;
747
748 pre_len = svar - *var->value.s;
749
750 /* First skip the leading "${" */
751 s = ++svar;
752 brace = (*svar == '{');
753 if (brace)
754 s = ++svar;
755
756 /* Now skip the variable name itself */
757 while (isalnum(*svar) || *svar == '_')
758 ++svar;
759
760 /* Finally skip the trailing "}" */
761 if (brace && *svar != '}') {
762 warn("invalid variable setting: %s\n", *var->value.s);
763 break;
764 }
765
766 var_len = svar - s + 1 + (brace ? 2 : 0);
767
768 byte = *svar;
769 *svar = '\0';
770
771 /* Don't try to expand ourselves */
772 if (strcmp(var->name, s)) {
773 evar = get_portage_env_var(vars_to_read, s);
774 if (evar) {
775 sval = *evar->value.s;
776 } else {
777 sval = getenv(s);
778 if (!sval)
779 sval = "";
780 }
781 } else {
782 sval = "";
783 }
784 *svar = byte;
785 slen = strlen(sval);
786 post_len = strlen(svar + 1);
787 *var->value.s = xrealloc(*var->value.s, pre_len + MAX(var_len, slen) + post_len + 1);
788
789 /*
790 * VAR=XxXxX (slen = 5)
791 * FOO${VAR}BAR
792 * pre_len = 3
793 * var_len = 6
794 * post_len = 3
795 */
796 memmove(*var->value.s + pre_len + slen,
797 *var->value.s + pre_len + var_len,
798 post_len + 1);
799 memcpy(*var->value.s + pre_len, sval, slen);
800 }
801 }
802
803 if (getenv("DEBUG") IF_DEBUG(|| 1)) {
804 for (i = 0; vars_to_read[i].name; ++i) {
805 var = &vars_to_read[i];
806 fprintf(stderr, "%s = ", var->name);
807 switch (var->type) {
808 case _Q_BOOL: fprintf(stderr, "%i\n", *var->value.b); break;
809 case _Q_STR:
810 case _Q_ISTR: fprintf(stderr, "%s\n", *var->value.s); break;
811 }
812 }
813 }
814
815 /* Make sure ROOT always ends in a slash */
816 var = &vars_to_read[0];
817 if ((*var->value.s)[var->value_len - 1] != '/') {
818 portroot = xrealloc(portroot, var->value_len + 2);
819 portroot[var->value_len] = '/';
820 portroot[var->value_len + 1] = '\0';
821 }
822
823 if (getenv("PORTAGE_QUIET") != NULL)
824 quiet = 1;
825
826 if (nocolor)
827 no_colors();
828 else
829 color_remap();
830 }
831
832 enum {
833 CACHE_EBUILD = 1,
834 CACHE_METADATA = 2,
835 CACHE_METADATA_PMS = 10,
836 CACHE_METADATA_MD5 = 11,
837 };
838
839 int filter_hidden(const struct dirent *dentry);
840 int filter_hidden(const struct dirent *dentry)
841 {
842 if (dentry->d_name[0] == '.')
843 return 0;
844 return 1;
845 }
846
847 #define CACHE_EBUILD_FILE (getenv("CACHE_EBUILD_FILE") ? getenv("CACHE_EBUILD_FILE") : ".ebuild.x")
848 #define CACHE_METADATA_FILE ".metadata.x"
849 const char *initialize_flat(int cache_type);
850 const char *initialize_flat(int cache_type)
851 {
852 struct dirent **category, **pn, **eb;
853 struct stat st;
854 struct timeval start, finish;
855 static const char *cache_file;
856 const char *portcachedir_actual;
857 char *p;
858 int a, b, c, d, e, i;
859 int frac, secs, count;
860 FILE *fp;
861
862 a = b = c = d = e = i = 0;
863 count = frac = secs = 0;
864
865 cache_file = (cache_type == CACHE_EBUILD ? CACHE_EBUILD_FILE : CACHE_METADATA_FILE);
866
867 if (chdir(portdir) != 0) {
868 warnp("chdir to PORTDIR '%s' failed", portdir);
869 goto ret;
870 }
871
872 if (cache_type == CACHE_METADATA) {
873 if (chdir(portcachedir_md5) == 0) {
874 portcachedir_type = CACHE_METADATA_MD5;
875 portcachedir_actual = portcachedir_md5;
876 } else if (chdir(portcachedir_pms) == 0) {
877 portcachedir_type = CACHE_METADATA_PMS;
878 portcachedir_actual = portcachedir_pms;
879 } else {
880 warnp("chdir to portage cache '%s/%s' or '%s/%s' failed", portdir, portcachedir_md5, portdir, portcachedir_pms);
881 goto ret;
882 }
883 }
884
885 if (stat(cache_file, &st) != -1)
886 if (st.st_size == 0)
887 unlink(cache_file);
888
889 /* assuming --sync is used with --delete this will get recreated after every merge */
890 if (access(cache_file, R_OK) == 0)
891 goto ret;
892 if (!quiet)
893 warn("Updating ebuild %scache ... ", cache_type == CACHE_EBUILD ? "" : "meta");
894
895 unlink(cache_file);
896 if (errno != ENOENT) {
897 warnfp("unlinking '%s/%s' failed", portdir, cache_file);
898 goto ret;
899 }
900
901 if ((fp = fopen(cache_file, "w")) == NULL) {
902 if (cache_type == CACHE_EBUILD)
903 warnfp("opening '%s/%s' failed", portdir, cache_file);
904 else
905 warnfp("opening '%s/%s/%s' failed", portdir, portcachedir_actual, cache_file);
906 if (errno == EACCES)
907 warnf("You should run this command as root: q -%c",
908 cache_type == CACHE_EBUILD ? 'r' : 'm');
909 goto ret;
910 }
911
912 gettimeofday(&start, NULL);
913
914 if ((a = scandir(".", &category, q_vdb_filter_cat, alphasort)) < 0)
915 goto ret;
916
917 for (i = 0; i < a; i++) {
918 stat(category[i]->d_name, &st);
919 if (!S_ISDIR(st.st_mode))
920 continue;
921 if (strchr(category[i]->d_name, '-') == NULL)
922 if (strncmp(category[i]->d_name, "virtual", 7) != 0)
923 continue;
924
925 if ((b = scandir(category[i]->d_name, &pn, q_vdb_filter_pkg, alphasort)) < 0)
926 continue;
927 for (c = 0; c < b; c++) {
928 char de[_Q_PATH_MAX];
929
930 snprintf(de, sizeof(de), "%s/%s", category[i]->d_name, pn[c]->d_name);
931
932 if (stat(de, &st) < 0)
933 continue;
934
935 switch (cache_type) {
936 case CACHE_EBUILD:
937 if (!S_ISDIR(st.st_mode))
938 continue;
939 break;
940 case CACHE_METADATA:
941 if (S_ISREG(st.st_mode))
942 fprintf(fp, "%s\n", de);
943 continue;
944 break;
945 }
946 if ((e = scandir(de, &eb, filter_hidden, alphasort)) < 0)
947 continue;
948 for (d = 0; d < e; d++) {
949 if ((p = strrchr(eb[d]->d_name, '.')) != NULL)
950 if (strcmp(p, ".ebuild") == 0) {
951 count++;
952 fprintf(fp, "%s/%s/%s\n", category[i]->d_name, pn[c]->d_name, eb[d]->d_name);
953 }
954 }
955 while (d--) free(eb[d]);
956 free(eb);
957 }
958 scandir_free(pn, b);
959 }
960 fclose(fp);
961 scandir_free(category, a);
962
963 if (quiet) goto ret;
964
965 gettimeofday(&finish, NULL);
966 if (start.tv_usec > finish.tv_usec) {
967 finish.tv_usec += 1000000;
968 finish.tv_sec--;
969 }
970 frac = (finish.tv_usec - start.tv_usec);
971 secs = (finish.tv_sec - start.tv_sec);
972 if (secs < 0) secs = 0;
973 if (frac < 0) frac = 0;
974
975 warn("Finished %u entries in %d.%06d seconds", count, secs, frac);
976 if (secs > 120)
977 warn("You should consider using the noatime mount option for PORTDIR='%s' if it's not already enabled", portdir);
978 ret:
979 return cache_file;
980 }
981 #define initialize_ebuild_flat() initialize_flat(CACHE_EBUILD)
982 #define initialize_metadata_flat() initialize_flat(CACHE_METADATA)
983
984 void reinitialize_ebuild_flat(void)
985 {
986 if (chdir(portdir) != 0) {
987 warnp("chdir to PORTDIR '%s' failed", portdir);
988 return;
989 }
990 unlink(CACHE_EBUILD_FILE);
991 initialize_ebuild_flat();
992 }
993
994 void reinitialize_as_needed(void)
995 {
996 if (reinitialize)
997 reinitialize_ebuild_flat();
998 if (reinitialize_metacache)
999 initialize_metadata_flat();
1000 }
1001
1002 typedef struct {
1003 char *_data;
1004 char *DEPEND; /* line 1 */
1005 char *RDEPEND;
1006 char *SLOT;
1007 char *SRC_URI;
1008 char *RESTRICT; /* line 5 */
1009 char *HOMEPAGE;
1010 char *LICENSE;
1011 char *DESCRIPTION;
1012 char *KEYWORDS;
1013 char *INHERITED; /* line 10 */
1014 char *IUSE;
1015 char *CDEPEND;
1016 char *PDEPEND;
1017 char *PROVIDE; /* line 14 */
1018 char *EAPI;
1019 char *PROPERTIES;
1020 depend_atom *atom;
1021 /* These are MD5-Cache only */
1022 char *DEFINED_PHASES;
1023 char *REQUIRED_USE;
1024 char *_eclasses_;
1025 char *_md5_;
1026 } portage_cache;
1027
1028 void cache_free(portage_cache *cache);
1029 portage_cache *cache_read_file_pms(const char *file);
1030 portage_cache *cache_read_file_md5(const char *file);
1031 portage_cache *cache_read_file(const char *file);
1032
1033 portage_cache *cache_read_file(const char *file)
1034 {
1035 if (portcachedir_type == CACHE_METADATA_MD5)
1036 return(cache_read_file_md5(file));
1037 else if (portcachedir_type == CACHE_METADATA_PMS)
1038 return(cache_read_file_pms(file));
1039 warn("Unknown metadata cache type!");
1040 return NULL;
1041 }
1042
1043 portage_cache *cache_read_file_pms(const char *file)
1044 {
1045 struct stat s;
1046 char *ptr;
1047 FILE *f;
1048 portage_cache *ret = NULL;
1049 size_t len;
1050
1051 if ((f = fopen(file, "r")) == NULL)
1052 goto err;
1053
1054 if (fstat(fileno(f), &s) != 0)
1055 goto err;
1056 len = sizeof(*ret) + s.st_size + 1;
1057 ret = xzalloc(len);
1058 ptr = (char*)ret;
1059 ret->_data = ptr + sizeof(*ret);
1060 if ((off_t)fread(ret->_data, 1, s.st_size, f) != s.st_size)
1061 goto err;
1062
1063 ret->atom = atom_explode(file);
1064 ret->DEPEND = ret->_data;
1065 #define next_line(curr, next) \
1066 if ((ptr = strchr(ret->curr, '\n')) == NULL) { \
1067 warn("Invalid cache file '%s'", file); \
1068 goto err; \
1069 } \
1070 ret->next = ptr+1; \
1071 *ptr = '\0';
1072 next_line(DEPEND, RDEPEND)
1073 next_line(RDEPEND, SLOT)
1074 next_line(SLOT, SRC_URI)
1075 next_line(SRC_URI, RESTRICT)
1076 next_line(RESTRICT, HOMEPAGE)
1077 next_line(HOMEPAGE, LICENSE)
1078 next_line(LICENSE, DESCRIPTION)
1079 next_line(DESCRIPTION, KEYWORDS)
1080 next_line(KEYWORDS, INHERITED)
1081 next_line(INHERITED, IUSE)
1082 next_line(IUSE, CDEPEND)
1083 next_line(CDEPEND, PDEPEND)
1084 next_line(PDEPEND, PROVIDE)
1085 next_line(PROVIDE, EAPI)
1086 next_line(EAPI, PROPERTIES)
1087 #undef next_line
1088 ptr = strchr(ptr+1, '\n');
1089 *ptr = '\0';
1090
1091 fclose(f);
1092
1093 return ret;
1094
1095 err:
1096 if (ret) cache_free(ret);
1097 return NULL;
1098 }
1099
1100 portage_cache *cache_read_file_md5(const char *file)
1101 {
1102 struct stat s;
1103 char *ptr, *endptr;
1104 FILE *f;
1105 portage_cache *ret = NULL;
1106 size_t len;
1107
1108 if ((f = fopen(file, "r")) == NULL)
1109 goto err;
1110
1111 if (fstat(fileno(f), &s) != 0)
1112 goto err;
1113 len = sizeof(*ret) + s.st_size + 1;
1114 ret = xzalloc(len);
1115 ptr = (char*)ret;
1116 ret->_data = ptr + sizeof(*ret);
1117 if ((off_t)fread(ret->_data, 1, s.st_size, f) != s.st_size)
1118 goto err;
1119
1120 ret->atom = atom_explode(file);
1121
1122 /* We have a block of key=value\n data.
1123 * KEY=VALUE\n
1124 * Where KEY does NOT contain:
1125 * \0 \n =
1126 * And VALUE does NOT contain:
1127 * \0 \n
1128 * */
1129 #define assign_var_cmp(keyname, cmpkey) \
1130 if (strncmp(keyptr, cmpkey, strlen(cmpkey)) == 0) { \
1131 ret->keyname = valptr; \
1132 continue; \
1133 }
1134 #define assign_var(keyname) \
1135 assign_var_cmp(keyname, #keyname);
1136
1137 ptr = ret->_data;
1138 endptr = strchr(ptr, '\0');
1139 if (endptr == NULL) {
1140 warn("Invalid cache file '%s' - could not find end of cache data", file);
1141 goto err;
1142 }
1143
1144 while (ptr != NULL && ptr != endptr) {
1145 char *keyptr;
1146 char *valptr;
1147 keyptr = ptr;
1148 valptr = strchr(ptr, '=');
1149 if (valptr == NULL) {
1150 warn("Invalid cache file '%s' val", file);
1151 goto err;
1152 }
1153 *valptr = '\0';
1154 valptr++;
1155 ptr = strchr(valptr, '\n');
1156 if (ptr == NULL) {
1157 warn("Invalid cache file '%s' key", file);
1158 goto err;
1159 }
1160 *ptr = '\0';
1161 ptr++;
1162
1163 assign_var(CDEPEND);
1164 assign_var(DEPEND);
1165 assign_var(DESCRIPTION);
1166 assign_var(EAPI);
1167 assign_var(HOMEPAGE);
1168 assign_var(INHERITED);
1169 assign_var(IUSE);
1170 assign_var(KEYWORDS);
1171 assign_var(LICENSE);
1172 assign_var(PDEPEND);
1173 assign_var(PROPERTIES);
1174 assign_var(PROVIDE);
1175 assign_var(RDEPEND);
1176 assign_var(RESTRICT);
1177 assign_var(SLOT);
1178 assign_var(SRC_URI);
1179 assign_var(DEFINED_PHASES);
1180 assign_var(REQUIRED_USE);
1181 assign_var(_eclasses_);
1182 assign_var(_md5_);
1183 warn("Cache file '%s' with unknown key %s", file, keyptr);
1184 }
1185 #undef assign_var
1186 #undef assign_var_cmp
1187
1188 fclose(f);
1189
1190 return ret;
1191
1192 err:
1193 fclose(f);
1194 if (ret) cache_free(ret);
1195 return NULL;
1196 }
1197
1198 void cache_dump(portage_cache *cache);
1199 void cache_dump(portage_cache *cache)
1200 {
1201 if (!cache)
1202 errf("Cache is empty !");
1203
1204 printf("DEPEND : %s\n", cache->DEPEND);
1205 printf("RDEPEND : %s\n", cache->RDEPEND);
1206 printf("SLOT : %s\n", cache->SLOT);
1207 printf("SRC_URI : %s\n", cache->SRC_URI);
1208 printf("RESTRICT : %s\n", cache->RESTRICT);
1209 printf("HOMEPAGE : %s\n", cache->HOMEPAGE);
1210 printf("LICENSE : %s\n", cache->LICENSE);
1211 printf("DESCRIPTION: %s\n", cache->DESCRIPTION);
1212 printf("KEYWORDS : %s\n", cache->KEYWORDS);
1213 printf("INHERITED : %s\n", cache->INHERITED);
1214 printf("IUSE : %s\n", cache->IUSE);
1215 printf("CDEPEND : %s\n", cache->CDEPEND);
1216 printf("PDEPEND : %s\n", cache->PDEPEND);
1217 printf("PROVIDE : %s\n", cache->PROVIDE);
1218 printf("EAPI : %s\n", cache->EAPI);
1219 printf("PROPERTIES : %s\n", cache->PROPERTIES);
1220 if (!cache->atom) return;
1221 printf("CATEGORY : %s\n", cache->atom->CATEGORY);
1222 printf("PN : %s\n", cache->atom->PN);
1223 printf("PV : %s\n", cache->atom->PV);
1224 printf("PVR : %s\n", cache->atom->PVR);
1225 }
1226
1227 void cache_free(portage_cache *cache)
1228 {
1229 if (!cache)
1230 errf("Cache is empty !");
1231 atom_implode(cache->atom);
1232 free(cache);
1233 }
1234
1235 char *atom_to_pvr(depend_atom *atom);
1236 char *atom_to_pvr(depend_atom *atom) {
1237 return (atom->PR_int == 0 ? atom->P : atom->PVR );
1238 }
1239
1240 static char *grab_vdb_item(const char *item, const char *CATEGORY, const char *PF)
1241 {
1242 static char buf[_Q_PATH_MAX];
1243
1244 snprintf(buf, sizeof(buf), "%s%s/%s/%s/%s", portroot, portvdb, CATEGORY, PF, item);
1245 eat_file(buf, buf, sizeof(buf));
1246 rmspace(buf);
1247
1248 return buf;
1249 }
1250
1251 _q_static queue *get_vdb_atoms(int fullcpv)
1252 {
1253 q_vdb_ctx *ctx;
1254
1255 int cfd, j;
1256 int dfd, i;
1257
1258 char buf[_Q_PATH_MAX];
1259 char slot[_Q_PATH_MAX];
1260
1261 struct dirent **cat;
1262 struct dirent **pf;
1263
1264 depend_atom *atom = NULL;
1265 queue *cpf = NULL;
1266
1267 ctx = q_vdb_open();
1268 if (!ctx)
1269 return NULL;
1270
1271 /* scan the cat first */
1272 if ((cfd = scandirat(ctx->vdb_fd, ".", &cat, q_vdb_filter_cat, alphasort)) < 0)
1273 goto fuckit;
1274
1275 for (j = 0; j < cfd; j++) {
1276 if ((dfd = scandirat(ctx->vdb_fd, cat[j]->d_name, &pf, q_vdb_filter_pkg, alphasort)) < 0)
1277 continue;
1278 for (i = 0; i < dfd; i++) {
1279 snprintf(buf, sizeof(buf), "%s/%s", cat[j]->d_name, pf[i]->d_name);
1280 if ((atom = atom_explode(buf)) == NULL)
1281 continue;
1282
1283 slot[0] = '0';
1284 slot[1] = 0;
1285 strncat(buf, "/SLOT", sizeof(buf));
1286 eat_file_at(ctx->vdb_fd, buf, buf, sizeof(buf));
1287 rmspace(buf);
1288
1289 if (fullcpv) {
1290 if (atom->PR_int)
1291 snprintf(buf, sizeof(buf), "%s/%s-%s-r%i", atom->CATEGORY, atom->PN, atom->PV, atom->PR_int);
1292 else
1293 snprintf(buf, sizeof(buf), "%s/%s-%s", atom->CATEGORY, atom->PN, atom->PV);
1294 } else {
1295 snprintf(buf, sizeof(buf), "%s/%s", atom->CATEGORY, atom->PN);
1296 }
1297 atom_implode(atom);
1298 cpf = add_set(buf, slot, cpf);
1299 }
1300 scandir_free(pf, dfd);
1301 }
1302 scandir_free(cat, cfd);
1303
1304 fuckit:
1305 q_vdb_close(ctx);
1306 return cpf;
1307 }
1308
1309 void cleanup(void)
1310 {
1311 reinitialize_as_needed();
1312 free_sets(virtuals);
1313 fclose(stderr);
1314 }
1315
1316 int main(int argc, char **argv)
1317 {
1318 struct stat st;
1319 IF_DEBUG(init_coredumps());
1320 argv0 = argv[0];
1321
1322 #ifdef ENABLE_NLS /* never tested */
1323 setlocale(LC_ALL, "");
1324 bindtextdomain(argv0, CONFIG_EPREFIX "usr/share/locale");
1325 textdomain(argv0);
1326 #endif
1327 #if 1
1328 if (fstat(fileno(stdout), &st) != -1)
1329 if (!isatty(fileno(stdout)))
1330 if (S_ISFIFO(st.st_mode) == 0)
1331 no_colors();
1332 #endif
1333 if ((getenv("TERM") == NULL) || (strcmp(getenv("TERM"), "dumb") == 0))
1334 no_colors();
1335
1336 initialize_portage_env();
1337 atexit(cleanup);
1338 optind = 0;
1339 return q_main(argc, argv);
1340 }
1341
1342 #include "include_applets.h"

  ViewVC Help
Powered by ViewVC 1.1.20