2 * FreeBSD install - a package for the installation and maintainance
3 * of non-core utilities.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
17 * Routines for dealing with the packing list.
21 #include <sys/cdefs.h>
22 __FBSDID("$FreeBSD$");
30 /* Add an MD5 checksum entry for a file or link */
32 add_cksum(Package
*pkg
, PackingList p
, const char *fname
)
34 char *cp
= NULL
, buf
[33];
36 if (issymlink(fname
)) {
38 char lnk
[FILENAME_MAX
];
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
);
48 PackingList tmp
= new_plist_entry();
50 tmp
->name
= copy_string(strconcat("MD5:", cp
));
51 tmp
->type
= PLIST_COMMENT
;
60 /* Check a list for files that require preconversion */
62 check_list(const char *home
, Package
*pkg
)
64 const char *where
= home
;
65 const char *there
= NULL
;
66 char name
[FILENAME_MAX
];
70 for (p
= pkg
->head
; p
!= NULL
; p
= p
->next
)
75 where
= (p
->name
== NULL
) ? prefix
: p
->name
;
88 snprintf(name
, sizeof(name
), "%s/%s", there
, p
->name
);
90 snprintf(name
, sizeof(name
), "%s%s/%s",
91 BaseDir
&& where
&& where
[0] == '/' ? BaseDir
: "", where
, p
->name
);
93 add_cksum(pkg
, p
, name
);
101 trylink(const char *from
, const char *to
)
103 if (link(from
, to
) == 0)
105 if (errno
== ENOENT
) {
106 /* try making the container directory */
107 char *cp
= strrchr(to
, '/');
109 vsystem("/bin/mkdir -p %.*s", cp
- to
,
111 return link(from
, to
);
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)) { \
123 errx(2, "%s: can't invoke tar pipeline", __func__); \
125 memset(where_args, 0, maxargs); \
127 strcpy(where_args, STARTSTRING); \
128 where_count = sizeof(STARTSTRING)-1; \
132 * Copy unmarked files in packing list to playpen - marked files
133 * have already been copied in an earlier pass through the list.
136 copy_plist(const char *home
, Package
*plist
)
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
;
147 maxargs
= sysconf(_SC_ARG_MAX
);
149 * Some slop for the tar cmd text,
152 where_args
= malloc(maxargs
);
155 errx(2, "%s: can't get argument list space", __func__
);
158 memset(where_args
, 0, maxargs
);
159 strcpy(where_args
, STARTSTRING
);
160 where_count
= sizeof(STARTSTRING
)-1;
163 if (stat(".", &stb
) == 0)
166 curdir
= (dev_t
) -1; /*
167 * It's ok if this is a valid dev_t;
168 * this is just a hint for an
173 if (p
->type
== PLIST_CWD
)
177 where
= p
->name
== NULL
? prefix
: p
->name
;
179 else if (p
->type
== PLIST_SRC
)
181 else if (p
->type
== PLIST_IGNORE
)
183 else if (p
->type
== PLIST_FILE
&& !p
->marked
) {
184 char fn
[FILENAME_MAX
];
187 /* First, look for it in the "home" dir */
188 sprintf(fn
, "%s/%s", home
, p
->name
);
190 if (lstat(fn
, &stb
) == 0 && stb
.st_dev
== curdir
&&
191 S_ISREG(stb
.st_mode
)) {
193 * If we can link it to the playpen, that avoids a copy
196 if (p
->name
[0] != '/') {
198 * Don't link abspn stuff--it doesn't come from
201 if (trylink(fn
, p
->name
) == 0) {
210 if (p
->name
[0] == '/') {
211 add_count
= snprintf(&where_args
[where_count
],
212 maxargs
- where_count
,
214 last_chdir
== root
? "" : "-C /",
218 add_count
= snprintf(&where_args
[where_count
],
219 maxargs
- where_count
,
221 last_chdir
== home
? "" : "-C ",
222 last_chdir
== home
? "" : home
,
226 if (add_count
< 0 || add_count
>= maxargs
- where_count
) {
228 errx(2, "%s: oops, miscounted strings!", __func__
);
230 where_count
+= add_count
;
233 * Otherwise, try along the actual extraction path..
236 if (p
->name
[0] == '/')
238 else mythere
= there
;
240 snprintf(fn
, sizeof(fn
), "%s/%s", mythere
, p
->name
);
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
)) {
247 * If we can link it to the playpen, that avoids a copy
250 if (trylink(fn
, p
->name
) == 0) {
255 if (TOOBIG(p
->name
)) {
258 if (last_chdir
== (mythere
? mythere
: where
))
259 add_count
= snprintf(&where_args
[where_count
],
260 maxargs
- where_count
,
263 add_count
= snprintf(&where_args
[where_count
],
264 maxargs
- where_count
,
266 mythere
? mythere
: where
,
268 if (add_count
< 0 || add_count
>= maxargs
- where_count
) {
270 errx(2, "%s: oops, miscounted strings!", __func__
);
272 where_count
+= add_count
;
273 last_chdir
= (mythere
? mythere
: where
);