ref: 39cdb8b036fd676576d3575df6b8c49b47f786ae
dir: /llt/dirpath.c/
#ifdef PLAN9 #include <u.h> #include <libc.h> #define getcwd getwd #else #include <stdlib.h> #include <stdio.h> #include <string.h> #include <time.h> #include <assert.h> #include <errno.h> #include <limits.h> #include <sys/stat.h> #include <sys/types.h> #include <sys/time.h> #include <sys/poll.h> #include <unistd.h> #endif #include "dtypes.h" #include "dirpath.h" void get_cwd(char *buf, size_t size) { getcwd(buf, size); } int set_cwd(char *buf) { return chdir(buf); } // destructively convert path to directory part void path_to_dirname(char *path) { char *sep = strrchr(path, PATHSEP); if (sep != NULL) { *sep = '\0'; } else { path[0] = '\0'; } } #ifdef PLAN9 char *get_exename(char *buf, size_t size) { snprint(buf, size, argv0); return buf; } #elif defined(LINUX) char *get_exename(char *buf, size_t size) { char linkname[64]; /* /proc/<pid>/exe */ pid_t pid; ssize_t ret; /* Get our PID and build the name of the link in /proc */ pid = getpid(); if (snprintf(linkname, sizeof(linkname), "/proc/%i/exe", pid) < 0) return NULL; /* Now read the symbolic link */ ret = readlink(linkname, buf, size); /* In case of an error, leave the handling up to the caller */ if (ret == -1) return NULL; /* Report insufficient buffer size */ if ((size_t)ret >= size) return NULL; /* Ensure proper NUL termination */ buf[ret] = 0; return buf; } #elif defined(OPENBSD) #include <sys/param.h> #include <sys/sysctl.h> char *get_exename(char *buf, size_t size) { int mib[4]; pid_t pid; size_t len, plen; char **argv, **argv2; char *p, *path, *pathcpy, filename[PATH_MAX]; struct stat sbuf; pid = getpid(); mib[0] = CTL_KERN; mib[1] = KERN_PROC_ARGS; mib[2] = pid; mib[3] = KERN_PROC_ARGV; USED(size); buf = NULL; argv = NULL; len = 128; // Now, play The Guessing Game with sysctl(3) as to how big argv // is supposed to be. (It's loads of fun for the whole family!) while (len < SIZE_MAX / 2) { len *= 2; if ((argv2 = realloc(argv, len)) == NULL) break; argv = argv2; if (sysctl(mib, 4, argv, &len, NULL, 0) == -1) { if (errno == ENOMEM) continue; // Go back and realloc more memory. break; // Bail for some other error in sysctl(3). } // If you made it here, congrats! You guessed right! if (*argv != NULL) buf = strdup(*argv); break; } free(argv); // If no error occurred in the sysctl(3) KERN_PROC_ARGV call // above, then buf at this point contains some kind of pathname. if (buf != NULL) { if (strchr(buf, '/') == NULL) { // buf contains a `basename`-style pathname (i.e. "foo", // as opposed to "../foo" or "/usr/bin/foo"); search the // PATH for its location. (BTW the setgid(2), setuid(2) // calls are a pre-condition for the access(2) call // later.) if ( (path = getenv("PATH")) != NULL && !setgid(getegid()) && !setuid(geteuid()) ) { // The strdup(3) call below, if successful, will // allocate memory for the PATH string returned by // getenv(3) above. This is necessary because the man // page of getenv(3) says that its return value // "should be considered read-only"; however, the // strsep(3) call below is going to be destructively // modifying that value. ("Hulk smash!") if ((path = strdup(path)) != NULL) { pathcpy = path; len = strlen(buf); while ((p = strsep(&pathcpy, ":")) != NULL) { if (*p == '\0') p = "."; plen = strlen(p); // strip trailing '/' while (p[plen-1] == '/') p[--plen] = '\0'; if (plen + 1 + len < sizeof(filename)) { snprintf(filename, sizeof(filename), "%s/%s", p, buf); if ( (stat(filename, &sbuf) == 0) && S_ISREG(sbuf.st_mode) && access(filename, X_OK) == 0 ) { buf = strdup(filename); break; } } } free(path); // free the strdup(3) memory allocation. } } else buf = NULL; // call to getenv(3) or [sg]ete?[ug]id(2) failed. } if ( buf != NULL && *buf != '/' ) { // buf contains a relative pathname (e.g. "../foo"); // resolve this to an absolute pathname. if ( strlcpy(filename, buf, sizeof(filename)) >= sizeof(filename) || realpath(filename, buf) == NULL ) buf = NULL; } } return buf; } #elif defined(FREEBSD) || defined(NETBSD) #include <sys/types.h> #include <sys/sysctl.h> char *get_exename(char *buf, size_t size) { int mib[4]; mib[0] = CTL_KERN; #if defined(FREEBSD) mib[1] = KERN_PROC; mib[2] = KERN_PROC_PATHNAME; mib[3] = -1; #else mib[1] = KERN_PROC_ARGS; mib[2] = -1; mib[3] = KERN_PROC_PATHNAME; #endif sysctl(mib, 4, buf, &size, NULL, 0); return buf; } #endif