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

Contents of /portage-utils/main.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.229 - (show annotations) (download) (as text)
Thu Oct 31 02:40:23 2013 UTC (10 months, 3 weeks ago) by vapier
Branch: MAIN
Changes since 1.228: +2 -2 lines
File MIME type: text/x-csrc
fix bug related to var parsing w/out braces

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

  ViewVC Help
Powered by ViewVC 1.1.20