Last active
July 26, 2023 13:58
-
-
Save phlummox/c2c14b30f7185ee49ab76baf4924da9f to your computer and use it in GitHub Desktop.
"relative executor" program
This file contains hidden or 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
CFLAGS = -pedantic -Wall -Wextra -std=c11 -O2 | |
rel: rel.o | |
rel.o: | |
clean: | |
-rm *.o rel |
This file contains hidden or 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 <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <libgen.h> | |
#include <unistd.h> | |
// Variable naming: | |
// | |
// - Lengths of NUL-terminated strings are called <something>_len | |
// (and don't include the NUL in the length) | |
// - Sizes of buffers are called <something>_size | |
// (and represent the exact size of the buffer) | |
// | |
// We assume a Linux with memory overcommit enabled, and lazily don't bother to | |
// check the return value of calls to malloc(). (But we should. See | |
// <https://ewontfix.com/3/>.) | |
// Wrapper around POSIX dirname which works on a copy | |
// of `path` (since `dirname()` may try to alter its | |
// argument). | |
// | |
// `dir` should point to memory which can hold the full result | |
// of `dirname(path)`. | |
// `dir_len` should point to memory which can hold a size_t; the | |
// length of `dir` will be written to it. | |
void dirname_(char *dir, size_t *dir_len, const char *path) { | |
const size_t path_len = strlen(path); | |
char *path_cp = malloc(path_len+1); | |
strncpy(path_cp, path, path_len+1); | |
char *tmp = dirname(path_cp); | |
*dir_len = strlen(tmp); | |
strncpy(dir, tmp, (*dir_len)+1); | |
free(path_cp); | |
} | |
int main(int argc, char* argv[]) { | |
if (argc < 3) { | |
fprintf(stderr, "expected at least 2 args: <INTERPRETER> <SCRIPT> ...\n"); | |
exit(EXIT_FAILURE); | |
} | |
const char * interpreter = argv[1]; | |
const char * orig_script = argv[2]; | |
const size_t interpreter_len = strlen(interpreter); | |
// max buf needed: + 1 for a "/" char between the two, +1 more for NUL. | |
const size_t buf_size = strlen(orig_script) + 1 + interpreter_len + 1; | |
char * buf = malloc(buf_size); | |
size_t dirname_len; | |
dirname_(buf, &dirname_len, orig_script); | |
buf[dirname_len] = '/'; | |
strncpy(buf + dirname_len + 1, interpreter, interpreter_len+1); | |
// adjust argv for passing to execv: | |
// argv[0] <- buf, all others shift back one place. | |
argv[0] = buf; | |
for (int i = 1; i < argc - 1; i++) { | |
argv[i] = argv[i+1]; | |
} | |
argv[argc-1] = NULL; | |
execv(buf, argv); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
See https://www.reddit.com/r/unix/comments/152hr8c/shebangs_cant_be_used_with_relative_paths_so_i/