Skip to content

Instantly share code, notes, and snippets.

@phlummox
Last active July 26, 2023 13:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save phlummox/c2c14b30f7185ee49ab76baf4924da9f to your computer and use it in GitHub Desktop.
Save phlummox/c2c14b30f7185ee49ab76baf4924da9f to your computer and use it in GitHub Desktop.
"relative executor" program
CFLAGS = -pedantic -Wall -Wextra -std=c11 -O2
rel: rel.o
rel.o:
clean:
-rm *.o rel
#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);
}
@phlummox
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment