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

Contents of /portage-utils/qpkg.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.38 - (show annotations) (download) (as text)
Sun Oct 28 04:16:19 2012 UTC (21 months, 3 weeks ago) by vapier
Branch: MAIN
Changes since 1.37: +4 -4 lines
File MIME type: text/x-csrc
kill off more spurious/useless parens

1 /*
2 * Copyright 2005-2010 Gentoo Foundation
3 * Distributed under the terms of the GNU General Public License v2
4 * $Header: /var/cvsroot/gentoo-projects/portage-utils/qpkg.c,v 1.37 2012/01/08 09:53:35 solar Exp $
5 *
6 * Copyright 2005-2010 Ned Ludd - <solar@gentoo.org>
7 * Copyright 2005-2010 Mike Frysinger - <vapier@gentoo.org>
8 */
9
10 #ifdef APPLET_qpkg
11
12 #include <fnmatch.h>
13
14 #define QPKG_FLAGS "cEpP:" COMMON_FLAGS
15 static struct option const qpkg_long_opts[] = {
16 {"clean", no_argument, NULL, 'c'},
17 {"eclean", no_argument, NULL, 'E'},
18 {"pretend", no_argument, NULL, 'p'},
19 {"pkgdir", a_argument, NULL, 'P'},
20 COMMON_LONG_OPTS
21 };
22 static const char * const qpkg_opts_help[] = {
23 "clean pkgdir of unused binary files",
24 "clean pkgdir of files not in the tree anymore (slow)",
25 "pretend only",
26 "alternate package directory",
27 COMMON_OPTS_HELP
28 };
29 static const char qpkg_rcsid[] = "$Id: qpkg.c,v 1.37 2012/01/08 09:53:35 solar Exp $";
30 #define qpkg_usage(ret) usage(ret, QPKG_FLAGS, qpkg_long_opts, qpkg_opts_help, lookup_applet_idx("qpkg"))
31
32 extern char pretend;
33
34 static char *qpkg_bindir = NULL;
35 static int eclean = 0;
36
37 /* global functions */
38 int filter_tbz2(const struct dirent *);
39 uint64_t qpkg_clean_dir(char *, queue *);
40 int qpkg_clean(char *);
41 const char *qpkg_get_bindir(void);
42 int qpkg_make(depend_atom *);
43
44 /* checks to make sure this is a .tbz2 file. used by scandir() */
45 int filter_tbz2(const struct dirent *dentry)
46 {
47 if (dentry->d_name[0] == '.')
48 return 0;
49 if (strlen(dentry->d_name) < 6)
50 return 0;
51 return !strcmp(".tbz2", dentry->d_name + strlen(dentry->d_name) - 5);
52 }
53
54 /* process a single dir for cleaning. dir can be a $PKGDIR, $PKGDIR/All/, $PKGDIR/$CAT */
55 uint64_t qpkg_clean_dir(char *dirp, queue *vdb)
56 {
57 queue *ll;
58 struct dirent **fnames;
59 int i, count;
60 char buf[_Q_PATH_MAX];
61 struct stat st;
62 uint64_t num_all_bytes = 0;
63 size_t disp_units = 0;
64
65 if (dirp == NULL)
66 return 0;
67 if (chdir(dirp) != 0)
68 return 0;
69 if ((count = scandir(".", &fnames, filter_tbz2, alphasort)) < 0)
70 return 0;
71
72 for (i = 0; i < count; i++) {
73 int del = 1;
74 fnames[i]->d_name[strlen(fnames[i]->d_name)-5] = 0;
75 for (ll = vdb; ll != NULL; ll = ll->next) {
76 if (1) {
77 if (strcmp(fnames[i]->d_name, basename(ll->name)) == 0) {
78 del = 0;
79 break;
80 }
81 }
82 }
83 if (!del)
84 continue;
85 snprintf(buf, sizeof(buf), "%s.tbz2", fnames[i]->d_name);
86 if (lstat(buf, &st) != -1) {
87 if (S_ISREG(st.st_mode)) {
88 disp_units = KILOBYTE;
89 if ((st.st_size / KILOBYTE) > 1000)
90 disp_units = MEGABYTE;
91 num_all_bytes += st.st_size;
92 qprintf(" %s[%s%s %3s %s %s%s]%s %s%s/%s%s\n", DKBLUE, NORM, GREEN, make_human_readable_str(st.st_size, 1, disp_units),
93 disp_units == MEGABYTE ? "M" : "K", NORM, DKBLUE, NORM, CYAN, basename(dirp), fnames[i]->d_name, NORM);
94 }
95 if (!pretend)
96 unlink(buf);
97 }
98 }
99
100 scandir_free(fnames, count);
101
102 return num_all_bytes;
103 }
104
105 /* figure out what dirs we want to process for cleaning and display results. */
106 int qpkg_clean(char *dirp)
107 {
108 FILE *fp;
109 int i, count;
110 size_t disp_units = 0;
111 uint64_t num_all_bytes;
112 struct dirent **dnames;
113 queue *vdb;
114
115 vdb = get_vdb_atoms(1);
116
117 if (chdir(dirp) != 0) {
118 free_sets(vdb);
119 return 1;
120 }
121 if ((count = scandir(".", &dnames, filter_hidden, alphasort)) < 0) {
122 free_sets(vdb);
123 return 1;
124 }
125
126 if (eclean) {
127 char fname[_Q_PATH_MAX] = "";
128 const char *ecache;
129
130 /* CACHE_EBUILD_FILE is a macro so don't put it in the .bss */
131 ecache = CACHE_EBUILD_FILE;
132
133 if (ecache) {
134 if (*ecache != '/')
135 snprintf(fname, sizeof(fname), "%s/%s", portdir, ecache);
136 else
137 strncpy(fname, ecache, sizeof(fname));
138 }
139 if ((fp = fopen(fname, "r")) != NULL) {
140 size_t buflen;
141 char *buf;
142
143 buf = NULL;
144 while (getline(&buf, &buflen, fp) != -1) {
145 char *name, *p;
146 if ((p = strrchr(buf, '.')) == NULL)
147 continue;
148 *p = 0;
149 if ((p = strrchr(buf, '/')) == NULL)
150 continue;
151 *p = 0;
152 name = p + 1;
153 if ((p = strrchr(buf, '/')) == NULL)
154 continue;
155 *p = 0;
156 /* these strcat() are safe. the name is extracted from buf already. */
157 strcat(buf, "/");
158 strcat(buf, name);
159
160 /* num_all_bytes will be off when pretend and eclean are enabled together */
161 /* vdb = del_set(buf, vdb, &i); */
162 vdb = add_set(buf, "0", vdb);
163 }
164
165 free(buf);
166 fclose(fp);
167 }
168 }
169
170 num_all_bytes = qpkg_clean_dir(dirp, vdb);
171
172 for (i = 0; i < count; i++) {
173 char buf[_Q_PATH_MAX];
174 snprintf(buf, sizeof(buf), "%s/%s", dirp, dnames[i]->d_name);
175 num_all_bytes += qpkg_clean_dir(buf, vdb);
176 }
177 scandir_free(dnames, count);
178
179 free_sets(vdb);
180
181 disp_units = KILOBYTE;
182 if ((num_all_bytes / KILOBYTE) > 1000)
183 disp_units = MEGABYTE;
184 qprintf(" %s*%s Total space that would be freed in packages directory: %s%s %c%s\n", GREEN, NORM, RED,
185 make_human_readable_str(num_all_bytes, 1, disp_units), disp_units == MEGABYTE ? 'M' : 'K', NORM);
186
187 return 0;
188 }
189
190 const char *qpkg_get_bindir(void)
191 {
192 if (qpkg_bindir != NULL)
193 return qpkg_bindir;
194 if (getuid() == 0)
195 return "/var/tmp/binpkgs";
196 if (getenv("HOME") == NULL)
197 errp("Your $HOME env var isn't set, aborting");
198 xasprintf(&qpkg_bindir, "%s/binpkgs", getenv("HOME"));
199
200 return qpkg_bindir;
201 }
202
203 int check_pkg_install_mask(char *name);
204 int check_pkg_install_mask(char *name)
205 {
206 int i, iargc, ret;
207 char **iargv;
208
209 i = iargc = ret = 0;
210
211 if (*name != '/')
212 return ret;
213
214 makeargv(pkg_install_mask, &iargc, &iargv);
215
216 for (i = 1; i < iargc; i++) {
217 if (fnmatch(iargv[i], name, 0) != 0)
218 continue;
219 ret = 1;
220 break;
221 }
222 freeargv(iargc, iargv);
223 return ret;
224 }
225
226 int qpkg_make(depend_atom *atom)
227 {
228 FILE *fp, *out;
229 char tmpdir[BUFSIZE], filelist[BUFSIZE], xpak[BUFSIZE], tbz2[BUFSIZE];
230 size_t buflen;
231 char *buf;
232 int i;
233 char *xpak_argv[2];
234 struct stat st;
235
236 if (pretend) {
237 printf(" %s-%s %s/%s:\n", GREEN, NORM, atom->CATEGORY, atom_to_pvr(atom));
238 return 0;
239 }
240
241 buflen = _Q_PATH_MAX;
242 buf = xmalloc(buflen);
243
244 snprintf(buf, buflen, "%s/%s/%s/CONTENTS", portvdb, atom->CATEGORY, atom_to_pvr(atom));
245 if ((fp = fopen(buf, "r")) == NULL)
246 return -1;
247
248 snprintf(tmpdir, sizeof(tmpdir), "%s/qpkg.XXXXXX", qpkg_get_bindir());
249 if ((i = mkstemp(tmpdir)) == -1)
250 return -2;
251 close(i);
252 unlink(tmpdir);
253 if (mkdir(tmpdir, 0750))
254 return -3;
255
256 snprintf(filelist, sizeof(filelist), "%s/filelist", tmpdir);
257 if ((out = fopen(filelist, "w")) == NULL)
258 return -4;
259
260 while (getline(&buf, &buflen, fp) != -1) {
261 contents_entry *e;
262 e = contents_parse_line(buf);
263 if (!e || e->type == CONTENTS_DIR)
264 continue;
265 if (check_pkg_install_mask(e->name) != 0)
266 continue;
267 fprintf(out, "%s\n", e->name+1); /* dont output leading / */
268 if (e->type == CONTENTS_OBJ && verbose) {
269 char *hash = (char *)hash_file(e->name, HASH_MD5);
270 if (hash != NULL) {
271 if (strcmp(e->digest, hash) != 0)
272 warn("MD5: mismatch expected %s got %s for %s", e->digest, hash, e->name);
273 free(hash);
274 }
275 }
276 }
277
278 fclose(out);
279 fclose(fp);
280
281 printf(" %s-%s %s/%s: ", GREEN, NORM, atom->CATEGORY, atom_to_pvr(atom));
282 fflush(stdout);
283
284 snprintf(tbz2, sizeof(tbz2), "%s/bin.tar.bz2", tmpdir);
285 snprintf(buf, buflen, "tar jcf '%s' --files-from='%s' --no-recursion >/dev/null 2>&1", tbz2, filelist);
286 if ((fp = popen(buf, "r")) == NULL)
287 return 2;
288 pclose(fp);
289
290 snprintf(xpak, sizeof(xpak), "%s/inf.xpak", tmpdir);
291 snprintf(buf, buflen, "%s/%s/%s", portvdb, atom->CATEGORY, atom_to_pvr(atom));
292 xpak_argv[0] = buf;
293 xpak_argv[1] = NULL;
294 xpak_create(AT_FDCWD, xpak, 1, xpak_argv);
295
296 snprintf(buf, buflen, "%s/binpkg.tbz2", tmpdir);
297 tbz2_compose(AT_FDCWD, tbz2, xpak, buf);
298
299 unlink(filelist);
300 unlink(xpak);
301 unlink(tbz2);
302
303 snprintf(tbz2, sizeof(tbz2), "%s/%s.tbz2", qpkg_get_bindir(), atom_to_pvr(atom));
304 if (rename(buf, tbz2)) {
305 warnp("could not move '%s' to '%s'", buf, tbz2);
306 return 1;
307 }
308
309 rmdir(tmpdir);
310
311 stat(tbz2, &st);
312 printf("%s%s%s kB\n", RED, make_human_readable_str(st.st_size, 1, KILOBYTE), NORM);
313
314 return 0;
315 }
316
317 int qpkg_main(int argc, char **argv)
318 {
319 q_vdb_ctx *ctx;
320 q_vdb_cat_ctx *cat_ctx;
321 q_vdb_pkg_ctx *pkg_ctx;
322 size_t s, pkgs_made;
323 int i;
324 struct stat st;
325 char buf[BUFSIZE];
326 const char *bindir;
327 depend_atom *atom;
328 int restrict_chmod = 0;
329 int qclean = 0;
330 DBG("argc=%d argv[0]=%s argv[1]=%s",
331 argc, argv[0], argc > 1 ? argv[1] : "NULL?");
332
333 while ((i = GETOPT_LONG(QPKG, qpkg, "")) != -1) {
334 switch (i) {
335 case 'E': eclean = qclean = 1; break;
336 case 'c': qclean = 1; break;
337 case 'p': pretend = 1; break;
338 case 'P':
339 restrict_chmod = 1;
340 qpkg_bindir = xstrdup(optarg);
341 if (access(qpkg_bindir, W_OK) != 0)
342 errp("%s", qpkg_bindir);
343 break;
344 COMMON_GETOPTS_CASES(qpkg)
345 }
346 }
347 if (qclean)
348 return qpkg_clean(qpkg_bindir == NULL ? pkgdir : qpkg_bindir);
349
350 if (argc == optind)
351 qpkg_usage(EXIT_FAILURE);
352
353 xchdir(portroot);
354
355 /* setup temp dirs */
356 i = 0;
357 bindir = qpkg_get_bindir();
358 if (*bindir != '/')
359 err("'%s' is not a valid package destination", bindir);
360 retry_mkdir:
361 if (mkdir(bindir, 0750) == -1) {
362 lstat(bindir, &st);
363 if (!S_ISDIR(st.st_mode)) {
364 unlink(bindir);
365 if (!i++) goto retry_mkdir;
366 errp("could not create temp bindir '%s'", bindir);
367 }
368 if (!restrict_chmod)
369 if (chmod(bindir, 0750))
370 errp("could not chmod(0750) temp bindir '%s'", bindir);
371 }
372
373 /* first process any arguments which point to /var/db/pkg */
374 pkgs_made = 0;
375 s = strlen(portvdb);
376 for (i = optind; i < argc; ++i) {
377 size_t asize = strlen(argv[i]);
378 if (asize == 0) {
379 argv[i] = NULL;
380 continue;
381 }
382 if (argv[i][asize-1] == '/')
383 argv[i][asize-1] = '\0';
384 if (!strncmp(portvdb, argv[i], s))
385 memmove(argv[i], argv[i]+s+1, asize-s);
386 else if (argv[i][0] == '/' && !strncmp(portvdb, argv[i]+1, s))
387 memmove(argv[i], argv[i]+s+2, asize-s-1);
388 else
389 continue;
390
391 atom = atom_explode(argv[i]);
392 if (atom) {
393 if (!qpkg_make(atom)) ++pkgs_made;
394 atom_implode(atom);
395 } else
396 warn("could not explode '%s'", argv[i]);
397 argv[i] = NULL;
398 }
399
400 /* now try to run through vdb and locate matches for user inputs */
401 ctx = q_vdb_open();
402 if (!ctx)
403 return EXIT_FAILURE;
404
405 /* scan all the categories */
406 while ((cat_ctx = q_vdb_next_cat(ctx))) {
407 /* scan all the packages in this category */
408 const char *catname = cat_ctx->name;
409 while ((pkg_ctx = q_vdb_next_pkg(cat_ctx))) {
410 const char *pkgname = pkg_ctx->name;
411
412 /* see if user wants any of these packages */
413 snprintf(buf, sizeof(buf), "%s/%s", catname, pkgname);
414 atom = atom_explode(buf);
415 if (!atom) {
416 warn("could not explode '%s'", buf);
417 goto next_pkg;
418 }
419 snprintf(buf, sizeof(buf), "%s/%s", atom->CATEGORY, atom->PN);
420 for (i = optind; i < argc; ++i) {
421 if (!argv[i]) continue;
422
423 if (!strcmp(argv[i], atom->PN) || !strcmp(argv[i], atom->P) || !strcmp(argv[i], buf) || !strcmp(argv[i], "world"))
424 if (!qpkg_make(atom)) ++pkgs_made;
425 }
426 atom_implode(atom);
427
428 next_pkg:
429 q_vdb_close_pkg(pkg_ctx);
430 }
431 }
432
433 s = (argc - optind) - pkgs_made;
434 if (s && !pretend)
435 printf(" %s*%s %i package%s could not be matched :/\n", RED, NORM, (int)s, (s > 1 ? "s" : ""));
436 if (pkgs_made)
437 qprintf(" %s*%s Packages can be found in %s\n", GREEN, NORM, bindir);
438
439 return (pkgs_made ? EXIT_SUCCESS : EXIT_FAILURE);
440 }
441
442 #else
443 DEFINE_APPLET_STUB(qpkg)
444 #endif

  ViewVC Help
Powered by ViewVC 1.1.20