turns printfs back on
[freebsd-src/fkvm-freebsd.git] / usr.sbin / pkg_install / lib / file.c
blob0b74ddfdfdcd0908a68326f771405987ddc280e3
1 /*
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
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.
14 * Jordan K. Hubbard
15 * 18 July 1993
17 * Miscellaneous file access utilities.
21 #include <sys/cdefs.h>
22 __FBSDID("$FreeBSD$");
24 #include "lib.h"
25 #include <err.h>
26 #include <pwd.h>
27 #include <time.h>
28 #include <sys/wait.h>
30 /* Quick check to see if a file exists */
31 Boolean
32 fexists(const char *fname)
34 struct stat dummy;
35 if (!lstat(fname, &dummy))
36 return TRUE;
37 return FALSE;
40 /* Quick check to see if something is a directory or symlink to a directory */
41 Boolean
42 isdir(const char *fname)
44 struct stat sb;
46 if (lstat(fname, &sb) != FAIL && S_ISDIR(sb.st_mode))
47 return TRUE;
48 else if (lstat(strconcat(fname, "/."), &sb) != FAIL && S_ISDIR(sb.st_mode))
49 return TRUE;
50 else
51 return FALSE;
54 /* Check to see if file is a dir or symlink to a dir, and is empty */
55 Boolean
56 isemptydir(const char *fname)
58 if (isdir(fname)) {
59 DIR *dirp;
60 struct dirent *dp;
62 dirp = opendir(fname);
63 if (!dirp)
64 return FALSE; /* no perms, leave it alone */
65 for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
66 if (strcmp(dp->d_name, ".") && strcmp(dp->d_name, "..")) {
67 closedir(dirp);
68 return FALSE;
71 (void)closedir(dirp);
72 return TRUE;
74 return FALSE;
78 * Returns TRUE if file is a regular file or symlink pointing to a regular
79 * file
81 Boolean
82 isfile(const char *fname)
84 struct stat sb;
85 if (stat(fname, &sb) != FAIL && S_ISREG(sb.st_mode))
86 return TRUE;
87 return FALSE;
91 * Check to see if file is a file or symlink pointing to a file and is empty.
92 * If nonexistent or not a file, say "it's empty", otherwise return TRUE if
93 * zero sized.
95 Boolean
96 isemptyfile(const char *fname)
98 struct stat sb;
99 if (stat(fname, &sb) != FAIL && S_ISREG(sb.st_mode)) {
100 if (sb.st_size != 0)
101 return FALSE;
103 return TRUE;
106 /* Returns TRUE if file is a symbolic link. */
107 Boolean
108 issymlink(const char *fname)
110 struct stat sb;
111 if (lstat(fname, &sb) != FAIL && S_ISLNK(sb.st_mode))
112 return TRUE;
113 return FALSE;
116 /* Returns TRUE if file is a URL specification */
117 Boolean
118 isURL(const char *fname)
121 * I'm sure there are other types of URL specifications that I could
122 * also be looking for here, but for now I'll just be happy to get ftp
123 * and http working.
125 if (!fname)
126 return FALSE;
127 while (isspace(*fname))
128 ++fname;
129 if (!strncmp(fname, "ftp://", 6) || !strncmp(fname, "http://", 7) ||
130 !strncmp(fname, "https://", 8) || !strncmp(fname, "file://", 7))
131 return TRUE;
132 return FALSE;
135 char *
136 fileFindByPath(const char *base, const char *fname)
138 static char tmp[FILENAME_MAX];
139 char *cp;
140 const char *suffixes[] = {".tbz", ".tgz", ".tar", NULL};
141 int i;
143 if (fexists(fname) && isfile(fname)) {
144 strcpy(tmp, fname);
145 return tmp;
147 if (base) {
148 strcpy(tmp, base);
150 cp = strrchr(tmp, '/');
151 if (cp) {
152 *cp = '\0'; /* chop name */
153 cp = strrchr(tmp, '/');
155 if (cp)
156 for (i = 0; suffixes[i] != NULL; i++) {
157 *(cp + 1) = '\0';
158 strcat(cp, "All/");
159 strcat(cp, fname);
160 strcat(cp, suffixes[i]);
161 if (fexists(tmp))
162 return tmp;
166 cp = getenv("PKG_PATH");
167 while (cp) {
168 char *cp2 = strsep(&cp, ":");
170 for (i = 0; suffixes[i] != NULL; i++) {
171 snprintf(tmp, FILENAME_MAX, "%s/%s%s", cp2 ? cp2 : cp, fname, suffixes[i]);
172 if (fexists(tmp) && isfile(tmp))
173 return tmp;
176 return NULL;
179 char *
180 fileGetContents(const char *fname)
182 char *contents;
183 struct stat sb;
184 int fd;
186 if (stat(fname, &sb) == FAIL) {
187 cleanup(0);
188 errx(2, "%s: can't stat '%s'", __func__, fname);
191 contents = (char *)malloc(sb.st_size + 1);
192 fd = open(fname, O_RDONLY, 0);
193 if (fd == FAIL) {
194 cleanup(0);
195 errx(2, "%s: unable to open '%s' for reading", __func__, fname);
197 if (read(fd, contents, sb.st_size) != sb.st_size) {
198 cleanup(0);
199 errx(2, "%s: short read on '%s' - did not get %lld bytes", __func__,
200 fname, (long long)sb.st_size);
202 close(fd);
203 contents[sb.st_size] = '\0';
204 return contents;
208 * Takes a filename and package name, returning (in "try") the
209 * canonical "preserve" name for it.
211 Boolean
212 make_preserve_name(char *try, int max, const char *name, const char *file)
214 int len, i;
216 if ((len = strlen(file)) == 0)
217 return FALSE;
218 else
219 i = len - 1;
220 strncpy(try, file, max);
221 if (try[i] == '/') /* Catch trailing slash early and save checking in the loop */
222 --i;
223 for (; i; i--) {
224 if (try[i] == '/') {
225 try[i + 1]= '.';
226 strncpy(&try[i + 2], &file[i + 1], max - i - 2);
227 break;
230 if (!i) {
231 try[0] = '.';
232 strncpy(try + 1, file, max - 1);
234 /* I should probably be called rude names for these inline assignments */
235 strncat(try, ".", max -= strlen(try));
236 strncat(try, name, max -= strlen(name));
237 strncat(try, ".", max--);
238 strncat(try, "backup", max -= 6);
239 return TRUE;
242 /* Write the contents of "str" to a file */
243 void
244 write_file(const char *name, const char *str)
246 FILE *fp;
247 size_t len;
249 fp = fopen(name, "w");
250 if (!fp) {
251 cleanup(0);
252 errx(2, "%s: cannot fopen '%s' for writing", __func__, name);
254 len = strlen(str);
255 if (fwrite(str, 1, len, fp) != len) {
256 cleanup(0);
257 errx(2, "%s: short fwrite on '%s', tried to write %ld bytes",
258 __func__, name, (long)len);
260 if (fclose(fp)) {
261 cleanup(0);
262 errx(2, "%s: failure to fclose '%s'", __func__, name);
266 void
267 copy_file(const char *dir, const char *fname, const char *to)
269 char cmd[FILENAME_MAX];
271 if (fname[0] == '/')
272 snprintf(cmd, FILENAME_MAX, "/bin/cp -r %s %s", fname, to);
273 else
274 snprintf(cmd, FILENAME_MAX, "/bin/cp -r %s/%s %s", dir, fname, to);
275 if (vsystem(cmd)) {
276 cleanup(0);
277 errx(2, "%s: could not perform '%s'", __func__, cmd);
281 void
282 move_file(const char *dir, const char *fname, const char *to)
284 char cmd[FILENAME_MAX];
286 if (fname[0] == '/')
287 snprintf(cmd, FILENAME_MAX, "/bin/mv %s %s", fname, to);
288 else
289 snprintf(cmd, FILENAME_MAX, "/bin/mv %s/%s %s", dir, fname, to);
290 if (vsystem(cmd)) {
291 cleanup(0);
292 errx(2, "%s: could not perform '%s'", __func__, cmd);
297 * Copy a hierarchy (possibly from dir) to the current directory, or
298 * if "to" is TRUE, from the current directory to a location someplace
299 * else.
301 * Though slower, using tar to copy preserves symlinks and everything
302 * without me having to write some big hairy routine to do it.
304 void
305 copy_hierarchy(const char *dir, const char *fname, Boolean to)
307 char cmd[FILENAME_MAX * 3];
309 if (!to) {
310 /* If absolute path, use it */
311 if (*fname == '/')
312 dir = "/";
313 snprintf(cmd, FILENAME_MAX * 3, "/usr/bin/tar cf - -C %s %s | /usr/bin/tar xpf -",
314 dir, fname);
316 else
317 snprintf(cmd, FILENAME_MAX * 3, "/usr/bin/tar cf - %s | /usr/bin/tar xpf - -C %s",
318 fname, dir);
319 #ifdef DEBUG
320 printf("Using '%s' to copy trees.\n", cmd);
321 #endif
322 if (system(cmd)) {
323 cleanup(0);
324 errx(2, "%s: could not perform '%s'", __func__, cmd);
328 /* Unpack a tar file */
330 unpack(const char *pkg, const char *flist)
332 const char *comp, *cp;
333 char suff[80];
335 comp = "";
337 * Figure out by a crude heuristic whether this or not this is probably
338 * compressed and whichever compression utility was used (gzip or bzip2).
340 if (strcmp(pkg, "-")) {
341 cp = strrchr(pkg, '.');
342 if (cp) {
343 strcpy(suff, cp + 1);
344 if (strchr(suff, 'z') || strchr(suff, 'Z')) {
345 if (strchr(suff, 'b'))
346 comp = "-j";
347 else
348 comp = "-z";
352 else
353 comp = "-j";
354 if (vsystem("/usr/bin/tar -xp %s -f '%s' %s", comp, pkg, flist ? flist : "")) {
355 warnx("tar extract of %s failed!", pkg);
356 return 1;
358 return 0;
362 * Using fmt, replace all instances of:
364 * %F With the parameter "name"
365 * %D With the parameter "dir"
366 * %B Return the directory part ("base") of %D/%F
367 * %f Return the filename part of %D/%F
369 * Does not check for overflow - caution!
372 void
373 format_cmd(char *buf, int max, const char *fmt, const char *dir, const char *name)
375 char *cp, scratch[FILENAME_MAX * 2];
376 int l;
378 while (*fmt && max > 0) {
379 if (*fmt == '%') {
380 switch (*++fmt) {
381 case 'F':
382 strncpy(buf, name, max);
383 l = strlen(name);
384 buf += l, max -= l;
385 break;
387 case 'D':
388 strncpy(buf, dir, max);
389 l = strlen(dir);
390 buf += l, max -= l;
391 break;
393 case 'B':
394 snprintf(scratch, FILENAME_MAX * 2, "%s/%s", dir, name);
395 cp = &scratch[strlen(scratch) - 1];
396 while (cp != scratch && *cp != '/')
397 --cp;
398 *cp = '\0';
399 strncpy(buf, scratch, max);
400 l = strlen(scratch);
401 buf += l, max -= l;
402 break;
404 case 'f':
405 snprintf(scratch, FILENAME_MAX * 2, "%s/%s", dir, name);
406 cp = &scratch[strlen(scratch) - 1];
407 while (cp != scratch && *(cp - 1) != '/')
408 --cp;
409 strncpy(buf, cp, max);
410 l = strlen(cp);
411 buf += l, max -= l;
412 break;
414 default:
415 *buf++ = *fmt;
416 --max;
417 break;
419 ++fmt;
421 else {
422 *buf++ = *fmt++;
423 --max;
426 *buf = '\0';