perform.c revision 67454
1#ifndef lint
2static const char rcsid[] =
3  "$FreeBSD: head/usr.sbin/pkg_install/create/perform.c 67454 2000-10-23 07:01:31Z sobomax $";
4#endif
5
6/*
7 * FreeBSD install - a package for the installation and maintainance
8 * of non-core utilities.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * Jordan K. Hubbard
20 * 18 July 1993
21 *
22 * This is the main body of the create module.
23 *
24 */
25
26#include "lib.h"
27#include "create.h"
28
29#include <err.h>
30#include <signal.h>
31#include <sys/syslimits.h>
32#include <sys/wait.h>
33#include <unistd.h>
34
35static void sanity_check(void);
36static void make_dist(char *, char *, char *, Package *);
37
38static char *home;
39
40int
41pkg_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    char *suf;
49    int compress = 0;
50
51    /* Preliminary setup */
52    sanity_check();
53    if (Verbose && !PlistOnly)
54	printf("Creating package %s\n", pkg);
55    get_dash_string(&Comment);
56    get_dash_string(&Desc);
57    if (!strcmp(Contents, "-"))
58	pkg_in = stdin;
59    else {
60	pkg_in = fopen(Contents, "r");
61	if (!pkg_in) {
62	    cleanup(0);
63	    errx(2, __FUNCTION__ ": unable to open contents file '%s' for input", Contents);
64	}
65    }
66    plist.head = plist.tail = NULL;
67
68    /* chop suffix off if already specified, remembering if we want to compress  */
69    len = strlen(pkg);
70    if (len > 4) {
71	if (!strcmp(&pkg[len - 4], ".tgz")) {
72	    compress = TRUE;
73	    pkg[len - 4] = '\0';
74	}
75	else if (!strcmp(&pkg[len - 4], ".tar")) {
76	    compress = FALSE;
77	    pkg[len - 4] = '\0';
78	}
79	else
80	    /* default is to compress packages */
81	    compress = TRUE;
82    }
83    if (compress)
84	suf = "tgz";
85    else
86	suf = "tar";
87
88    /* Add the origin if asked, at the top */
89    if (Origin)
90	add_plist(&plist, PLIST_COMMENT, strconcat("ORIGIN:", Origin));
91
92    /* Stick the dependencies, if any, at the top */
93    if (Pkgdeps) {
94	if (Verbose && !PlistOnly)
95	    printf("Registering depends:");
96	while (Pkgdeps) {
97	    cp = strsep(&Pkgdeps, " \t\n");
98	    if (*cp) {
99		add_plist_top(&plist, PLIST_PKGDEP, cp);
100		if (Verbose && !PlistOnly)
101		    printf(" %s", cp);
102	    }
103	}
104	if (Verbose && !PlistOnly)
105	    printf(".\n");
106    }
107
108    /* If a SrcDir override is set, add it now */
109    if (SrcDir) {
110	if (Verbose && !PlistOnly)
111	    printf("Using SrcDir value of %s\n", SrcDir);
112	add_plist(&plist, PLIST_SRC, SrcDir);
113    }
114
115    /* Slurp in the packing list */
116    read_plist(&plist, pkg_in);
117
118    /* Prefix should add an @cwd to the packing list */
119    if (Prefix)
120	add_plist_top(&plist, PLIST_CWD, Prefix);
121    /*
122     * Run down the list and see if we've named it, if not stick in a name
123     * at the top.
124     */
125    if (find_plist(&plist, PLIST_NAME) == NULL)
126	add_plist_top(&plist, PLIST_NAME, basename_of(pkg));
127
128    /*
129     * We're just here for to dump out a revised plist for the FreeBSD ports
130     * hack.  It's not a real create in progress.
131     */
132    if (PlistOnly) {
133	check_list(home, &plist);
134	write_plist(&plist, stdout);
135	exit(0);
136    }
137
138    /* Make a directory to stomp around in */
139    home = make_playpen(PlayPen, 0);
140    signal(SIGINT, cleanup);
141    signal(SIGHUP, cleanup);
142
143    /* Make first "real contents" pass over it */
144    check_list(home, &plist);
145    (void) umask(022);	/* make sure gen'ed directories, files don't have
146			   group or other write bits. */
147    /* copy_plist(home, &plist); */
148    /* mark_plist(&plist); */
149
150    /* Now put the release specific items in */
151    add_plist(&plist, PLIST_CWD, ".");
152    write_file(COMMENT_FNAME, Comment);
153    add_plist(&plist, PLIST_IGNORE, NULL);
154    add_plist(&plist, PLIST_FILE, COMMENT_FNAME);
155    write_file(DESC_FNAME, Desc);
156    add_plist(&plist, PLIST_IGNORE, NULL);
157    add_plist(&plist, PLIST_FILE, DESC_FNAME);
158
159    if (Install) {
160	copy_file(home, Install, INSTALL_FNAME);
161	add_plist(&plist, PLIST_IGNORE, NULL);
162	add_plist(&plist, PLIST_FILE, INSTALL_FNAME);
163    }
164    if (PostInstall) {
165	copy_file(home, PostInstall, POST_INSTALL_FNAME);
166	add_plist(&plist, PLIST_IGNORE, NULL);
167	add_plist(&plist, PLIST_FILE, POST_INSTALL_FNAME);
168    }
169    if (DeInstall) {
170	copy_file(home, DeInstall, DEINSTALL_FNAME);
171	add_plist(&plist, PLIST_IGNORE, NULL);
172	add_plist(&plist, PLIST_FILE, DEINSTALL_FNAME);
173    }
174    if (PostDeInstall) {
175	copy_file(home, PostDeInstall, POST_DEINSTALL_FNAME);
176	add_plist(&plist, PLIST_IGNORE, NULL);
177	add_plist(&plist, PLIST_FILE, POST_DEINSTALL_FNAME);
178    }
179    if (Require) {
180	copy_file(home, Require, REQUIRE_FNAME);
181	add_plist(&plist, PLIST_IGNORE, NULL);
182	add_plist(&plist, PLIST_FILE, REQUIRE_FNAME);
183    }
184    if (Display) {
185	copy_file(home, Display, DISPLAY_FNAME);
186	add_plist(&plist, PLIST_IGNORE, NULL);
187	add_plist(&plist, PLIST_FILE, DISPLAY_FNAME);
188	add_plist(&plist, PLIST_DISPLAY, DISPLAY_FNAME);
189    }
190    if (Mtree) {
191	copy_file(home, Mtree, MTREE_FNAME);
192	add_plist(&plist, PLIST_IGNORE, NULL);
193	add_plist(&plist, PLIST_FILE, MTREE_FNAME);
194	add_plist(&plist, PLIST_MTREE, MTREE_FNAME);
195    }
196
197    /* Finally, write out the packing list */
198    fp = fopen(CONTENTS_FNAME, "w");
199    if (!fp) {
200	cleanup(0);
201	errx(2, __FUNCTION__ ": can't open file %s for writing", CONTENTS_FNAME);
202    }
203    write_plist(&plist, fp);
204    if (fclose(fp)) {
205	cleanup(0);
206	errx(2, __FUNCTION__ ": error while closing %s", CONTENTS_FNAME);
207    }
208
209    /* And stick it into a tar ball */
210    make_dist(home, pkg, suf, &plist);
211
212    /* Cleanup */
213    free(Comment);
214    free(Desc);
215    free_plist(&plist);
216    leave_playpen();
217    return TRUE;	/* Success */
218}
219
220static void
221make_dist(char *home, char *pkg, char *suffix, Package *plist)
222{
223    char tball[FILENAME_MAX];
224    PackingList p;
225    int ret;
226    char *args[50];	/* Much more than enough. */
227    int nargs = 0;
228    int pipefds[2];
229    FILE *totar;
230    pid_t pid;
231
232    args[nargs++] = "tar";	/* argv[0] */
233
234    if (*pkg == '/')
235	snprintf(tball, FILENAME_MAX, "%s.%s", pkg, suffix);
236    else
237	snprintf(tball, FILENAME_MAX, "%s/%s.%s", home, pkg, suffix);
238
239    args[nargs++] = "-c";
240    args[nargs++] = "-f";
241    args[nargs++] = tball;
242    if (strchr(suffix, 'z'))	/* Compress/gzip? */
243	args[nargs++] = "-z";
244    if (Dereference)
245	args[nargs++] = "-h";
246    if (ExcludeFrom) {
247	args[nargs++] = "-X";
248	args[nargs++] = ExcludeFrom;
249    }
250    args[nargs++] = "-T";	/* Take filenames from file instead of args. */
251    args[nargs++] = "-";	/* Use stdin for the file. */
252    args[nargs] = NULL;
253
254    if (Verbose)
255	printf("Creating gzip'd tar ball in '%s'\n", tball);
256
257    /* Set up a pipe for passing the filenames, and fork off a tar process. */
258    if (pipe(pipefds) == -1) {
259	cleanup(0);
260	errx(2, __FUNCTION__ ": cannot create pipe");
261    }
262    if ((pid = fork()) == -1) {
263	cleanup(0);
264	errx(2, __FUNCTION__ ": cannot fork process for tar");
265    }
266    if (pid == 0) {	/* The child */
267	dup2(pipefds[0], 0);
268	close(pipefds[0]);
269	close(pipefds[1]);
270	execv("/usr/bin/tar", args);
271	cleanup(0);
272	errx(2, __FUNCTION__ ": failed to execute tar command");
273    }
274
275    /* Meanwhile, back in the parent process ... */
276    close(pipefds[0]);
277    if ((totar = fdopen(pipefds[1], "w")) == NULL) {
278	cleanup(0);
279	errx(2, __FUNCTION__ ": fdopen failed");
280    }
281
282    fprintf(totar, "%s\n", CONTENTS_FNAME);
283    fprintf(totar, "%s\n", COMMENT_FNAME);
284    fprintf(totar, "%s\n", DESC_FNAME);
285
286    if (Install)
287	fprintf(totar, "%s\n", INSTALL_FNAME);
288    if (PostInstall)
289	fprintf(totar, "%s\n", POST_INSTALL_FNAME);
290    if (DeInstall)
291	fprintf(totar, "%s\n", DEINSTALL_FNAME);
292    if (PostDeInstall)
293	fprintf(totar, "%s\n", POST_DEINSTALL_FNAME);
294    if (Require)
295	fprintf(totar, "%s\n", REQUIRE_FNAME);
296    if (Display)
297	fprintf(totar, "%s\n", DISPLAY_FNAME);
298    if (Mtree)
299	fprintf(totar, "%s\n", MTREE_FNAME);
300
301    for (p = plist->head; p; p = p->next) {
302	if (p->type == PLIST_FILE)
303	    fprintf(totar, "%s\n", p->name);
304	else if (p->type == PLIST_CWD || p->type == PLIST_SRC)
305	    fprintf(totar, "-C\n%s\n", p->name);
306	else if (p->type == PLIST_IGNORE)
307	     p = p->next;
308    }
309
310    fclose(totar);
311    wait(&ret);
312    /* assume either signal or bad exit is enough for us */
313    if (ret) {
314	cleanup(0);
315	errx(2, __FUNCTION__ ": tar command failed with code %d", ret);
316    }
317}
318
319static void
320sanity_check()
321{
322    if (!Comment) {
323	cleanup(0);
324	errx(2, __FUNCTION__ ": required package comment string is missing (-c comment)");
325    }
326    if (!Desc) {
327	cleanup(0);
328	errx(2,	__FUNCTION__ ": required package description string is missing (-d desc)");
329    }
330    if (!Contents) {
331	cleanup(0);
332	errx(2,	__FUNCTION__ ": required package contents list is missing (-f [-]file)");
333    }
334}
335
336
337/* Clean up those things that would otherwise hang around */
338void
339cleanup(int sig)
340{
341    int in_cleanup = 0;
342
343    if (!in_cleanup) {
344	in_cleanup = 1;
345    	leave_playpen();
346    }
347    if (sig)
348	exit(1);
349}
350