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