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