Last active
August 14, 2018 08:13
-
-
Save edsko/6e6ac1f007d35a88611410e547ca2e4c to your computer and use it in GitHub Desktop.
Utility to find and run an executable in the `dist-newstyle` directory
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <dirent.h> | |
#include <errno.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <sys/types.h> | |
#include <unistd.h> | |
int findUp(char* cwd, const char* needle, unsigned char typ); | |
void findDown(char* cwd, const char* needle, unsigned char typ, char* out); | |
DIR* opendirOrError(const char* name); | |
void append(char* x, const char* y); | |
int main(int argc, char** argv, char** env) { | |
if(argc < 2) { | |
printf("Usage: %s prog [args]\n", argv[0]); | |
exit(-1); | |
} | |
char* cwd = calloc(1024, 1); | |
strcpy(cwd, "."); | |
int foundDistNewStyle = findUp(cwd, "dist-newstyle", DT_DIR); | |
if(!foundDistNewStyle) { | |
fprintf(stderr, "Error: dist-newstyle not found\n"); | |
exit(-1); | |
} | |
char* out = calloc(1024, 1); | |
findDown(cwd, argv[1], DT_REG, out); | |
if(!out[0]) { | |
fprintf(stderr, "Error: %s not found\n", argv[1]); | |
exit(-1); | |
} | |
execve(out, argv + 1, env); | |
} | |
/** | |
* Find directory entry needle, starting at cwd and working our way up, | |
* looking for entries of type typ (DT_DIR; DT_REG; see man readdir). | |
* | |
* The result will be written to cwd, so cwd must be large enough to contain | |
* possibly large paths. | |
* | |
* Returns 1 if found, 0 otherwise. | |
*/ | |
int findUp(char* cwd, const char* needle, unsigned char typ) { | |
struct dirent* dirent = NULL; | |
int reachedRoot = 0; | |
while(!reachedRoot) { | |
DIR* dirp = opendirOrError(cwd); | |
while((dirent = readdir(dirp))) { | |
if(dirent->d_type == typ && !strcmp(dirent->d_name, needle)) { | |
append(cwd, "/"); | |
append(cwd, needle); | |
return 1; | |
} | |
// inode of the root is 2 on ext4 | |
if(!strcmp(dirent->d_name, ".") && dirent->d_ino == 2) { | |
reachedRoot = 1; | |
} | |
} | |
closedir(dirp); | |
append(cwd, "/.."); | |
} | |
// Not found :-( | |
return 0; | |
} | |
/** | |
* Like findUp, but searching _down_ a directory tree instead, recursively. | |
* | |
* We store the result in out, which must be a suitably large buffer and | |
* initialized to zero. | |
* | |
* If we find more than one match, we return an error. | |
*/ | |
void findDown(char* cwd, const char* needle, unsigned char typ, char* out) { | |
struct dirent* dirent = NULL; | |
// TODO: Right now this opens as many directories at a time as we might | |
// need to go down the directory tree. This is perhaps not ideal. | |
DIR* dirp = opendirOrError(cwd); | |
while((dirent = readdir(dirp))) { | |
if(dirent->d_type == typ && !strcmp(dirent->d_name, needle)) { | |
if(!out[0]) { | |
sprintf(out, "%s/%s", cwd, needle); | |
// We keep going, to check for other entries | |
} else { | |
fprintf(stderr, "Error: more than one match (%s, %s, possibly others)\n", out, cwd); | |
exit(-1); | |
} | |
} | |
if(dirent->d_type == DT_DIR && dirent->d_name[0] != '.') { | |
// Recursively go down the tree. We will only _append_ to cwd, never | |
// overwrite or remove stuff from it, so we can easily restore cwd | |
// simply by remembering the current length. We use recursion so | |
// we can rely on the C stack rather than having to maintain our own. | |
int oldLength = strlen(cwd); | |
append(cwd, "/"); | |
append(cwd, dirent->d_name); | |
findDown(cwd, needle, typ, out); | |
cwd[oldLength] = 0; | |
} | |
} | |
closedir(dirp); | |
} | |
/** | |
* Simple wrapper around opendir that exits on error | |
*/ | |
DIR* opendirOrError(const char* name) { | |
DIR* dirp = opendir(name); | |
if(dirp == NULL) { | |
fprintf(stderr, "Could not open %s: %s\n", name, strerror(errno)); | |
exit(-1); | |
} | |
return dirp; | |
} | |
/** | |
* Append `y` to `x`, in-place | |
*/ | |
void append(char* x, const char* y) { | |
strcpy(x + strlen(x), y); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment