Clean (void) casts from usr.sbin
[dragonfly.git] / usr.sbin / pkg_install / add / extract.c
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 package extraction code for the add module.
18  *
19  * $FreeBSD: src/usr.sbin/pkg_install/add/extract.c,v 1.42 2004/07/28 07:19:15 kan Exp $
20  * $DragonFly: src/usr.sbin/pkg_install/add/Attic/extract.c,v 1.4 2004/12/18 22:48:04 swildner Exp $
21  */
22
23 #include <ctype.h>
24 #include <err.h>
25 #include "lib.h"
26 #include "add.h"
27
28
29 #define STARTSTRING "/usr/bin/tar cf -"
30 #define TOOBIG(str) \
31     (((int)strlen(str) + FILENAME_MAX + where_count > maxargs) ||\
32         ((int)strlen(str) + FILENAME_MAX + perm_count > maxargs))
33
34 #define PUSHOUT(todir) /* push out string */ \
35     if (where_count > (int)sizeof(STARTSTRING)-1) { \
36         strcat(where_args, "|/usr/bin/tar --unlink -xpf - -C "); \
37         strcat(where_args, todir); \
38         if (system(where_args)) { \
39             cleanup(0); \
40             errx(2, "%s: can not invoke %ld byte tar pipeline: %s", \
41                  __func__, (long)strlen(where_args), where_args); \
42         } \
43         strcpy(where_args, STARTSTRING); \
44         where_count = sizeof(STARTSTRING)-1; \
45     } \
46     if (perm_count) { \
47         apply_perms(todir, perm_args); \
48         perm_args[0] = 0;\
49         perm_count = 0; \
50     }
51
52 static void
53 rollback(const char *name, const char *home, PackingList start, PackingList stop)
54 {
55     PackingList q;
56     char try[FILENAME_MAX], bup[FILENAME_MAX];
57     const char *dir;
58
59     dir = home;
60     for (q = start; q != stop; q = q->next) {
61         if (q->type == PLIST_FILE) {
62             snprintf(try, FILENAME_MAX, "%s/%s", dir, q->name);
63             if (make_preserve_name(bup, FILENAME_MAX, name, try) && fexists(bup)) {
64                 chflags(try, 0);
65                 unlink(try);
66                 if (rename(bup, try))
67                     warnx("rollback: unable to rename %s back to %s", bup, try);
68             }
69         }
70         else if (q->type == PLIST_CWD) {
71             if (strcmp(q->name, "."))
72                 dir = q->name;
73             else
74                 dir = home;
75         }
76     }
77 }
78
79 #define add_char(buf, len, pos, ch) do {\
80     if ((pos) < (len)) { \
81         buf[(pos)] = (ch); \
82         buf[(pos) + 1] = '\0'; \
83     } \
84     ++(pos); \
85 } while (0)
86
87 static int
88 add_arg(char *buf, int len, const char *str)
89 {
90     int i = 0;
91
92     add_char(buf, len, i, ' ');
93     for (; *str != '\0'; ++str) {
94         if (!isalnum(*str) && *str != '/' && *str != '.' && *str != '-')
95             add_char(buf, len, i, '\\');
96         add_char(buf, len, i, *str);
97     }
98     return (i);
99 }
100
101 void
102 extract_plist(const char *home, Package *pkg)
103 {
104     PackingList p = pkg->head;
105     char *last_file;
106     char *where_args, *perm_args, *last_chdir;
107     int maxargs, where_count = 0, perm_count = 0, add_count;
108     Boolean preserve;
109
110     maxargs = sysconf(_SC_ARG_MAX) / 2; /* Just use half the argument space */
111     where_args = alloca(maxargs);
112     if (!where_args) {
113         cleanup(0);
114         errx(2, "%s: can't get argument list space", __func__);
115     }
116     perm_args = alloca(maxargs);
117     if (!perm_args) {
118         cleanup(0);
119         errx(2, "%s: can't get argument list space", __func__);
120     }
121
122     strcpy(where_args, STARTSTRING);
123     where_count = sizeof(STARTSTRING)-1;
124     perm_args[0] = 0;
125
126     last_chdir = 0;
127     preserve = find_plist_option(pkg, "preserve") ? TRUE : FALSE;
128
129     /* Reset the world */
130     Owner = NULL;
131     Group = NULL;
132     Mode = NULL;
133     last_file = NULL;
134     Directory = (char *)home;
135
136     /* Do it */
137     while (p) {
138         char cmd[FILENAME_MAX];
139
140         switch(p->type) {
141         case PLIST_NAME:
142             PkgName = p->name;
143             if (Verbose)
144                 printf("extract: Package name is %s\n", p->name);
145             break;
146
147         case PLIST_FILE:
148             last_file = p->name;
149             if (Verbose)
150                 printf("extract: %s/%s\n", Directory, p->name);
151             if (!Fake) {
152                 char try[FILENAME_MAX];
153
154                 /* first try to rename it into place */
155                 snprintf(try, FILENAME_MAX, "%s/%s", Directory, p->name);
156                 if (fexists(try)) {
157                     chflags(try, 0);    /* XXX hack - if truly immutable, rename fails */
158                     if (preserve && PkgName) {
159                         char pf[FILENAME_MAX];
160
161                         if (make_preserve_name(pf, FILENAME_MAX, PkgName, try)) {
162                             if (rename(try, pf)) {
163                                 warnx(
164                                 "unable to back up %s to %s, aborting pkg_add",
165                                 try, pf);
166                                 rollback(PkgName, home, pkg->head, p);
167                                 return;
168                             }
169                         }
170                     }
171                 }
172                 if (rename(p->name, try) == 0) {
173                     /* try to add to list of perms to be changed and run in bulk. */
174                     if (p->name[0] == '/' || TOOBIG(p->name)) {
175                         PUSHOUT(Directory);
176                     }
177                     add_count = add_arg(&perm_args[perm_count], maxargs - perm_count, p->name);
178                     if (add_count < 0 || add_count >= maxargs - perm_count) {
179                         cleanup(0);
180                         errx(2, "%s: oops, miscounted strings!", __func__);
181                     }
182                     perm_count += add_count;
183                 }
184                 else {
185                     /* rename failed, try copying with a big tar command */
186                     if (last_chdir != Directory) {
187                         if (last_chdir == NULL) {
188                             PUSHOUT(Directory);
189                         } else {
190                             PUSHOUT(last_chdir);
191                         }
192                         last_chdir = Directory;
193                     }
194                     else if (p->name[0] == '/' || TOOBIG(p->name)) {
195                         PUSHOUT(Directory);
196                     }
197                     add_count = add_arg(&where_args[where_count], maxargs - where_count, p->name);
198                     if (add_count < 0 || add_count >= maxargs - where_count) {
199                         cleanup(0);
200                         errx(2, "%s: oops, miscounted strings!", __func__);
201                     }
202                     where_count += add_count;
203                     add_count = add_arg(&perm_args[perm_count], maxargs - perm_count, p->name);
204                     if (add_count < 0 || add_count >= maxargs - perm_count) {
205                         cleanup(0);
206                         errx(2, "%s: oops, miscounted strings!", __func__);
207                     }
208                     perm_count += add_count;
209                 }
210             }
211             break;
212
213         case PLIST_CWD:
214             if (Verbose)
215                 printf("extract: CWD to %s\n", p->name);
216             PUSHOUT(Directory);
217             if (strcmp(p->name, ".")) {
218                 if (!Fake && make_hierarchy(p->name) == FAIL) {
219                     cleanup(0);
220                     errx(2, "%s: unable to cwd to '%s'", __func__, p->name);
221                 }
222                 Directory = p->name;
223             }
224             else
225                 Directory = (char *)home;
226             break;
227
228         case PLIST_CMD:
229             if ((strstr(p->name, "%B") || strstr(p->name, "%F") ||
230                  strstr(p->name, "%f")) && last_file == NULL) {
231                 cleanup(0);
232                 errx(2, "%s: no last file specified for '%s' command",
233                     __func__, p->name);
234             }
235             if (strstr(p->name, "%D") && Directory == NULL) {
236                 cleanup(0);
237                 errx(2, "%s: no directory specified for '%s' command",
238                     __func__, p->name);
239             }
240             format_cmd(cmd, FILENAME_MAX, p->name, Directory, last_file);
241             PUSHOUT(Directory);
242             if (Verbose)
243                 printf("extract: execute '%s'\n", cmd);
244             if (!Fake && system(cmd))
245                 warnx("command '%s' failed", cmd);
246             break;
247
248         case PLIST_CHMOD:
249             PUSHOUT(Directory);
250             Mode = p->name;
251             break;
252
253         case PLIST_CHOWN:
254             PUSHOUT(Directory);
255             Owner = p->name;
256             break;
257
258         case PLIST_CHGRP:
259             PUSHOUT(Directory);
260             Group = p->name;
261             break;
262
263         case PLIST_COMMENT:
264             break;
265
266         case PLIST_IGNORE:
267             p = p->next;
268             break;
269
270         default:
271             break;
272         }
273         p = p->next;
274     }
275     PUSHOUT(Directory);
276 }