]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/pkg_install/create/perform.c
This commit was generated by cvs2svn to compensate for changes in r175189,
[FreeBSD/FreeBSD.git] / usr.sbin / pkg_install / create / perform.c
1 /*
2  * FreeBSD install - a package for the installation and maintainance
3  * of non-core utilities.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * Jordan K. Hubbard
15  * 18 July 1993
16  *
17  * This is the main body of the create module.
18  *
19  */
20
21 #include <sys/cdefs.h>
22 __FBSDID("$FreeBSD$");
23
24 #include "lib.h"
25 #include "create.h"
26
27 #include <err.h>
28 #include <libgen.h>
29 #include <signal.h>
30 #include <stdlib.h>
31 #include <sys/syslimits.h>
32 #include <sys/wait.h>
33 #include <unistd.h>
34
35 static void sanity_check(void);
36 static void make_dist(const char *, const char *, const char *, Package *);
37 static int create_from_installed_recursive(const char *, const char *);
38 static int create_from_installed(const char *, const char *, const char *);
39
40 static char *home;
41
42 int
43 pkg_perform(char **pkgs)
44 {
45     char *pkg = *pkgs;          /* Only one arg to create */
46     char *cp;
47     FILE *pkg_in, *fp;
48     Package plist;
49     int len;
50     const char *suf;
51
52     /* Preliminary setup */
53     if (InstalledPkg == NULL)
54         sanity_check();
55     if (Verbose && !PlistOnly)
56         printf("Creating package %s\n", pkg);
57
58     /* chop suffix off if already specified, remembering if we want to compress  */
59     len = strlen(pkg);
60     if (len > 4) {
61         if (!strcmp(&pkg[len - 4], ".tbz")) {
62             Zipper = BZIP2;
63             pkg[len - 4] = '\0';
64         }
65         else if (!strcmp(&pkg[len - 4], ".tgz")) {
66             Zipper = GZIP;
67             pkg[len - 4] = '\0';
68         }
69         else if (!strcmp(&pkg[len - 4], ".tar")) {
70             Zipper = NONE;
71             pkg[len - 4] = '\0';
72         }
73     }
74     if (Zipper == BZIP2) {
75         suf = "tbz";
76         setenv("BZIP2", "--best", 0);
77     } else if (Zipper == GZIP) {
78         suf = "tgz";
79         setenv("GZIP", "-9", 0);
80     } else
81         suf = "tar";
82
83     if (InstalledPkg != NULL) {
84         char *pkgglob[] = { InstalledPkg, NULL };
85         char **matched, **pkgs;
86         int i, error;
87
88         pkgs = pkgglob;
89         if (MatchType != MATCH_EXACT) {
90                 matched = matchinstalled(MatchType, pkgs, &error);
91                 if (!error && matched != NULL)
92                         pkgs = matched;
93                 else if (MatchType != MATCH_GLOB)
94                         errx(1, "no packages match pattern");
95         }
96         /*
97          * Is there is only one installed package matching the pattern,
98          * we need to respect the optional pkg-filename parameter.  If,
99          * however, the pattern matches several packages, this parameter
100          * makes no sense and is ignored.
101          */
102         if (pkgs[1] == NULL) {
103             if (pkg == InstalledPkg)
104                 pkg = *pkgs;
105             InstalledPkg = *pkgs;
106             if (!Recursive)
107                 return (create_from_installed(InstalledPkg, pkg, suf));
108             return (create_from_installed_recursive(pkg, suf));
109         }
110         for (i = 0; pkgs[i] != NULL; i++) {
111             InstalledPkg = pkg = pkgs[i];
112             if (!Recursive)
113                 create_from_installed(pkg, pkg, suf);
114             else
115                 create_from_installed_recursive(pkg, suf);
116         }
117         return TRUE;
118     }
119
120     get_dash_string(&Comment);
121     get_dash_string(&Desc);
122     if (!strcmp(Contents, "-"))
123         pkg_in = stdin;
124     else {
125         pkg_in = fopen(Contents, "r");
126         if (!pkg_in) {
127             cleanup(0);
128             errx(2, "%s: unable to open contents file '%s' for input",
129                 __func__, Contents);
130         }
131     }
132     plist.head = plist.tail = NULL;
133
134     /* Stick the dependencies, if any, at the top */
135     if (Pkgdeps) {
136         char **deps, *deporigin;
137         int i;
138         int ndeps = 0;
139
140         if (Verbose && !PlistOnly)
141             printf("Registering depends:");
142
143         /* Count number of dependencies */
144         for (cp = Pkgdeps; cp != NULL && *cp != '\0';
145                            cp = strpbrk(++cp, " \t\n")) {
146             ndeps++;
147         }
148
149         if (ndeps != 0) {
150             /* Create easy to use NULL-terminated list */
151             deps = alloca(sizeof(*deps) * ndeps + 1);
152             if (deps == NULL) {
153                 errx(2, "%s: alloca() failed", __func__);
154                 /* Not reached */
155             }
156             for (i = 0; Pkgdeps;) {
157                 cp = strsep(&Pkgdeps, " \t\n");
158                 if (*cp) {
159                     deps[i] = cp;
160                     i++;
161                 }
162             }
163             ndeps = i;
164             deps[ndeps] = NULL;
165
166             sortdeps(deps);
167             for (i = 0; i < ndeps; i++) {
168                 deporigin = strchr(deps[i], ':');
169                 if (deporigin != NULL) {
170                     *deporigin = '\0';
171                     add_plist_top(&plist, PLIST_DEPORIGIN, ++deporigin);
172                 }
173                 add_plist_top(&plist, PLIST_PKGDEP, deps[i]);
174                 if (Verbose && !PlistOnly)
175                     printf(" %s", deps[i]);
176             }
177         }
178
179         if (Verbose && !PlistOnly)
180             printf(".\n");
181     }
182
183     /* Put the conflicts directly after the dependencies, if any */
184     if (Conflicts) {
185         if (Verbose && !PlistOnly)
186             printf("Registering conflicts:");
187         while (Conflicts) {
188            cp = strsep(&Conflicts, " \t\n");
189            if (*cp) {
190                 add_plist(&plist, PLIST_CONFLICTS, cp);
191                 if (Verbose && !PlistOnly)
192                     printf(" %s", cp);
193            }
194         }
195         if (Verbose && !PlistOnly)
196             printf(".\n");
197     }
198
199     /* If a SrcDir override is set, add it now */
200     if (SrcDir) {
201         if (Verbose && !PlistOnly)
202             printf("Using SrcDir value of %s\n", SrcDir);
203         add_plist(&plist, PLIST_SRC, SrcDir);
204     }
205
206     /* Slurp in the packing list */
207     read_plist(&plist, pkg_in);
208
209     /* Prefix should add an @cwd to the packing list */
210     if (Prefix)
211         add_plist_top(&plist, PLIST_CWD, Prefix);
212
213     /* Add the origin if asked, at the top */
214     if (Origin)
215         add_plist_top(&plist, PLIST_ORIGIN, Origin);
216
217     /*
218      * Run down the list and see if we've named it, if not stick in a name
219      * at the top.
220      */
221     if (find_plist(&plist, PLIST_NAME) == NULL)
222         add_plist_top(&plist, PLIST_NAME, basename(pkg));
223
224     if (asprintf(&cp, "PKG_FORMAT_REVISION:%d.%d", PLIST_FMT_VER_MAJOR,
225                  PLIST_FMT_VER_MINOR) == -1) {
226         errx(2, "%s: asprintf() failed", __func__);
227     }
228     add_plist_top(&plist, PLIST_COMMENT, cp);
229     free(cp);
230
231     /*
232      * We're just here for to dump out a revised plist for the FreeBSD ports
233      * hack.  It's not a real create in progress.
234      */
235     if (PlistOnly) {
236         check_list(home, &plist);
237         write_plist(&plist, stdout);
238         exit(0);
239     }
240
241     /* Make a directory to stomp around in */
242     home = make_playpen(PlayPen, 0);
243     signal(SIGINT, cleanup);
244     signal(SIGHUP, cleanup);
245
246     /* Make first "real contents" pass over it */
247     check_list(home, &plist);
248     (void) umask(022);  /*
249                          * Make sure gen'ed directories, files don't have
250                          * group or other write bits.
251                          */
252     /* copy_plist(home, &plist); */
253     /* mark_plist(&plist); */
254
255     /* Now put the release specific items in */
256     add_plist(&plist, PLIST_CWD, ".");
257     write_file(COMMENT_FNAME, Comment);
258     add_plist(&plist, PLIST_IGNORE, NULL);
259     add_plist(&plist, PLIST_FILE, COMMENT_FNAME);
260     add_cksum(&plist, plist.tail, COMMENT_FNAME);
261     write_file(DESC_FNAME, Desc);
262     add_plist(&plist, PLIST_IGNORE, NULL);
263     add_plist(&plist, PLIST_FILE, DESC_FNAME);
264     add_cksum(&plist, plist.tail, DESC_FNAME);
265
266     if (Install) {
267         copy_file(home, Install, INSTALL_FNAME);
268         add_plist(&plist, PLIST_IGNORE, NULL);
269         add_plist(&plist, PLIST_FILE, INSTALL_FNAME);
270         add_cksum(&plist, plist.tail, INSTALL_FNAME);
271     }
272     if (PostInstall) {
273         copy_file(home, PostInstall, POST_INSTALL_FNAME);
274         add_plist(&plist, PLIST_IGNORE, NULL);
275         add_plist(&plist, PLIST_FILE, POST_INSTALL_FNAME);
276         add_cksum(&plist, plist.tail, POST_INSTALL_FNAME);
277     }
278     if (DeInstall) {
279         copy_file(home, DeInstall, DEINSTALL_FNAME);
280         add_plist(&plist, PLIST_IGNORE, NULL);
281         add_plist(&plist, PLIST_FILE, DEINSTALL_FNAME);
282         add_cksum(&plist, plist.tail, DEINSTALL_FNAME);
283     }
284     if (PostDeInstall) {
285         copy_file(home, PostDeInstall, POST_DEINSTALL_FNAME);
286         add_plist(&plist, PLIST_IGNORE, NULL);
287         add_plist(&plist, PLIST_FILE, POST_DEINSTALL_FNAME);
288         add_cksum(&plist, plist.tail, POST_DEINSTALL_FNAME);
289     }
290     if (Require) {
291         copy_file(home, Require, REQUIRE_FNAME);
292         add_plist(&plist, PLIST_IGNORE, NULL);
293         add_plist(&plist, PLIST_FILE, REQUIRE_FNAME);
294         add_cksum(&plist, plist.tail, REQUIRE_FNAME);
295     }
296     if (Display) {
297         copy_file(home, Display, DISPLAY_FNAME);
298         add_plist(&plist, PLIST_IGNORE, NULL);
299         add_plist(&plist, PLIST_FILE, DISPLAY_FNAME);
300         add_cksum(&plist, plist.tail, DISPLAY_FNAME);
301         add_plist(&plist, PLIST_DISPLAY, DISPLAY_FNAME);
302     }
303     if (Mtree) {
304         copy_file(home, Mtree, MTREE_FNAME);
305         add_plist(&plist, PLIST_IGNORE, NULL);
306         add_plist(&plist, PLIST_FILE, MTREE_FNAME);
307         add_cksum(&plist, plist.tail, MTREE_FNAME);
308         add_plist(&plist, PLIST_MTREE, MTREE_FNAME);
309     }
310
311     /* Finally, write out the packing list */
312     fp = fopen(CONTENTS_FNAME, "w");
313     if (!fp) {
314         cleanup(0);
315         errx(2, "%s: can't open file %s for writing",
316             __func__, CONTENTS_FNAME);
317     }
318     write_plist(&plist, fp);
319     if (fclose(fp)) {
320         cleanup(0);
321         errx(2, "%s: error while closing %s",
322             __func__, CONTENTS_FNAME);
323     }
324
325     /* And stick it into a tar ball */
326     make_dist(home, pkg, suf, &plist);
327
328     /* Cleanup */
329     free(Comment);
330     free(Desc);
331     free_plist(&plist);
332     leave_playpen();
333     return TRUE;        /* Success */
334 }
335
336 static void
337 make_dist(const char *homedir, const char *pkg, const char *suff, Package *plist)
338 {
339     char tball[FILENAME_MAX];
340     PackingList p;
341     int ret;
342     const char *args[50];       /* Much more than enough. */
343     int nargs = 0;
344     int pipefds[2];
345     FILE *totar;
346     pid_t pid;
347     const char *cname;
348     char *prefix = NULL;
349
350
351     args[nargs++] = "tar";      /* argv[0] */
352
353     if (*pkg == '/')
354         snprintf(tball, FILENAME_MAX, "%s.%s", pkg, suff);
355     else
356         snprintf(tball, FILENAME_MAX, "%s/%s.%s", homedir, pkg, suff);
357
358     args[nargs++] = "-c";
359     args[nargs++] = "-f";
360     args[nargs++] = tball;
361     if (strchr(suff, 'z')) {    /* Compress/gzip/bzip2? */
362         if (Zipper == BZIP2) {
363             args[nargs++] = "-j";
364             cname = "bzip'd ";
365         }
366         else {
367             args[nargs++] = "-z";
368             cname = "gzip'd ";
369         }
370     } else {
371         cname = "";
372     }
373     if (Dereference)
374         args[nargs++] = "-h";
375     if (ExcludeFrom) {
376         args[nargs++] = "-X";
377         args[nargs++] = ExcludeFrom;
378     }
379     args[nargs++] = "-T";       /* Take filenames from file instead of args. */
380     args[nargs++] = "-";        /* Use stdin for the file. */
381     args[nargs] = NULL;
382
383     if (Verbose)
384         printf("Creating %star ball in '%s'\n", cname, tball);
385
386     /* Set up a pipe for passing the filenames, and fork off a tar process. */
387     if (pipe(pipefds) == -1) {
388         cleanup(0);
389         errx(2, "%s: cannot create pipe", __func__);
390     }
391     if ((pid = fork()) == -1) {
392         cleanup(0);
393         errx(2, "%s: cannot fork process for tar", __func__);
394     }
395     if (pid == 0) {     /* The child */
396         dup2(pipefds[0], 0);
397         close(pipefds[0]);
398         close(pipefds[1]);
399         execv("/usr/bin/tar", (char * const *)(uintptr_t)args);
400         cleanup(0);
401         errx(2, "%s: failed to execute tar command", __func__);
402     }
403
404     /* Meanwhile, back in the parent process ... */
405     close(pipefds[0]);
406     if ((totar = fdopen(pipefds[1], "w")) == NULL) {
407         cleanup(0);
408         errx(2, "%s: fdopen failed", __func__);
409     }
410
411     fprintf(totar, "%s\n", CONTENTS_FNAME);
412     fprintf(totar, "%s\n", COMMENT_FNAME);
413     fprintf(totar, "%s\n", DESC_FNAME);
414
415     if (Install)
416         fprintf(totar, "%s\n", INSTALL_FNAME);
417     if (PostInstall)
418         fprintf(totar, "%s\n", POST_INSTALL_FNAME);
419     if (DeInstall)
420         fprintf(totar, "%s\n", DEINSTALL_FNAME);
421     if (PostDeInstall)
422         fprintf(totar, "%s\n", POST_DEINSTALL_FNAME);
423     if (Require)
424         fprintf(totar, "%s\n", REQUIRE_FNAME);
425     if (Display)
426         fprintf(totar, "%s\n", DISPLAY_FNAME);
427     if (Mtree)
428         fprintf(totar, "%s\n", MTREE_FNAME);
429
430     for (p = plist->head; p; p = p->next) {
431         if (p->type == PLIST_FILE)
432             fprintf(totar, "%s\n", p->name);
433         else if (p->type == PLIST_CWD && p->name == NULL)
434             fprintf(totar, "-C\n%s\n", prefix);
435         else if (p->type == PLIST_CWD && BaseDir && p->name && p->name[0] == '/')
436             fprintf(totar, "-C\n%s%s\n", BaseDir, p->name);
437         else if (p->type == PLIST_CWD || p->type == PLIST_SRC)
438             fprintf(totar, "-C\n%s\n", p->name);
439         else if (p->type == PLIST_IGNORE)
440              p = p->next;
441         if (p->type == PLIST_CWD && !prefix)
442             prefix = p->name;
443
444     }
445
446     fclose(totar);
447     wait(&ret);
448     /* assume either signal or bad exit is enough for us */
449     if (ret) {
450         cleanup(0);
451         errx(2, "%s: tar command failed with code %d", __func__, ret);
452     }
453 }
454
455 static void
456 sanity_check()
457 {
458     if (!Comment) {
459         cleanup(0);
460         errx(2, "%s: required package comment string is missing (-c comment)",
461             __func__);
462     }
463     if (!Desc) {
464         cleanup(0);
465         errx(2, "%s: required package description string is missing (-d desc)",
466             __func__);
467     }
468     if (!Contents) {
469         cleanup(0);
470         errx(2, "%s: required package contents list is missing (-f [-]file)",
471             __func__);
472     }
473 }
474
475
476 /* Clean up those things that would otherwise hang around */
477 void
478 cleanup(int sig)
479 {
480     int in_cleanup = 0;
481
482     if (!in_cleanup) {
483         in_cleanup = 1;
484         leave_playpen();
485     }
486     if (sig)
487         exit(1);
488 }
489
490 static int
491 create_from_installed_recursive(const char *pkg, const char *suf)
492 {
493     FILE *fp;
494     Package plist;
495     PackingList p;
496     char tmp[PATH_MAX];
497     int rval;
498
499     if (!create_from_installed(InstalledPkg, pkg, suf))
500         return FALSE;
501     snprintf(tmp, sizeof(tmp), "%s/%s/%s", LOG_DIR, InstalledPkg, CONTENTS_FNAME);
502     if (!fexists(tmp)) {
503         warnx("can't find package '%s' installed!", InstalledPkg);
504         return FALSE;
505     }
506     /* Suck in the contents list */
507     plist.head = plist.tail = NULL;
508     fp = fopen(tmp, "r");
509     if (!fp) {
510         warnx("unable to open %s file", tmp);
511         return FALSE;
512     }
513     read_plist(&plist, fp);
514     fclose(fp);
515     rval = TRUE;
516     for (p = plist.head; p ; p = p->next) {
517         if (p->type != PLIST_PKGDEP)
518             continue;
519         if (Verbose)
520             printf("Creating package %s\n", p->name);
521         if (!create_from_installed(p->name, p->name, suf)) {
522             rval = FALSE;
523             break;
524         }
525     }
526     free_plist(&plist);
527     return rval;
528 }
529
530 static int
531 create_from_installed(const char *ipkg, const char *pkg, const char *suf)
532 {
533     FILE *fp;
534     Package plist;
535     char homedir[MAXPATHLEN], log_dir[FILENAME_MAX];
536
537     snprintf(log_dir, sizeof(log_dir), "%s/%s", LOG_DIR, ipkg);
538     if (!fexists(log_dir)) {
539         warnx("can't find package '%s' installed!", ipkg);
540         return FALSE;
541     }
542     getcwd(homedir, sizeof(homedir));
543     if (chdir(log_dir) == FAIL) {
544         warnx("can't change directory to '%s'!", log_dir);
545         return FALSE;
546     }
547     /* Suck in the contents list */
548     plist.head = plist.tail = NULL;
549     fp = fopen(CONTENTS_FNAME, "r");
550     if (!fp) {
551         warnx("unable to open %s file", CONTENTS_FNAME);
552         return FALSE;
553     }
554     read_plist(&plist, fp);
555     fclose(fp);
556
557     Install = isfile(INSTALL_FNAME) ? (char *)INSTALL_FNAME : NULL;
558     PostInstall = isfile(POST_INSTALL_FNAME) ?
559         (char *)POST_INSTALL_FNAME : NULL;
560     DeInstall = isfile(DEINSTALL_FNAME) ? (char *)DEINSTALL_FNAME : NULL;
561     PostDeInstall = isfile(POST_DEINSTALL_FNAME) ?
562         (char *)POST_DEINSTALL_FNAME : NULL;
563     Require = isfile(REQUIRE_FNAME) ? (char *)REQUIRE_FNAME : NULL;
564     Display = isfile(DISPLAY_FNAME) ? (char *)DISPLAY_FNAME : NULL;
565     Mtree = isfile(MTREE_FNAME) ?  (char *)MTREE_FNAME : NULL;
566
567     make_dist(homedir, pkg, suf, &plist);
568
569     free_plist(&plist);
570     if (chdir(homedir) == FAIL) {
571         warnx("can't change directory to '%s'!", homedir);
572         return FALSE;
573     }
574     return TRUE;
575 }