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

Contents of /portage-utils/main.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.232 - (show annotations) (download) (as text)
Tue Feb 25 21:30:50 2014 UTC (6 months ago) by vapier
Branch: MAIN
Changes since 1.231: +5 -2 lines
File MIME type: text/x-csrc
add support for setting ROOT via cmdline --root flag http://crbug.com/336871

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

  ViewVC Help
Powered by ViewVC 1.1.20