perform.c revision 37914
1#ifndef lint
2static const char rcsid[] =
3	"$Id: perform.c,v 1.41 1998/02/16 17:16:28 jkh Exp $";
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    char *suffix;  /* What we tack on to the end of the finished package */
48
49    /* Preliminary setup */
50    sanity_check();
51    if (Verbose && !PlistOnly)
52	printf("Creating package %s\n", pkg);
53    get_dash_string(&Comment);
54    get_dash_string(&Desc);
55    if (!strcmp(Contents, "-"))
56	pkg_in = stdin;
57    else {
58	pkg_in = fopen(Contents, "r");
59	if (!pkg_in)
60	    cleanup(0), errx(2, "unable to open contents file '%s' for input",
61				Contents);
62    }
63    plist.head = plist.tail = NULL;
64
65    /* Break the package name into base and desired suffix (if any) */
66    if ((cp = rindex(pkg, '.')) != NULL) {
67	suffix = cp + 1;
68	*cp = '\0';
69    }
70    else
71	suffix = "tgz";
72
73    /* Stick the dependencies, if any, at the top */
74    if (Pkgdeps) {
75	if (Verbose && !PlistOnly)
76	    printf("Registering depends:");
77	while (Pkgdeps) {
78	    cp = strsep(&Pkgdeps, " \t\n");
79	    if (*cp) {
80		add_plist(&plist, PLIST_PKGDEP, cp);
81		if (Verbose && !PlistOnly)
82		    printf(" %s", cp);
83	    }
84	}
85	if (Verbose && !PlistOnly)
86	    printf(".\n");
87    }
88
89    /* If a SrcDir override is set, add it now */
90    if (SrcDir) {
91	if (Verbose && !PlistOnly)
92	    printf("Using SrcDir value of %s\n", SrcDir);
93	add_plist(&plist, PLIST_SRC, SrcDir);
94    }
95
96    /* Slurp in the packing list */
97    read_plist(&plist, pkg_in);
98
99    /* Prefix should add an @cwd to the packing list */
100    if (Prefix)
101	add_plist_top(&plist, PLIST_CWD, Prefix);
102    /*
103     * Run down the list and see if we've named it, if not stick in a name
104     * at the top.
105     */
106    if (find_plist(&plist, PLIST_NAME) == NULL)
107	add_plist_top(&plist, PLIST_NAME, basename_of(pkg));
108
109    /*
110     * We're just here for to dump out a revised plist for the FreeBSD ports
111     * hack.  It's not a real create in progress.
112     */
113    if (PlistOnly) {
114	check_list(home, &plist);
115	write_plist(&plist, stdout);
116	exit(0);
117    }
118
119    /* Make a directory to stomp around in */
120    home = make_playpen(PlayPen, 0);
121    signal(SIGINT, cleanup);
122    signal(SIGHUP, cleanup);
123
124    /* Make first "real contents" pass over it */
125    check_list(home, &plist);
126    (void) umask(022);	/* make sure gen'ed directories, files don't have
127			   group or other write bits. */
128    /* copy_plist(home, &plist); */
129    /* mark_plist(&plist); */
130
131    /* Now put the release specific items in */
132    add_plist(&plist, PLIST_CWD, ".");
133    write_file(COMMENT_FNAME, Comment);
134    add_plist(&plist, PLIST_IGNORE, NULL);
135    add_plist(&plist, PLIST_FILE, COMMENT_FNAME);
136    write_file(DESC_FNAME, Desc);
137    add_plist(&plist, PLIST_IGNORE, NULL);
138    add_plist(&plist, PLIST_FILE, DESC_FNAME);
139
140    if (Install) {
141	copy_file(home, Install, INSTALL_FNAME);
142	add_plist(&plist, PLIST_IGNORE, NULL);
143	add_plist(&plist, PLIST_FILE, INSTALL_FNAME);
144    }
145    if (DeInstall) {
146	copy_file(home, DeInstall, DEINSTALL_FNAME);
147	add_plist(&plist, PLIST_IGNORE, NULL);
148	add_plist(&plist, PLIST_FILE, DEINSTALL_FNAME);
149    }
150    if (Require) {
151	copy_file(home, Require, REQUIRE_FNAME);
152	add_plist(&plist, PLIST_IGNORE, NULL);
153	add_plist(&plist, PLIST_FILE, REQUIRE_FNAME);
154    }
155    if (Display) {
156	copy_file(home, Display, DISPLAY_FNAME);
157	add_plist(&plist, PLIST_IGNORE, NULL);
158	add_plist(&plist, PLIST_FILE, DISPLAY_FNAME);
159	add_plist(&plist, PLIST_DISPLAY, DISPLAY_FNAME);
160    }
161    if (Mtree) {
162	copy_file(home, Mtree, MTREE_FNAME);
163	add_plist(&plist, PLIST_IGNORE, NULL);
164	add_plist(&plist, PLIST_FILE, MTREE_FNAME);
165	add_plist(&plist, PLIST_MTREE, MTREE_FNAME);
166    }
167
168    /* Finally, write out the packing list */
169    fp = fopen(CONTENTS_FNAME, "w");
170    if (!fp)
171	cleanup(0), errx(2, "can't open file %s for writing", CONTENTS_FNAME);
172    write_plist(&plist, fp);
173    if (fclose(fp))
174	cleanup(0), errx(2, "error while closing %s", CONTENTS_FNAME);
175
176    /* And stick it into a tar ball */
177    make_dist(home, pkg, suffix, &plist);
178
179    /* Cleanup */
180    free(Comment);
181    free(Desc);
182    free_plist(&plist);
183    leave_playpen();
184    return TRUE;	/* Success */
185}
186
187static void
188make_dist(char *home, char *pkg, char *suffix, Package *plist)
189{
190    char tball[FILENAME_MAX];
191    PackingList p;
192    int ret;
193    char *args[50];	/* Much more than enough. */
194    int nargs = 0;
195    int pipefds[2];
196    FILE *totar;
197    pid_t pid;
198
199    args[nargs++] = "tar";	/* argv[0] */
200
201    if (*pkg == '/')
202	snprintf(tball, FILENAME_MAX, "%s.%s", pkg, suffix);
203    else
204	snprintf(tball, FILENAME_MAX, "%s/%s.%s", home, pkg, suffix);
205
206    args[nargs++] = "-c";
207    args[nargs++] = "-f";
208    args[nargs++] = tball;
209    if (index(suffix, 'z'))	/* Compress/gzip? */
210	args[nargs++] = "-z";
211    if (Dereference)
212	args[nargs++] = "-h";
213    if (ExcludeFrom) {
214	args[nargs++] = "-X";
215	args[nargs++] = ExcludeFrom;
216    }
217    args[nargs++] = "-T";	/* Take filenames from file instead of args. */
218    args[nargs++] = "-";	/* Use stdin for the file. */
219    args[nargs] = NULL;
220
221    if (Verbose)
222	printf("Creating gzip'd tar ball in '%s'\n", tball);
223
224    /* Set up a pipe for passing the filenames, and fork off a tar process. */
225    if (pipe(pipefds) == -1)
226	cleanup(0), errx(2, "cannot create pipe");
227    if ((pid = fork()) == -1)
228	cleanup(0), errx(2, "cannot fork process for tar");
229    if (pid == 0) {	/* The child */
230	dup2(pipefds[0], 0);
231	close(pipefds[0]);
232	close(pipefds[1]);
233	execv("/usr/bin/tar", args);
234	cleanup(0);
235	errx(2, "failed to execute tar command");
236    }
237
238    /* Meanwhile, back in the parent process ... */
239    close(pipefds[0]);
240    if ((totar = fdopen(pipefds[1], "w")) == NULL)
241	cleanup(0), errx(2, "fdopen failed");
242
243    fprintf(totar, "%s\n", CONTENTS_FNAME);
244    fprintf(totar, "%s\n", COMMENT_FNAME);
245    fprintf(totar, "%s\n", DESC_FNAME);
246
247    if (Install)
248	fprintf(totar, "%s\n", INSTALL_FNAME);
249    if (DeInstall)
250	fprintf(totar, "%s\n", DEINSTALL_FNAME);
251    if (Require)
252	fprintf(totar, "%s\n", REQUIRE_FNAME);
253    if (Display)
254	fprintf(totar, "%s\n", DISPLAY_FNAME);
255    if (Mtree)
256	fprintf(totar, "%s\n", MTREE_FNAME);
257
258    for (p = plist->head; p; p = p->next) {
259	if (p->type == PLIST_FILE)
260	    fprintf(totar, "%s\n", p->name);
261	else if (p->type == PLIST_CWD || p->type == PLIST_SRC)
262	    fprintf(totar, "-C\n%s\n", p->name);
263	else if (p->type == PLIST_IGNORE)
264	     p = p->next;
265    }
266
267    fclose(totar);
268    wait(&ret);
269    /* assume either signal or bad exit is enough for us */
270    if (ret)
271	cleanup(0), errx(2, "tar command failed with code %d", ret);
272}
273
274static void
275sanity_check()
276{
277    if (!Comment)
278	cleanup(0), errx(2,
279		"required package comment string is missing (-c comment)");
280    if (!Desc)
281	cleanup(0), errx(2,
282		"required package description string is missing (-d desc)");
283    if (!Contents)
284	cleanup(0), errx(2,
285		"required package contents list is missing (-f [-]file)");
286}
287
288
289/* Clean up those things that would otherwise hang around */
290void
291cleanup(int sig)
292{
293    int in_cleanup = 0;
294
295    if (!in_cleanup) {
296	in_cleanup = 1;
297    	leave_playpen();
298    }
299    if (sig)
300	exit(1);
301}
302