/* * resolve /proc/$pid/cwd */ int proc_cwd(pid_t pid, char **buf) { int ret; char *cwd, *linkcwd; struct stat s; assert(pid >= 1); assert(buf); if (asprintf(&linkcwd, "/proc/%lu/cwd", (unsigned long)pid) < 0) return -ENOMEM; ret = readlink_alloc(linkcwd, &cwd); free(linkcwd); if (ret) return ret; /* If the current working directory of a process is removed after the * process started, /proc/$pid/cwd is a dangling symbolic link and * points to "/path/to/current/working/directory (deleted)". */ if (stat(cwd, &s) && errno == ENOENT) { char *c; if ((c = strrchr(cwd, ' '))) cwd[c - cwd] = '\0'; } *buf = cwd; return 0; }
static char *readlink_slash_alloc(char *path) { char *p, *q, c; for (p = path + strlen(path); p != path && p[-1] == '/'; --p) {} if (p == path) return NULL; for (q = p; q != path && q[-1] == '/'; --q) {} for (; q != path && q[-1] != '/'; --q) {} /* Don't follow symlink if ends with /.. or /. */ if (q[0] == '.' && (q[1] == '/' || q[1] == '\0' || (q[1] == '.' && (q[2] == '/' || q[2] == '\0')))) return NULL; c = *p; *p = '\0'; q = readlink_alloc(path); *p = c; return q; }
/* Resolve symlinks until a non-symlink is found. */ static char *readlink_alloc_all(const char *path) { char *path2, *path1 = strdup(path); while ((path2 = readlink_alloc(path1))) { if (path2[0] != '/') { char *p; for (p = path1 + strlen(path1); p != path1 && p[-1] != '/'; --p) {} if (p != path1) { *p = '\0'; /* Remove basename from path1. */ p = combine_paths_dotdot_alloc(path1, path2); free(path2); path2 = p; } } free(path1); path1 = path2; } return path1; }
/* * resolve /proc/$pid/fd/$dirfd */ int proc_fd(pid_t pid, int dfd, char **buf) { int ret; char *fd, *linkdir; assert(pid >= 1); assert(dfd >= 0); assert(buf); if (asprintf(&linkdir, "/proc/%lu/fd/%d", (unsigned long)pid, dfd) < 0) return -ENOMEM; ret = readlink_alloc(linkdir, &fd); free(linkdir); if (!ret) *buf = fd; return ret; }
static char *get_up_dir_alloc(const char *dir) { char *dirup = NULL, *p; if (0 == strcmp(dir, "..") || (dirup = readlink_alloc(dir))) { free(dirup); return strdupcat(dir, "/..", ""); } dirup = strdupcat(dir, ".", ""); for (p = dirup + strlen(dirup) - 1; p != dirup && p[-1] != '/'; --p) {} if (p == dirup) { *p++ = '.'; if (0 == strcmp(dir, ".")) *p++ = '.'; *p = '\0'; } else if (dirup[0] == '/' && dirup[1] == '\0') { fdprint(2, strdupcat("xstatic: error: no parent dir for: ", dir, "\n")); exit(122); } else { p[-1] = '\0'; /* Remove basename of dirup. */ } return dirup; }