Resolve a symlink step by step, printing each link in the chain
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <sys/stat.h> | |
#include <unistd.h> | |
static char *getlink(const char *); | |
static void panic(const char *); | |
int | |
main(int argc, char **argv) | |
{ | |
if (getopt(argc, argv, "") != -1 || optind + 1 != argc) { | |
fputs("usage: lsln [file]\n", stderr); | |
exit(2); | |
} | |
const char *name = argv[optind]; | |
for (char *link, *path = getlink(name); path; link = getlink(path), free(path), path = link) { | |
puts(path); | |
} | |
} | |
char * | |
getlink(const char *path) | |
{ | |
struct stat st; | |
if (lstat(path, &st) == -1) | |
panic(path); | |
if (!S_ISLNK(st.st_mode)) | |
return NULL; | |
size_t size = st.st_size + 1; | |
const char *ptr = strrchr(path, '/'); | |
size_t off = ptr ? ptr + 1 - path : 0; | |
char *buf = malloc(size + off); | |
if (!buf) | |
panic(path); | |
ssize_t len = readlink(path, buf, size); | |
if (len == -1) | |
panic(path); | |
if (len == size) | |
return NULL; | |
buf[len++] = '\0'; | |
if (buf[0] != '/' && off != 0) { | |
memmove(buf + off, buf, len); | |
memcpy(buf, path, off); | |
} | |
return buf; | |
} | |
void | |
panic(const char *mesg) | |
{ | |
perror(mesg); | |
exit(1); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment