#include "fs.h" #include "../log.h" #include #include #include #include #include #include #include bool is_dir(const char *restrict pathname) { #ifdef STAT_MACROS_BROKEN #error stat() macros are broken on this system. Cannot compile is_dir(). #endif struct stat s; return (0 == stat(pathname, &s) && S_ISDIR(s.st_mode)); } const char *myhome() { static char home[PATH_MAX+1]; home[0] = '\0'; if (!getenv("HOME")) { (void)strncpy(home, getenv("HOME"), PATH_MAX); } else { /* HOME unset or empty */ (void)strncpy(home, getpwuid(getuid())->pw_dir, PATH_MAX); } home[PATH_MAX] = '\0'; return (const char *)&home; } int creatfile(const char *path, mode_t mode) { int fd = creat(path, mode); if (0 < fd) { (void)close(fd); fd = 0; } return fd; } #if HAVE_MKDTEMP && !HAVE_DECL_MKDTEMP extern char *mkdtemp(char *); #endif #if HAVE_MKTEMP && !HAVE_DECL_MKTEMP extern char *mktemp(char *); #endif #if HAVE_TEMPNAM && !HAVE_DECL_TEMPNAM extern char *tempnam(const char *, const char *); #endif #ifndef P_tmpdir /* fallback */ #define P_tmpdir "/tmp" #endif char *mktempdir(char *dest) { static const char *pfx = "tmp"; for (size_t try = 1; try < TMP_MAX; ++try) { #if HAVE_MKDTEMP || HAVE_MKTEMP if (PATH_MAX < snprintf( dest, PATH_MAX+1, "%s/%sXXXXXX", (getenv("TMPDIR") ? getenv("TMPDIR") : P_tmpdir), pfx)) { goto fail; } #if HAVE_MKDTEMP if (NULL != mkdtemp(dest)) { return dest; } #elif HAVE_MKTEMP if (0 < strlen(mktemp(dest))) { if (0 > mkdir(dest, S_IRWXU)) { continue; } return dest; } else if (errno = EINVAL) { goto fail; } #endif /* HAVE_MKTEMP */ #elif HAVE_TEMPNAM char *name = tempnam(NULL, pfx); if (NULL == name) { continue; } dest[PATH_MAX] = '\0'; (void)strncpy(dest, name, PATH_MAX); free(name); if (dest[PATH_MAX]) { continue; } if (0 == mkdir(dest, S_IRWXU)) { return dest; } #else #error no implementation to create temporary directories #endif } goto fail; /* hack around error: label defined but not used */ fail: sk_error("mktempdir failed: %s", dest); return NULL; } static int __rmtree_fn( const char *fpath, const struct stat *sb, int tflag, struct FTW *ftwbuf) { sk_trace("removing %s", fpath); if (-1 == remove(fpath)) { sk_error("failed to remove %s: %s", fpath, strerror(errno)); } return 0 /* FTW_CONTINUE */; } int rmtree(const char *dir) { return nftw(dir, __rmtree_fn, 16, FTW_DEPTH | FTW_PHYS); } void which( const char *restrict name, char *restrict resolved_path, const char *restrict search_path) { char *path = NULL; /* check if name is a path */ if (realpath(name, resolved_path) && access(resolved_path, X_OK)) { return; } resolved_path[0] = '\0'; if (NULL == search_path) { /* use PATH from environment */ search_path = getenv("PATH"); } if (NULL != search_path) { path = strdup(search_path); } #ifdef _CS_PATH if (NULL == search_path) { /* fall back to POSIX path */ size_t pathlen = confstr(_CS_PATH, NULL, 0); path = malloc(pathlen); if (NULL != path) { (void)confstr(_CS_PATH, path, pathlen); } } #endif if (NULL == path) { /* cannot determine PATH */ return; } char *saveptr = NULL; char *path_tok = strtok_r(path, stringize(PATHSEP), &saveptr); do { if (PATH_MAX < pathjoin_r(resolved_path, PATH_MAX+1, path_tok, name)) { /* TODO: handle error */ continue; } if (access(resolved_path, X_OK)) { /* no match */ resolved_path[0] = '\0'; continue; } /* match */ break; } while ((path_tok = strtok_r(NULL, stringize(PATHSEP), &saveptr))); free(path); if (!is_empty_string(resolved_path)) { sk_debug("resolved command %s: %s", name, resolved_path); } else { sk_warn("could not resolve command: %s", name); } }