logo

utils

~/.local/bin tools and git-hooks git clone https://hacktivis.me/git/utils.git
commit: 3df989fa876c2b72bd7714574a17ef4ff706728d
parent b0af37a039de92e89f5739e56a6ff47e3dbe1468
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date:   Wed, 16 Feb 2022 03:57:38 +0100

bin/env: New

Diffstat:

Abin/env.c97+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mtest-bin/Kyuafile1+
Atest-bin/env43+++++++++++++++++++++++++++++++++++++++++++
3 files changed, 141 insertions(+), 0 deletions(-)

diff --git a/bin/env.c b/bin/env.c @@ -0,0 +1,97 @@ +// Collection of Unix tools, comparable to coreutils +// Copyright 2017-2022 Haelwenn (lanodan) Monnier <contact+utils@hacktivis.me> +// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only + +#define _POSIX_C_SOURCE 200809L +#include <stdbool.h> // bool, true, false +#include <stdio.h> // puts, perror, fprintf +#include <stdlib.h> // putenv +#include <string.h> // strchr +#include <unistd.h> // getopt, opt* + +extern char **environ; + +int export() +{ + int i = 0; + + for(; environ[i] != NULL; i++) + { + if(puts(environ[i]) < 0) + { + perror("env: puts"); + return 1; + } + } + + return 0; +} + +void +usage() +{ + fprintf(stderr, "env [-i] [key=value ...] [command [args]]\n"); +} + +int +main(int argc, char *argv[]) +{ + int c; + bool flag_i = false; + + while((c = getopt(argc, argv, ":i")) != -1) + { + switch(c) + { + case 'i': flag_i = true; break; + case ':': + fprintf(stderr, "Error: Missing operand for option: '-%c'\n", optopt); + usage(); + return 127; + case '?': + fprintf(stderr, "Error: Unrecognised option: '-%c'\n", optopt); + usage(); + return 127; + } + } + + argc -= optind; + argv += optind; + + if(flag_i) + { + char *envclear[] = {NULL}; + environ = envclear; + } + + for(; argv[0]; argv++, argc--) + { + char *sep = strchr(argv[0], '='); + if(sep == NULL) + { + break; + } + + *sep = 0; + sep++; + + if(setenv(argv[0], sep, 1)) + { + perror("env: setenv:"); + return 127; + } + } + + if(argc < 1) + { + return export(); + } + + if(execvp(argv[0], argv) < 0) + { + perror("env: execve"); + return 127; + } + + return 0; +} diff --git a/test-bin/Kyuafile b/test-bin/Kyuafile @@ -11,6 +11,7 @@ atf_test_program{name="cat", required_files=basedir.."/bin/cat"} atf_test_program{name="date", required_files=basedir.."/bin/date"} atf_test_program{name="dirname", required_files=basedir.."/bin/dirname"} atf_test_program{name="echo", required_files=basedir.."/bin/echo"} +atf_test_program{name="env", required_files=basedir.."/bin/env"} atf_test_program{name="false", required_files=basedir.."/bin/false"} atf_test_program{name="humanize", required_files=basedir.."/bin/humanize"} atf_test_program{name="pwd", required_files=basedir.."/bin/pwd"} diff --git a/test-bin/env b/test-bin/env @@ -0,0 +1,43 @@ +#!/usr/bin/env atf-sh +atf_test_case noargs +noargs_body() { + atf_check -o "inline:FOO=BAR\n" env -i FOO=BAR ../bin/env +} + +atf_test_case badarg +badarg_body() { + atf_check -s not-exit:0 -e "inline:Error: Unrecognised option: '-f'\nenv [-i] [key=value ...] [command [args]]\n" ../bin/env -f +} + +atf_test_case iflag +iflag_body() { + atf_check -o "inline:FOO=BAR\n" ../bin/env -i FOO=BAR ../bin/env + atf_check -o "inline:FOO=BAR\n" ../bin/env -i FOO=BAR + atf_check -o "not-inline:FOO=BAR\n" ../bin/env FOO=BAR ../bin/env + atf_check -o "not-inline:FOO=BAR\n" ../bin/env FOO=BAR +} + +atf_test_case devfull +devfull_body() { + atf_check -s exit:1 -e 'inline:env: puts: No space left on device\n' sh -c '../bin/env >/dev/full' +} + +atf_test_case noutil +noutil_body() { + atf_check -s exit:127 -e 'inline:env: execve: No such file or directory\n' ../bin/env /var/empty/e/no/ent +} + +atf_test_case false +false_body() { + atf_check -s exit:1 ../bin/env false +} + +atf_init_test_cases() { + cd "$(atf_get_srcdir)" || exit 1 + atf_add_test_case noargs + atf_add_test_case badarg + atf_add_test_case iflag + atf_add_test_case devfull + atf_add_test_case noutil + atf_add_test_case false +}