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