Comment out empty BUGS section.
[dragonfly.git] / usr.sbin / pkg_install / create / pl.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  * Routines for dealing with the packing list.
18  *
19  * $FreeBSD: src/usr.sbin/pkg_install/create/pl.c,v 1.27 2004/06/29 19:06:41 eik Exp $
20  * $DragonFly: src/usr.sbin/pkg_install/create/Attic/pl.c,v 1.3 2004/07/30 04:46:12 dillon Exp $
21  */
22
23 #include "lib.h"
24 #include "create.h"
25 #include <errno.h>
26 #include <err.h>
27 #include <md5.h>
28
29 /* Add an MD5 checksum entry for a file or link */
30 void
31 add_cksum(Package *pkg, PackingList p, const char *fname)
32 {
33     char *cp = NULL, buf[33];
34
35     if (issymlink(fname)) {
36         int len;
37         char lnk[FILENAME_MAX];
38
39         if ((len = readlink(fname, lnk, FILENAME_MAX)) > 0)
40             cp = MD5Data((unsigned char *)lnk, len, buf);
41     } else if (isfile(fname)) {
42         /* Don't record MD5 checksum for device nodes and such */
43         cp = MD5File(fname, buf);
44     }
45
46     if (cp != NULL) {
47         PackingList tmp = new_plist_entry();
48
49         tmp->name = copy_string(strconcat("MD5:", cp));
50         tmp->type = PLIST_COMMENT;
51         tmp->next = p->next;
52         tmp->prev = p;
53         p->next = tmp;
54         if (pkg->tail == p)
55             pkg->tail = tmp;
56     }
57 }
58
59 /* Check a list for files that require preconversion */
60 void
61 check_list(const char *home, Package *pkg)
62 {
63     const char *where = home;
64     const char *there = NULL;
65     char name[FILENAME_MAX];
66     PackingList p;
67
68     for (p = pkg->head; p != NULL; p = p->next)
69         switch (p->type) {
70         case PLIST_CWD:
71             where = p->name;
72             break;
73
74         case PLIST_IGNORE:
75             p = p->next;
76             break;
77
78         case PLIST_SRC:
79             there = p->name;
80             break;
81
82         case PLIST_FILE:
83             if (there)
84                 snprintf(name, sizeof(name), "%s/%s", there, p->name);
85             else
86                 snprintf(name, sizeof(name), "%s%s/%s",
87                     BaseDir && where && where[0] == '/' ? BaseDir : "", where, p->name);
88
89             add_cksum(pkg, p, name);
90             break;
91         default:
92             break;
93         }
94 }
95
96 static int
97 trylink(const char *from, const char *to)
98 {
99     if (link(from, to) == 0)
100         return 0;
101     if (errno == ENOENT) {
102         /* try making the container directory */
103         char *cp = strrchr(to, '/');
104         if (cp)
105             vsystem("/bin/mkdir -p %.*s", cp - to,
106                     to);
107         return link(from, to);
108     }
109     return -1;
110 }
111
112 #define STARTSTRING "/usr/bin/tar cf -"
113 #define TOOBIG(str) (int)strlen(str) + 6 + (int)strlen(home) + where_count > maxargs
114 #define PUSHOUT() /* push out string */ \
115         if (where_count > (int)sizeof(STARTSTRING)-1) { \
116                     strcat(where_args, "|/usr/bin/tar xpf -"); \
117                     if (system(where_args)) { \
118                         cleanup(0); \
119                         errx(2, "%s: can't invoke tar pipeline", __func__); \
120                     } \
121                     memset(where_args, 0, maxargs); \
122                     last_chdir = NULL; \
123                     strcpy(where_args, STARTSTRING); \
124                     where_count = sizeof(STARTSTRING)-1; \
125         }
126
127 /*
128  * Copy unmarked files in packing list to playpen - marked files
129  * have already been copied in an earlier pass through the list.
130  */
131 void
132 copy_plist(const char *home, Package *plist)
133 {
134     PackingList p = plist->head;
135     const char *where = home;
136     const char *there = NULL, *mythere;
137     char *where_args;
138     const char *last_chdir, *root = "/";
139     int maxargs, where_count = 0, add_count;
140     struct stat stb;
141     dev_t curdir;
142
143     maxargs = sysconf(_SC_ARG_MAX);
144     maxargs -= 64;                      /*
145                                          * Some slop for the tar cmd text,
146                                          * and sh -c
147                                          */
148     where_args = malloc(maxargs);
149     if (!where_args) {
150         cleanup(0);
151         errx(2, "%s: can't get argument list space", __func__);
152     }
153
154     memset(where_args, 0, maxargs);
155     strcpy(where_args, STARTSTRING);
156     where_count = sizeof(STARTSTRING)-1;
157     last_chdir = 0;
158
159     if (stat(".", &stb) == 0)
160         curdir = stb.st_dev;
161     else
162         curdir = (dev_t) -1;            /*
163                                          * It's ok if this is a valid dev_t;
164                                          * this is just a hint for an
165                                          * optimization.
166                                          */
167
168     while (p) {
169         if (p->type == PLIST_CWD)
170             where = p->name;
171         else if (p->type == PLIST_SRC)
172             there = p->name;
173         else if (p->type == PLIST_IGNORE)
174             p = p->next;
175         else if (p->type == PLIST_FILE && !p->marked) {
176             char fn[FILENAME_MAX];
177
178
179             /* First, look for it in the "home" dir */
180             sprintf(fn, "%s/%s", home, p->name);
181             if (fexists(fn)) {
182                 if (lstat(fn, &stb) == 0 && stb.st_dev == curdir &&
183                     S_ISREG(stb.st_mode)) {
184                     /*
185                      * If we can link it to the playpen, that avoids a copy
186                      * and saves time.
187                      */
188                     if (p->name[0] != '/') {
189                         /*
190                          * Don't link abspn stuff--it doesn't come from
191                          * local dir!
192                          */
193                         if (trylink(fn, p->name) == 0) {
194                             p = p->next;
195                             continue;
196                         }
197                     }
198                 }
199                 if (TOOBIG(fn)) {
200                     PUSHOUT();
201                 }
202                 if (p->name[0] == '/') {
203                     add_count = snprintf(&where_args[where_count],
204                                          maxargs - where_count,
205                                          " %s %s",
206                                          last_chdir == root ? "" : "-C /",
207                                          p->name);
208                     last_chdir = root;
209                 } else {
210                     add_count = snprintf(&where_args[where_count],
211                                          maxargs - where_count,
212                                          " %s%s %s",
213                                          last_chdir == home ? "" : "-C ",
214                                          last_chdir == home ? "" : home,
215                                          p->name);
216                     last_chdir = home;
217                 }
218                 if (add_count < 0 || add_count >= maxargs - where_count) {
219                     cleanup(0);
220                     errx(2, "%s: oops, miscounted strings!", __func__);
221                 }
222                 where_count += add_count;
223             }
224             /*
225              * Otherwise, try along the actual extraction path..
226              */
227             else {
228                 if (p->name[0] == '/')
229                     mythere = root;
230                 else mythere = there;
231                 if (mythere)
232                     snprintf(fn, sizeof(fn), "%s/%s", mythere, p->name);
233                 else
234                     snprintf(fn, sizeof(fn), "%s%s/%s",
235                         BaseDir && where && where[0] == '/' ? BaseDir : "", where, p->name);
236                 if (lstat(fn, &stb) == 0 && stb.st_dev == curdir &&
237                     S_ISREG(stb.st_mode)) {
238                     /*
239                      * If we can link it to the playpen, that avoids a copy
240                      * and saves time.
241                      */
242                     if (trylink(fn, p->name) == 0) {
243                         p = p->next;
244                         continue;
245                     }
246                 }
247                 if (TOOBIG(p->name)) {
248                     PUSHOUT();
249                 }
250                 if (last_chdir == (mythere ? mythere : where))
251                     add_count = snprintf(&where_args[where_count],
252                                          maxargs - where_count,
253                                          " %s", p->name);
254                 else
255                     add_count = snprintf(&where_args[where_count],
256                                          maxargs - where_count,
257                                          " -C %s %s",
258                                          mythere ? mythere : where,
259                                          p->name);
260                 if (add_count < 0 || add_count >= maxargs - where_count) {
261                     cleanup(0);
262                     errx(2, "%s: oops, miscounted strings!", __func__);
263                 }
264                 where_count += add_count;
265                 last_chdir = (mythere ? mythere : where);
266             }
267         }
268         p = p->next;
269     }
270     PUSHOUT();
271     free(where_args);
272 }