1327Sjkh/*
2228990Suqs * FreeBSD install - a package for the installation and maintenance
3327Sjkh * of non-core utilities.
4327Sjkh *
5327Sjkh * Redistribution and use in source and binary forms, with or without
6327Sjkh * modification, are permitted provided that the following conditions
7327Sjkh * are met:
8327Sjkh * 1. Redistributions of source code must retain the above copyright
9327Sjkh *    notice, this list of conditions and the following disclaimer.
10327Sjkh * 2. Redistributions in binary form must reproduce the above copyright
11327Sjkh *    notice, this list of conditions and the following disclaimer in the
12327Sjkh *    documentation and/or other materials provided with the distribution.
13327Sjkh *
14327Sjkh * Jordan K. Hubbard
15327Sjkh * 18 July 1993
16327Sjkh *
17327Sjkh * This is the package extraction code for the add module.
18327Sjkh *
19327Sjkh */
20327Sjkh
2193520Sobrien#include <sys/cdefs.h>
2293520Sobrien__FBSDID("$FreeBSD$");
2393520Sobrien
24124922Sdes#include <ctype.h>
2530221Scharnier#include <err.h>
26222035Sflz#include "lib.h"
27327Sjkh#include "add.h"
28327Sjkh
294996Sjkh
30131285Seik#define STARTSTRING "/usr/bin/tar cf -"
31124921Sdes#define TOOBIG(str) \
32124921Sdes    (((int)strlen(str) + FILENAME_MAX + where_count > maxargs) ||\
33124921Sdes	((int)strlen(str) + FILENAME_MAX + perm_count > maxargs))
344996Sjkh
354996Sjkh#define PUSHOUT(todir) /* push out string */ \
36124921Sdes    if (where_count > (int)sizeof(STARTSTRING)-1) { \
37171934Skrion	strcat(where_args, "|/usr/bin/tar --unlink -xpPf - -C "); \
38124921Sdes	strcat(where_args, todir); \
39124921Sdes	if (system(where_args)) { \
40124921Sdes	    cleanup(0); \
41124921Sdes	    errx(2, "%s: can not invoke %ld byte tar pipeline: %s", \
42124921Sdes		 __func__, (long)strlen(where_args), where_args); \
434996Sjkh	} \
44124921Sdes	strcpy(where_args, STARTSTRING); \
45124921Sdes	where_count = sizeof(STARTSTRING)-1; \
46124921Sdes    } \
47124921Sdes    if (perm_count) { \
48124921Sdes	apply_perms(todir, perm_args); \
49124921Sdes	perm_args[0] = 0;\
50124921Sdes	perm_count = 0; \
51124921Sdes    }
524996Sjkh
5327056Sjkhstatic void
5484745Ssobomaxrollback(const char *name, const char *home, PackingList start, PackingList stop)
5527056Sjkh{
5627056Sjkh    PackingList q;
5784745Ssobomax    char try[FILENAME_MAX], bup[FILENAME_MAX];
5884745Ssobomax    const char *dir;
59154102Skrion    char *prefix = NULL;
6027056Sjkh
6127056Sjkh    dir = home;
6227056Sjkh    for (q = start; q != stop; q = q->next) {
6327056Sjkh	if (q->type == PLIST_FILE) {
6427056Sjkh	    snprintf(try, FILENAME_MAX, "%s/%s", dir, q->name);
6527137Sjkh	    if (make_preserve_name(bup, FILENAME_MAX, name, try) && fexists(bup)) {
6627056Sjkh		(void)chflags(try, 0);
6727056Sjkh		(void)unlink(try);
6827056Sjkh		if (rename(bup, try))
6930221Scharnier		    warnx("rollback: unable to rename %s back to %s", bup, try);
7027056Sjkh	    }
7127056Sjkh	}
7227056Sjkh	else if (q->type == PLIST_CWD) {
73154102Skrion	    if (!prefix)
74154102Skrion		prefix = q->name;
75154102Skrion	    if (q->name == NULL)
76154102Skrion		q->name = prefix;
77154102Skrion	    else if (strcmp(q->name, "."))
7827056Sjkh		dir = q->name;
7927056Sjkh	    else
8027056Sjkh		dir = home;
8127056Sjkh	}
8227056Sjkh    }
8327056Sjkh}
8427056Sjkh
85124922Sdes#define add_char(buf, len, pos, ch) do {\
86124922Sdes    if ((pos) < (len)) { \
87124922Sdes        buf[(pos)] = (ch); \
88124922Sdes        buf[(pos) + 1] = '\0'; \
89124922Sdes    } \
90124922Sdes    ++(pos); \
91124922Sdes} while (0)
92124922Sdes
93131280Seikstatic int
94124922Sdesadd_arg(char *buf, int len, const char *str)
95124922Sdes{
96124922Sdes    int i = 0;
97124922Sdes
98124922Sdes    add_char(buf, len, i, ' ');
99124922Sdes    for (; *str != '\0'; ++str) {
100124922Sdes	if (!isalnum(*str) && *str != '/' && *str != '.' && *str != '-')
101124922Sdes	    add_char(buf, len, i, '\\');
102124922Sdes	add_char(buf, len, i, *str);
103124922Sdes    }
104124922Sdes    return (i);
105124922Sdes}
106124922Sdes
107327Sjkhvoid
10884745Ssobomaxextract_plist(const char *home, Package *pkg)
109327Sjkh{
110327Sjkh    PackingList p = pkg->head;
111154102Skrion    char *last_file, *prefix = NULL;
1124996Sjkh    char *where_args, *perm_args, *last_chdir;
113252363Sobrien    long maxargs;
114252363Sobrien    int where_count = 0, perm_count = 0, add_count;
11527056Sjkh    Boolean preserve;
116327Sjkh
11723109Sjkh    maxargs = sysconf(_SC_ARG_MAX) / 2;	/* Just use half the argument space */
11822762Sjkh    where_args = alloca(maxargs);
11939068Sjkh    if (!where_args) {
12039068Sjkh	cleanup(0);
12196392Salfred	errx(2, "%s: can't get argument list space", __func__);
12239068Sjkh    }
12322762Sjkh    perm_args = alloca(maxargs);
12439068Sjkh    if (!perm_args) {
12539068Sjkh	cleanup(0);
12696392Salfred	errx(2, "%s: can't get argument list space", __func__);
12739068Sjkh    }
1284996Sjkh
1294996Sjkh    strcpy(where_args, STARTSTRING);
1304996Sjkh    where_count = sizeof(STARTSTRING)-1;
1314996Sjkh    perm_args[0] = 0;
1324996Sjkh
1334996Sjkh    last_chdir = 0;
13427056Sjkh    preserve = find_plist_option(pkg, "preserve") ? TRUE : FALSE;
1354996Sjkh
136327Sjkh    /* Reset the world */
137327Sjkh    Owner = NULL;
138327Sjkh    Group = NULL;
139327Sjkh    Mode = NULL;
140327Sjkh    last_file = NULL;
141132789Skan    Directory = (char *)home;
142327Sjkh
143327Sjkh    /* Do it */
144327Sjkh    while (p) {
145477Sjkh	char cmd[FILENAME_MAX];
146477Sjkh
147327Sjkh	switch(p->type) {
148327Sjkh	case PLIST_NAME:
149327Sjkh	    PkgName = p->name;
150327Sjkh	    if (Verbose)
151327Sjkh		printf("extract: Package name is %s\n", p->name);
152327Sjkh	    break;
153327Sjkh
154327Sjkh	case PLIST_FILE:
155327Sjkh	    last_file = p->name;
156327Sjkh	    if (Verbose)
157327Sjkh		printf("extract: %s/%s\n", Directory, p->name);
158327Sjkh	    if (!Fake) {
159382Sjkh		char try[FILENAME_MAX];
160382Sjkh
161382Sjkh		/* first try to rename it into place */
16227137Sjkh		snprintf(try, FILENAME_MAX, "%s/%s", Directory, p->name);
16327137Sjkh		if (fexists(try)) {
16427137Sjkh		    (void)chflags(try, 0);	/* XXX hack - if truly immutable, rename fails */
16527137Sjkh		    if (preserve && PkgName) {
16627137Sjkh			char pf[FILENAME_MAX];
16727056Sjkh
16827137Sjkh			if (make_preserve_name(pf, FILENAME_MAX, PkgName, try)) {
16927137Sjkh			    if (rename(try, pf)) {
17030221Scharnier				warnx(
17130221Scharnier				"unable to back up %s to %s, aborting pkg_add",
17230221Scharnier				try, pf);
17327137Sjkh				rollback(PkgName, home, pkg->head, p);
17427137Sjkh				return;
17527137Sjkh			    }
17627137Sjkh			}
17727056Sjkh		    }
17827056Sjkh		}
1794996Sjkh		if (rename(p->name, try) == 0) {
18023109Sjkh		    /* try to add to list of perms to be changed and run in bulk. */
18123109Sjkh		    if (p->name[0] == '/' || TOOBIG(p->name)) {
18222762Sjkh			PUSHOUT(Directory);
18323109Sjkh		    }
184124922Sdes		    add_count = add_arg(&perm_args[perm_count], maxargs - perm_count, p->name);
185123602Snectar		    if (add_count < 0 || add_count >= maxargs - perm_count) {
18639068Sjkh			cleanup(0);
18796392Salfred			errx(2, "%s: oops, miscounted strings!", __func__);
18839068Sjkh		    }
1894996Sjkh		    perm_count += add_count;
19022762Sjkh		}
19122762Sjkh		else {
1924996Sjkh		    /* rename failed, try copying with a big tar command */
19323109Sjkh		    if (last_chdir != Directory) {
19437378Sjkh			if (last_chdir == NULL) {
19537378Sjkh			    PUSHOUT(Directory);
19637378Sjkh			} else {
19737378Sjkh			    PUSHOUT(last_chdir);
19837378Sjkh			}
1994996Sjkh			last_chdir = Directory;
2004996Sjkh		    }
20123109Sjkh		    else if (p->name[0] == '/' || TOOBIG(p->name)) {
20223109Sjkh			PUSHOUT(Directory);
20323109Sjkh		    }
204124922Sdes		    add_count = add_arg(&where_args[where_count], maxargs - where_count, p->name);
205123602Snectar		    if (add_count < 0 || add_count >= maxargs - where_count) {
20639068Sjkh			cleanup(0);
20796392Salfred			errx(2, "%s: oops, miscounted strings!", __func__);
20839068Sjkh		    }
2094996Sjkh		    where_count += add_count;
210124922Sdes		    add_count = add_arg(&perm_args[perm_count], maxargs - perm_count, p->name);
211123602Snectar		    if (add_count < 0 || add_count >= maxargs - perm_count) {
21239068Sjkh			cleanup(0);
21396392Salfred			errx(2, "%s: oops, miscounted strings!", __func__);
21439068Sjkh		    }
2154996Sjkh		    perm_count += add_count;
2164996Sjkh		}
217327Sjkh	    }
218327Sjkh	    break;
219327Sjkh
220327Sjkh	case PLIST_CWD:
221154102Skrion	    if (!prefix)
222154102Skrion		prefix = p->name;
223154102Skrion	    if (p->name == NULL)
224154102Skrion		p->name = strdup(prefix);
225327Sjkh	    if (Verbose)
226327Sjkh		printf("extract: CWD to %s\n", p->name);
2274996Sjkh	    PUSHOUT(Directory);
228327Sjkh	    if (strcmp(p->name, ".")) {
229240476Sjkim		if (!Fake && make_hierarchy(p->name, TRUE) == FAIL) {
23039068Sjkh		    cleanup(0);
23196392Salfred		    errx(2, "%s: unable to cwd to '%s'", __func__, p->name);
23239068Sjkh		}
233327Sjkh		Directory = p->name;
234327Sjkh	    }
235327Sjkh	    else
236132789Skan		Directory = (char *)home;
237327Sjkh	    break;
238327Sjkh
239327Sjkh	case PLIST_CMD:
24030686Smax	    if ((strstr(p->name, "%B") || strstr(p->name, "%F") ||
24139068Sjkh		 strstr(p->name, "%f")) && last_file == NULL) {
24239068Sjkh		cleanup(0);
24396388Salfred		errx(2, "%s: no last file specified for '%s' command",
24496392Salfred		    __func__, p->name);
24539068Sjkh	    }
24639068Sjkh	    if (strstr(p->name, "%D") && Directory == NULL) {
24739068Sjkh		cleanup(0);
24896388Salfred		errx(2, "%s: no directory specified for '%s' command",
24996392Salfred		    __func__, p->name);
25039068Sjkh	    }
251108778Sjkh	    format_cmd(cmd, FILENAME_MAX, p->name, Directory, last_file);
2524996Sjkh	    PUSHOUT(Directory);
253327Sjkh	    if (Verbose)
254477Sjkh		printf("extract: execute '%s'\n", cmd);
255477Sjkh	    if (!Fake && system(cmd))
25630221Scharnier		warnx("command '%s' failed", cmd);
257327Sjkh	    break;
258327Sjkh
259327Sjkh	case PLIST_CHMOD:
2604996Sjkh	    PUSHOUT(Directory);
261327Sjkh	    Mode = p->name;
262327Sjkh	    break;
263327Sjkh
264327Sjkh	case PLIST_CHOWN:
2654996Sjkh	    PUSHOUT(Directory);
266327Sjkh	    Owner = p->name;
267327Sjkh	    break;
268327Sjkh
269327Sjkh	case PLIST_CHGRP:
2704996Sjkh	    PUSHOUT(Directory);
271327Sjkh	    Group = p->name;
272327Sjkh	    break;
273327Sjkh
274147381Skrion	case PLIST_COMMENT: /* FALLTHROUGH */
275147381Skrion	case PLIST_NOINST:
276327Sjkh	    break;
277327Sjkh
278327Sjkh	case PLIST_IGNORE:
279327Sjkh	    p = p->next;
280327Sjkh	    break;
28171373Ssobomax
28271373Ssobomax	default:
28371373Ssobomax	    break;
284327Sjkh	}
285327Sjkh	p = p->next;
286327Sjkh    }
2874996Sjkh    PUSHOUT(Directory);
288327Sjkh}
289