125 lines
3 KiB
C
125 lines
3 KiB
C
#define _DEFAULT_SOURCE
|
|
#include <dirent.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#define exit_with(f) \
|
|
exit_code = f; \
|
|
goto cleanup;
|
|
|
|
#define throw_on(f, e, c) \
|
|
if (f == e) { \
|
|
exit_with(c); \
|
|
}
|
|
|
|
#define free_if_used(f) \
|
|
if (f != NULL) { \
|
|
free(f); \
|
|
}
|
|
|
|
int main(int argc, char *argv[]) {
|
|
|
|
int exit_code = 0;
|
|
if (argc < 2) {
|
|
exit(EINVAL);
|
|
}
|
|
|
|
// open file
|
|
char *script_path = argv[1];
|
|
FILE *script = fopen(script_path, "r");
|
|
if (script == NULL) {
|
|
exit_with(errno);
|
|
}
|
|
|
|
// init variables
|
|
char found_path [PATH_MAX+1];
|
|
int nargc = 0;
|
|
char *args [128];
|
|
|
|
// read magic bytes
|
|
size_t read = 0;
|
|
char *line = NULL;
|
|
read = getline(&line, &read, script);
|
|
if (read == -1) {
|
|
exit_with(errno);
|
|
}
|
|
|
|
// close file
|
|
throw_on(fclose(script), EOF, EIO);
|
|
|
|
if (strncmp(line, "#?", 2) != 0) {
|
|
exit_with(ENOEXEC);
|
|
}
|
|
|
|
// read argv[0]
|
|
char *token = strtok(&line[2], " ");
|
|
throw_on(token, NULL, EINVAL);
|
|
|
|
args[nargc] = malloc(sizeof(char) * strlen(token));
|
|
// avoid copying the magic bytes and newline
|
|
char* p = mempcpy(args[nargc], token, strlen(token) - 1);
|
|
*p = '\0';
|
|
token = strtok(NULL, " ");
|
|
++nargc;
|
|
|
|
// collect rest of args
|
|
while (token != NULL && nargc < 127) {
|
|
args[nargc] = malloc(sizeof(char) * (strlen(token) + 1));
|
|
strcpy(args[nargc++], token);
|
|
token = strtok(NULL, " ");
|
|
}
|
|
args[nargc] = script_path;
|
|
|
|
|
|
// search for path env var
|
|
char *path_env = getenv("PATH");
|
|
if (path_env == NULL) {
|
|
exit(EINVAL);
|
|
}
|
|
|
|
// split it by colon
|
|
token = strtok(path_env, ":");
|
|
// search each member of PATH for executable with name
|
|
struct dirent *entity;
|
|
DIR *dir;
|
|
char rpath [PATH_MAX+1];
|
|
while (token != NULL) {
|
|
char* __attribute__((unused)) _ = realpath(token, rpath);
|
|
dir = opendir(token);
|
|
if (dir != NULL) {
|
|
while ((entity = readdir(dir)) != NULL) {
|
|
if (entity->d_type == DT_REG && strcmp(args[0], entity->d_name) == 0) {
|
|
throw_on(closedir(dir), -1, EIO);
|
|
int len = strlen(token) + strlen(args[0]) + 2;
|
|
snprintf(found_path, len, "%s/%s", token, args[0]);
|
|
goto end_loop;
|
|
}
|
|
}
|
|
throw_on(closedir(dir), -1, EIO);
|
|
}
|
|
token = strtok(NULL, ":");
|
|
}
|
|
|
|
end_loop:
|
|
if (strlen(found_path) == 0) {
|
|
exit_with(ENOENT);
|
|
}
|
|
|
|
cleanup:
|
|
free_if_used(line);
|
|
|
|
if (exit_code == 0) {
|
|
if (execv(found_path, args) == -1) {
|
|
exit(errno);
|
|
}
|
|
}
|
|
for (int n = 0; n < nargc; ++n) {
|
|
free_if_used(args[nargc]);
|
|
}
|
|
|
|
return exit_code;
|
|
}
|