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 * Miscellaneous file access utilities.
21 #include <sys/cdefs.h>
22 __FBSDID("$FreeBSD$");
30 /* Quick check to see if a file exists */
32 fexists(const char *fname
)
35 if (!lstat(fname
, &dummy
))
40 /* Quick check to see if something is a directory or symlink to a directory */
42 isdir(const char *fname
)
46 if (lstat(fname
, &sb
) != FAIL
&& S_ISDIR(sb
.st_mode
))
48 else if (lstat(strconcat(fname
, "/."), &sb
) != FAIL
&& S_ISDIR(sb
.st_mode
))
54 /* Check to see if file is a dir or symlink to a dir, and is empty */
56 isemptydir(const char *fname
)
62 dirp
= opendir(fname
);
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
, "..")) {
78 * Returns TRUE if file is a regular file or symlink pointing to a regular
82 isfile(const char *fname
)
85 if (stat(fname
, &sb
) != FAIL
&& S_ISREG(sb
.st_mode
))
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
96 isemptyfile(const char *fname
)
99 if (stat(fname
, &sb
) != FAIL
&& S_ISREG(sb
.st_mode
)) {
106 /* Returns TRUE if file is a symbolic link. */
108 issymlink(const char *fname
)
111 if (lstat(fname
, &sb
) != FAIL
&& S_ISLNK(sb
.st_mode
))
116 /* Returns TRUE if file is a URL specification */
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
127 while (isspace(*fname
))
129 if (!strncmp(fname
, "ftp://", 6) || !strncmp(fname
, "http://", 7) ||
130 !strncmp(fname
, "https://", 8) || !strncmp(fname
, "file://", 7))
136 fileFindByPath(const char *base
, const char *fname
)
138 static char tmp
[FILENAME_MAX
];
140 const char *suffixes
[] = {".tbz", ".tgz", ".tar", NULL
};
143 if (fexists(fname
) && isfile(fname
)) {
150 cp
= strrchr(tmp
, '/');
152 *cp
= '\0'; /* chop name */
153 cp
= strrchr(tmp
, '/');
156 for (i
= 0; suffixes
[i
] != NULL
; i
++) {
160 strcat(cp
, suffixes
[i
]);
166 cp
= getenv("PKG_PATH");
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
))
180 fileGetContents(const char *fname
)
186 if (stat(fname
, &sb
) == FAIL
) {
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);
195 errx(2, "%s: unable to open '%s' for reading", __func__
, fname
);
197 if (read(fd
, contents
, sb
.st_size
) != sb
.st_size
) {
199 errx(2, "%s: short read on '%s' - did not get %lld bytes", __func__
,
200 fname
, (long long)sb
.st_size
);
203 contents
[sb
.st_size
] = '\0';
208 * Takes a filename and package name, returning (in "try") the
209 * canonical "preserve" name for it.
212 make_preserve_name(char *try, int max
, const char *name
, const char *file
)
216 if ((len
= strlen(file
)) == 0)
220 strncpy(try, file
, max
);
221 if (try[i
] == '/') /* Catch trailing slash early and save checking in the loop */
226 strncpy(&try[i
+ 2], &file
[i
+ 1], max
- i
- 2);
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);
242 /* Write the contents of "str" to a file */
244 write_file(const char *name
, const char *str
)
249 fp
= fopen(name
, "w");
252 errx(2, "%s: cannot fopen '%s' for writing", __func__
, name
);
255 if (fwrite(str
, 1, len
, fp
) != len
) {
257 errx(2, "%s: short fwrite on '%s', tried to write %ld bytes",
258 __func__
, name
, (long)len
);
262 errx(2, "%s: failure to fclose '%s'", __func__
, name
);
267 copy_file(const char *dir
, const char *fname
, const char *to
)
269 char cmd
[FILENAME_MAX
];
272 snprintf(cmd
, FILENAME_MAX
, "/bin/cp -r %s %s", fname
, to
);
274 snprintf(cmd
, FILENAME_MAX
, "/bin/cp -r %s/%s %s", dir
, fname
, to
);
277 errx(2, "%s: could not perform '%s'", __func__
, cmd
);
282 move_file(const char *dir
, const char *fname
, const char *to
)
284 char cmd
[FILENAME_MAX
];
287 snprintf(cmd
, FILENAME_MAX
, "/bin/mv %s %s", fname
, to
);
289 snprintf(cmd
, FILENAME_MAX
, "/bin/mv %s/%s %s", dir
, fname
, to
);
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
301 * Though slower, using tar to copy preserves symlinks and everything
302 * without me having to write some big hairy routine to do it.
305 copy_hierarchy(const char *dir
, const char *fname
, Boolean to
)
307 char cmd
[FILENAME_MAX
* 3];
310 /* If absolute path, use it */
313 snprintf(cmd
, FILENAME_MAX
* 3, "/usr/bin/tar cf - -C %s %s | /usr/bin/tar xpf -",
317 snprintf(cmd
, FILENAME_MAX
* 3, "/usr/bin/tar cf - %s | /usr/bin/tar xpf - -C %s",
320 printf("Using '%s' to copy trees.\n", cmd
);
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
;
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
, '.');
343 strcpy(suff
, cp
+ 1);
344 if (strchr(suff
, 'z') || strchr(suff
, 'Z')) {
345 if (strchr(suff
, 'b'))
354 if (vsystem("/usr/bin/tar -xp %s -f '%s' %s", comp
, pkg
, flist
? flist
: "")) {
355 warnx("tar extract of %s failed!", pkg
);
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!
373 format_cmd(char *buf
, int max
, const char *fmt
, const char *dir
, const char *name
)
375 char *cp
, scratch
[FILENAME_MAX
* 2];
378 while (*fmt
&& max
> 0) {
382 strncpy(buf
, name
, max
);
388 strncpy(buf
, dir
, max
);
394 snprintf(scratch
, FILENAME_MAX
* 2, "%s/%s", dir
, name
);
395 cp
= &scratch
[strlen(scratch
) - 1];
396 while (cp
!= scratch
&& *cp
!= '/')
399 strncpy(buf
, scratch
, max
);
405 snprintf(scratch
, FILENAME_MAX
* 2, "%s/%s", dir
, name
);
406 cp
= &scratch
[strlen(scratch
) - 1];
407 while (cp
!= scratch
&& *(cp
- 1) != '/')
409 strncpy(buf
, cp
, max
);