~jscott/which

ff4d25e3a9b66b436e2b5741b5491ed32467ac3a — John Scott 3 months ago b14f41f master
Add a test.
2 files changed, 91 insertions(+), 1 deletions(-)

M meson.build
A test.c
M meson.build => meson.build +4 -1
@@ 44,4 44,7 @@ if has_advisory_info
	assert(cc.has_function('posix_madvise', dependencies: [rt], prefix: '#define _POSIX_C_SOURCE 200809L'), 'posix_madvise() missing')
endif

executable('which', 'which.c', dependencies: [pthread, rt], install: true)
which = executable('which', 'which.c', dependencies: [pthread, rt], install: true)
if meson.can_run_host_binaries()
	test('find sh', executable('shtest', 'test.c', native: true), args: [which])
endif

A test.c => test.c +87 -0
@@ 0,0 1,87 @@
#define _POSIX_C_SOURCE 200809L
#include <locale.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>

/* Invoke the which executable passed on the command-line
 * to try and find the shell 'sh'. */
int main(int argc, char *argv[static argc+1]) {
	if(!setlocale(LC_ALL, "")) {
		fputs("Failed to enable default locale\n", stderr);
		abort();
	}
	if(argc < 2) {
		fputs("Missing argument\n", stderr);
		abort();
	}

	if(getenv("MESON_EXE_WRAPPER")) {
		/* We don't support this right now. */
		exit(77);
	}

	const size_t n = confstr(_CS_PATH, NULL, 0);
	char *path = malloc(n);
	if(!path) {
		perror("Failed to allocate memory");
		abort();
	}
	confstr(_CS_PATH, path, n);

	if(setenv("PATH", path, /* overwrite? */ true) == -1) {
		perror("Failed to set environment variable");
		abort();
	}
	free(path);

	char *cmd;
	FILE *cmdstream = open_memstream(&cmd, &(size_t){0});
	if(!cmdstream) {
		perror("Failed to create memory stream");
		abort();
	}
	/* If which is not at an absolute path, we'll need a leading './'
	 * for the shell to find it. */
	if(argv[1][0] != '/' && fputs("./", cmdstream) == EOF) {
		perror("Failed to print to memory stream");
		abort();
	}
	if(fputs(argv[1], cmdstream) == EOF || fputs (" sh", cmdstream) == EOF) {
		perror("Failed to print to memory stream");
		abort();
	}
	if(fclose(cmdstream) == EOF) {
		perror("Failed to close memory stream");
		abort();
	}

	FILE *pip = popen(cmd, "r");
	if(!pip) {
		perror("Failed to create pipe");
		abort();
	}
	free(cmd);

	char *line = NULL;
	const ssize_t z = getdelim(&line, &(size_t){0}, '\0', pip);
	if(ferror(pip)) {
		perror("Failed to read from which");
		abort();
	}
	if(z == -1) {
		fputs("Failed to read from which\n", stderr);
		abort();
	}
	fputs(line, stdout);
	free(line);

	int s = pclose(pip);
	if(!WIFEXITED(s) || WEXITSTATUS(s) != EXIT_SUCCESS) {
		fputs("which terminated abnormally\n", stderr);
		abort();
	}
}