Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[dragonfly.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  * $FreeBSD: src/usr.sbin/pkg_install/create/perform.c,v 1.49.2.18 2002/08/31 19:25:54 obrien Exp $
20  * $DragonFly: src/usr.sbin/pkg_install/create/Attic/perform.c,v 1.2 2003/06/17 04:29:59 dillon Exp $
21  */
22
23 #include "lib.h"
24 #include "create.h"
25
26 #include <err.h>
27 #include <libgen.h>
28 #include <signal.h>
29 #include <stdlib.h>
30 #include <sys/syslimits.h>
31 #include <sys/wait.h>
32 #include <unistd.h>
33
34 static void sanity_check(void);
35 static void make_dist(const char *, const char *, const char *, Package *);
36 static int create_from_installed(const char *, const char *);
37
38 static char *home;
39
40 int
41 pkg_perform(char **pkgs)
42 {
43     char *pkg = *pkgs;          /* Only one arg to create */
44     char *cp;
45     FILE *pkg_in, *fp;
46     Package plist;
47     int len;
48     const char *suf;
49
50     /* Preliminary setup */
51     if (InstalledPkg == NULL)
52         sanity_check();
53     if (Verbose && !PlistOnly)
54         printf("Creating package %s\n", pkg);
55
56     /* chop suffix off if already specified, remembering if we want to compress  */
57     len = strlen(pkg);
58     if (len > 4) {
59         if (!strcmp(&pkg[len - 4], ".tbz")) {
60             Zipper = BZIP2;
61             pkg[len - 4] = '\0';
62         }
63         else if (!strcmp(&pkg[len - 4], ".tgz")) {
64             Zipper = GZIP;
65             pkg[len - 4] = '\0';
66         }
67         else if (!strcmp(&pkg[len - 4], ".tar")) {
68             Zipper = NONE;
69             pkg[len - 4] = '\0';
70         }
71     }
72     if (Zipper == BZIP2) {
73         suf = "tbz";
74         setenv("BZIP2", "--best", 0);
75     } else if (Zipper == GZIP) {
76         suf = "tgz";
77         setenv("GZIP", "-9", 0);
78     } else
79         suf = "tar";
80
81     if (InstalledPkg != NULL)
82         return (create_from_installed(pkg, suf));
83
84     get_dash_string(&Comment);
85     get_dash_string(&Desc);
86     if (!strcmp(Contents, "-"))
87         pkg_in = stdin;
88     else {
89         pkg_in = fopen(Contents, "r");
90         if (!pkg_in) {
91             cleanup(0);
92             errx(2, "%s: unable to open contents file '%s' for input",
93                 __func__, Contents);
94         }
95     }
96     plist.head = plist.tail = NULL;
97
98     /* Stick the dependencies, if any, at the top */
99     if (Pkgdeps) {
100         char **deps, *deporigin;
101         int i;
102         int ndeps = 0;
103
104         if (Verbose && !PlistOnly)
105             printf("Registering depends:");
106
107         /* Count number of dependencies */
108         for (cp = Pkgdeps; cp != NULL && *cp != '\0';
109                            cp = strpbrk(++cp, " \t\n")) {
110             ndeps++;
111         }
112
113         if (ndeps != 0) {
114             /* Create easy to use NULL-terminated list */
115             deps = alloca(sizeof(*deps) * ndeps + 1);
116             if (deps == NULL) {
117                 errx(2, "%s: alloca() failed", __func__);
118                 /* Not reached */
119             }
120             for (i = 0; Pkgdeps;) {
121                 cp = strsep(&Pkgdeps, " \t\n");
122                 if (*cp) {
123                     deps[i] = cp;
124                     i++;
125                 }
126             }
127             ndeps = i;
128             deps[ndeps] = NULL;
129
130             sortdeps(deps);
131             for (i = 0; i < ndeps; i++) {
132                 deporigin = strchr(deps[i], ':');
133                 if (deporigin != NULL) {
134                     *deporigin = '\0';
135                     add_plist_top(&plist, PLIST_DEPORIGIN, ++deporigin);
136                 }
137                 add_plist_top(&plist, PLIST_PKGDEP, deps[i]);
138                 if (Verbose && !PlistOnly)
139                     printf(" %s", deps[i]);
140             }
141         }
142
143         if (Verbose && !PlistOnly)
144             printf(".\n");
145     }
146
147     /* If a SrcDir override is set, add it now */
148     if (SrcDir) {
149         if (Verbose && !PlistOnly)
150             printf("Using SrcDir value of %s\n", SrcDir);
151         add_plist(&plist, PLIST_SRC, SrcDir);
152     }
153
154     /* Slurp in the packing list */
155     read_plist(&plist, pkg_in);
156
157     /* Prefix should add an @cwd to the packing list */
158     if (Prefix)
159         add_plist_top(&plist, PLIST_CWD, Prefix);
160
161     /* Add the origin if asked, at the top */
162     if (Origin)
163         add_plist_top(&plist, PLIST_ORIGIN, Origin);
164
165     /*
166      * Run down the list and see if we've named it, if not stick in a name
167      * at the top.
168      */
169     if (find_plist(&plist, PLIST_NAME) == NULL)
170         add_plist_top(&plist, PLIST_NAME, basename(pkg));
171
172     if (asprintf(&cp, "PKG_FORMAT_REVISION:%d.%d", PLIST_FMT_VER_MAJOR,
173                  PLIST_FMT_VER_MINOR) == -1) {
174         errx(2, "%s: asprintf() failed", __func__);
175     }
176     add_plist_top(&plist, PLIST_COMMENT, cp);
177     free(cp);
178
179     /*
180      * We're just here for to dump out a revised plist for the FreeBSD ports
181      * hack.  It's not a real create in progress.
182      */
183     if (PlistOnly) {
184         check_list(home, &plist);
185         write_plist(&plist, stdout);
186         exit(0);
187     }
188
189     /* Make a directory to stomp around in */
190     home = make_playpen(PlayPen, 0);
191     signal(SIGINT, cleanup);
192     signal(SIGHUP, cleanup);
193
194     /* Make first "real contents" pass over it */
195     check_list(home, &plist);
196     (void) umask(022);  /*
197                          * Make sure gen'ed directories, files don't have
198                          * group or other write bits.
199                          */
200     /* copy_plist(home, &plist); */
201     /* mark_plist(&plist); */
202
203     /* Now put the release specific items in */
204     add_plist(&plist, PLIST_CWD, ".");
205     write_file(COMMENT_FNAME, Comment);
206     add_plist(&plist, PLIST_IGNORE, NULL);
207     add_plist(&plist, PLIST_FILE, COMMENT_FNAME);
208     write_file(DESC_FNAME, Desc);
209     add_plist(&plist, PLIST_IGNORE, NULL);
210     add_plist(&plist, PLIST_FILE, DESC_FNAME);
211
212     if (Install) {
213         copy_file(home, Install, INSTALL_FNAME);
214         add_plist(&plist, PLIST_IGNORE, NULL);
215         add_plist(&plist, PLIST_FILE, INSTALL_FNAME);
216     }
217     if (PostInstall) {
218         copy_file(home, PostInstall, POST_INSTALL_FNAME);
219         add_plist(&plist, PLIST_IGNORE, NULL);
220         add_plist(&plist, PLIST_FILE, POST_INSTALL_FNAME);
221     }
222     if (DeInstall) {
223         copy_file(home, DeInstall, DEINSTALL_FNAME);
224         add_plist(&plist, PLIST_IGNORE, NULL);
225         add_plist(&plist, PLIST_FILE, DEINSTALL_FNAME);
226     }
227     if (PostDeInstall) {
228         copy_file(home, PostDeInstall, POST_DEINSTALL_FNAME);
229         add_plist(&plist, PLIST_IGNORE, NULL);
230         add_plist(&plist, PLIST_FILE, POST_DEINSTALL_FNAME);
231     }
232     if (Require) {
233         copy_file(home, Require, REQUIRE_FNAME);
234         add_plist(&plist, PLIST_IGNORE, NULL);
235         add_plist(&plist, PLIST_FILE, REQUIRE_FNAME);
236     }
237     if (Display) {
238         copy_file(home, Display, DISPLAY_FNAME);
239         add_plist(&plist, PLIST_IGNORE, NULL);
240         add_plist(&plist, PLIST_FILE, DISPLAY_FNAME);
241         add_plist(&plist, PLIST_DISPLAY, DISPLAY_FNAME);
242     }
243     if (Mtree) {
244         copy_file(home, Mtree, MTREE_FNAME);
245         add_plist(&plist, PLIST_IGNORE, NULL);
246         add_plist(&plist, PLIST_FILE, MTREE_FNAME);
247         add_plist(&plist, PLIST_MTREE, MTREE_FNAME);
248     }
249
250     /* Finally, write out the packing list */
251     fp = fopen(CONTENTS_FNAME, "w");
252     if (!fp) {
253         cleanup(0);
254         errx(2, "%s: can't open file %s for writing",
255             __func__, CONTENTS_FNAME);
256     }
257     write_plist(&plist, fp);
258     if (fclose(fp)) {
259         cleanup(0);
260         errx(2, "%s: error while closing %s",
261             __func__, CONTENTS_FNAME);
262     }
263
264     /* And stick it into a tar ball */
265     make_dist(home, pkg, suf, &plist);
266
267     /* Cleanup */
268     free(Comment);
269     free(Desc);
270     free_plist(&plist);
271     leave_playpen();
272     return TRUE;        /* Success */
273 }
274
275 static void
276 make_dist(const char *homedir, const char *pkg, const char *suff, Package *plist)
277 {
278     char tball[FILENAME_MAX];
279     PackingList p;
280     int ret;
281     const char *args[50];       /* Much more than enough. */
282     int nargs = 0;
283     int pipefds[2];
284     FILE *totar;
285     pid_t pid;
286     const char *cname;
287
288     args[nargs++] = "tar";      /* argv[0] */
289
290     if (*pkg == '/')
291         snprintf(tball, FILENAME_MAX, "%s.%s", pkg, suff);
292     else
293         snprintf(tball, FILENAME_MAX, "%s/%s.%s", homedir, pkg, suff);
294
295     args[nargs++] = "-c";
296     args[nargs++] = "-f";
297     args[nargs++] = tball;
298     if (strchr(suff, 'z')) {    /* Compress/gzip/bzip2? */
299         if (Zipper == BZIP2) {
300             args[nargs++] = "-j";
301             cname = "bzip'd ";
302         }
303         else {
304             args[nargs++] = "-z";
305             cname = "gzip'd ";
306         }
307     } else {
308         cname = "";
309     }
310     if (Dereference)
311         args[nargs++] = "-h";
312     if (ExcludeFrom) {
313         args[nargs++] = "-X";
314         args[nargs++] = ExcludeFrom;
315     }
316     args[nargs++] = "-T";       /* Take filenames from file instead of args. */
317     args[nargs++] = "-";        /* Use stdin for the file. */
318     args[nargs] = NULL;
319
320     if (Verbose)
321         printf("Creating %star ball in '%s'\n", cname, tball);
322
323     /* Set up a pipe for passing the filenames, and fork off a tar process. */
324     if (pipe(pipefds) == -1) {
325         cleanup(0);
326         errx(2, "%s: cannot create pipe", __func__);
327     }
328     if ((pid = fork()) == -1) {
329         cleanup(0);
330         errx(2, "%s: cannot fork process for tar", __func__);
331     }
332     if (pid == 0) {     /* The child */
333         dup2(pipefds[0], 0);
334         close(pipefds[0]);
335         close(pipefds[1]);
336         execv("/usr/bin/tar", (char * const *)(uintptr_t)args);
337         cleanup(0);
338         errx(2, "%s: failed to execute tar command", __func__);
339     }
340
341     /* Meanwhile, back in the parent process ... */
342     close(pipefds[0]);
343     if ((totar = fdopen(pipefds[1], "w")) == NULL) {
344         cleanup(0);
345         errx(2, "%s: fdopen failed", __func__);
346     }
347
348     fprintf(totar, "%s\n", CONTENTS_FNAME);
349     fprintf(totar, "%s\n", COMMENT_FNAME);
350     fprintf(totar, "%s\n", DESC_FNAME);
351
352     if (Install)
353         fprintf(totar, "%s\n", INSTALL_FNAME);
354     if (PostInstall)
355         fprintf(totar, "%s\n", POST_INSTALL_FNAME);
356     if (DeInstall)
357         fprintf(totar, "%s\n", DEINSTALL_FNAME);
358     if (PostDeInstall)
359         fprintf(totar, "%s\n", POST_DEINSTALL_FNAME);
360     if (Require)
361         fprintf(totar, "%s\n", REQUIRE_FNAME);
362     if (Display)
363         fprintf(totar, "%s\n", DISPLAY_FNAME);
364     if (Mtree)
365         fprintf(totar, "%s\n", MTREE_FNAME);
366
367     for (p = plist->head; p; p = p->next) {
368         if (p->type == PLIST_FILE)
369             fprintf(totar, "%s\n", p->name);
370         else if (p->type == PLIST_CWD || p->type == PLIST_SRC)
371             fprintf(totar, "-C\n%s\n", p->name);
372         else if (p->type == PLIST_IGNORE)
373              p = p->next;
374     }
375
376     fclose(totar);
377     wait(&ret);
378     /* assume either signal or bad exit is enough for us */
379     if (ret) {
380         cleanup(0);
381         errx(2, "%s: tar command failed with code %d", __func__, ret);
382     }
383 }
384
385 static void
386 sanity_check()
387 {
388     if (!Comment) {
389         cleanup(0);
390         errx(2, "%s: required package comment string is missing (-c comment)",
391             __func__);
392     }
393     if (!Desc) {
394         cleanup(0);
395         errx(2, "%s: required package description string is missing (-d desc)",
396             __func__);
397     }
398     if (!Contents) {
399         cleanup(0);
400         errx(2, "%s: required package contents list is missing (-f [-]file)",
401             __func__);
402     }
403 }
404
405
406 /* Clean up those things that would otherwise hang around */
407 void
408 cleanup(int sig)
409 {
410     int in_cleanup = 0;
411
412     if (!in_cleanup) {
413         in_cleanup = 1;
414         leave_playpen();
415     }
416     if (sig)
417         exit(1);
418 }
419
420 static int
421 create_from_installed(const char *pkg, const char *suf)
422 {
423     FILE *fp;
424     Package plist;
425     char homedir[MAXPATHLEN], log_dir[FILENAME_MAX];
426
427     snprintf(log_dir, sizeof(log_dir), "%s/%s", LOG_DIR, InstalledPkg);
428     if (!fexists(log_dir)) {
429         warnx("can't find package '%s' installed!", InstalledPkg);
430         return FALSE;
431     }
432     getcwd(homedir, sizeof(homedir));
433     if (chdir(log_dir) == FAIL) {
434         warnx("can't change directory to '%s'!", log_dir);
435         return FALSE;
436     }
437     /* Suck in the contents list */
438     plist.head = plist.tail = NULL;
439     fp = fopen(CONTENTS_FNAME, "r");
440     if (!fp) {
441         warnx("unable to open %s file", CONTENTS_FNAME);
442         return FALSE;
443     }
444     read_plist(&plist, fp);
445     fclose(fp);
446
447     (const char *)Install = isfile(INSTALL_FNAME) ? INSTALL_FNAME : NULL;
448     (const char *)PostInstall = isfile(POST_INSTALL_FNAME) ? POST_INSTALL_FNAME : NULL;
449     (const char *)DeInstall = isfile(DEINSTALL_FNAME) ? DEINSTALL_FNAME : NULL;
450     (const char *)PostDeInstall = isfile(POST_DEINSTALL_FNAME) ? POST_DEINSTALL_FNAME : NULL;
451     (const char *)Require = isfile(REQUIRE_FNAME) ? REQUIRE_FNAME : NULL;
452     (const char *)Display = isfile(DISPLAY_FNAME) ? DISPLAY_FNAME : NULL;
453     (const char *)Mtree = isfile(MTREE_FNAME) ?  MTREE_FNAME : NULL;
454
455     make_dist(homedir, pkg, suf, &plist);
456
457     free_plist(&plist);
458     return TRUE;
459 }