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

Contents of /portage-utils/main.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.226 - (show annotations) (download) (as text)
Wed Apr 3 18:39:22 2013 UTC (17 months, 2 weeks ago) by vapier
Branch: MAIN
Changes since 1.225: +3 -1 lines
File MIME type: text/x-csrc
dump usage to stderr when an error has happened to avoid things like foo=`qlist $emptyvar` from inserting content into $foo

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

  ViewVC Help
Powered by ViewVC 1.1.20