init
This commit is contained in:
commit
133d7e7c5b
5 changed files with 201 additions and 0 deletions
1
.envrc
Normal file
1
.envrc
Normal file
|
|
@ -0,0 +1 @@
|
|||
use flake
|
||||
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
.direnv
|
||||
27
flake.lock
generated
Normal file
27
flake.lock
generated
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"nodes": {
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1763464769,
|
||||
"narHash": "sha256-AJHrsT7VoeQzErpBRlLJM1SODcaayp0joAoEA35yiwM=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "6f374686605df381de8541c072038472a5ea2e2d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nixos",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
47
flake.nix
Normal file
47
flake.nix
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
{
|
||||
inputs.nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
|
||||
|
||||
outputs =
|
||||
{ self, nixpkgs }:
|
||||
let
|
||||
lib = nixpkgs.lib;
|
||||
forAllSystems =
|
||||
func: lib.genAttrs lib.systems.flakeExposed (system: func (import nixpkgs { inherit system; }));
|
||||
in
|
||||
{
|
||||
devShells = forAllSystems (pkgs: {
|
||||
default = pkgs.mkShell {
|
||||
packages = with pkgs; [
|
||||
clang-tools
|
||||
gdb
|
||||
];
|
||||
};
|
||||
});
|
||||
packages = forAllSystems (pkgs: {
|
||||
default = self.packages.${pkgs.stdenv.hostPlatform.system}.qstn;
|
||||
qstn = pkgs.stdenv.mkDerivation (finalAttrs: {
|
||||
pname = "qstn";
|
||||
version = "0.0.1";
|
||||
src = ./.;
|
||||
buildPhase = ''
|
||||
mkdir -p $out/bin
|
||||
$CC -s -O3 --std=c17 -Wall -Wpedantic -Werror main.c -o $out/bin/qstn
|
||||
'';
|
||||
meta.mainProgram = "qstn";
|
||||
});
|
||||
});
|
||||
nixosModules = {
|
||||
default = self.nixosModules.qstn;
|
||||
qstn =
|
||||
{ pkgs, lib, ... }:
|
||||
{
|
||||
boot.binfmt.registrations.qstn = {
|
||||
wrapInterpreterInShell = false;
|
||||
recognitionType = "magic";
|
||||
magicOrExtension = "#?";
|
||||
interpreter = lib.getExe self.packages.${pkgs.stdenv.hostPlatform.system}.qstn;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
125
main.c
Normal file
125
main.c
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
#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;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue