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