feat(L01): add BusyBox multicall console card
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static const char *applets[] = {"cat", "contains", "count", "echo", "hostname", "pid"};
|
||||
|
||||
static const char *base_name(const char *path) {
|
||||
const char *slash = strrchr(path, '/');
|
||||
return slash ? slash + 1 : path;
|
||||
}
|
||||
|
||||
static int copy_file(const char *path) {
|
||||
FILE *stream = fopen(path, "rb");
|
||||
char buffer[512]; size_t count;
|
||||
if (!stream) { perror(path); return 2; }
|
||||
while ((count = fread(buffer, 1, sizeof buffer, stream)) > 0)
|
||||
if (fwrite(buffer, 1, count, stdout) != count) { fclose(stream); return 2; }
|
||||
fclose(stream); return 0;
|
||||
}
|
||||
|
||||
static int count_file(const char *path) {
|
||||
FILE *stream = fopen(path, "rb");
|
||||
unsigned long lines = 0, bytes = 0; int ch;
|
||||
if (!stream) { perror(path); return 2; }
|
||||
while ((ch = fgetc(stream)) != EOF) { bytes++; if (ch == '\n') lines++; }
|
||||
fclose(stream); printf("%lu %lu\n", lines, bytes); return 0;
|
||||
}
|
||||
|
||||
static int contains(const char *needle, const char *path) {
|
||||
FILE *stream = fopen(path, "r"); char *line = NULL; size_t capacity = 0; int found = 0;
|
||||
if (!stream) { perror(path); return 2; }
|
||||
while (getline(&line, &capacity, stream) >= 0) if (strstr(line, needle)) { found = 1; break; }
|
||||
free(line); fclose(stream); return found ? 0 : 1;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
const char *invoked = base_name(argv[0]);
|
||||
const char *applet = invoked;
|
||||
int first = 1;
|
||||
if (!strcmp(invoked, "multicall-lab")) {
|
||||
if (argc == 2 && !strcmp(argv[1], "--list")) {
|
||||
for (size_t i = 0; i < sizeof applets / sizeof applets[0]; i++) puts(applets[i]);
|
||||
return 0;
|
||||
}
|
||||
if (argc < 2) { fputs("usage: multicall-lab APPLET [ARGS]\n", stderr); return 2; }
|
||||
applet = argv[1]; first = 2;
|
||||
}
|
||||
if (!strcmp(applet, "echo")) {
|
||||
for (int i = first; i < argc; i++) printf("%s%s", argv[i], i + 1 < argc ? " " : "\n");
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(applet, "cat") && argc == first + 1) return copy_file(argv[first]);
|
||||
if (!strcmp(applet, "count") && argc == first + 1) return count_file(argv[first]);
|
||||
if (!strcmp(applet, "contains") && argc == first + 2) return contains(argv[first], argv[first + 1]);
|
||||
if (!strcmp(applet, "hostname")) { char host[256]; if (gethostname(host, sizeof host)) return errno; puts(host); return 0; }
|
||||
if (!strcmp(applet, "pid")) { printf("%ld\n", (long)getpid()); return 0; }
|
||||
fprintf(stderr, "unknown or invalid applet: %s\n", applet); return 2;
|
||||
}
|
||||
Executable
+12
@@ -0,0 +1,12 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
root="${CARD_ROOT:?CARD_ROOT is required}"
|
||||
work="$(mktemp -d)"; trap 'rm -rf -- "$work"' EXIT
|
||||
cc -std=c11 -Wall -Wextra -Werror "$root/src/fixtures/multicall_lab.c" -o "$work/multicall-lab"
|
||||
applet_count="$($work/multicall-lab --list | wc -l)"
|
||||
[[ "$applet_count" -eq 6 ]]
|
||||
[[ "$($work/multicall-lab echo argument-dispatch)" == argument-dispatch ]]
|
||||
ln -s multicall-lab "$work/echo"
|
||||
[[ "$($work/echo symlink-dispatch)" == symlink-dispatch ]]
|
||||
if command -v busybox >/dev/null 2>&1; then backend=busybox; busybox --list | grep -qx sh; else backend=auditable-fixture; fi
|
||||
printf 'PASS task01 applets=%s argument_dispatch=1 symlink_dispatch=1 backend=%s\n' "$applet_count" "$backend"
|
||||
Executable
+12
@@ -0,0 +1,12 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
root="${CARD_ROOT:?CARD_ROOT is required}"
|
||||
work="$(mktemp -d)"; trap 'rm -rf -- "$work"' EXIT
|
||||
cc -std=c11 -Wall -Wextra -Werror "$root/src/fixtures/multicall_lab.c" -o "$work/multicall-lab"
|
||||
printf 'alpha\nbeta tool\ngamma\n' >"$work/input.txt"
|
||||
content="$($work/multicall-lab cat "$work/input.txt")"
|
||||
[[ "$content" == $'alpha\nbeta tool\ngamma' ]]
|
||||
$work/multicall-lab contains tool "$work/input.txt"
|
||||
read -r lines bytes < <($work/multicall-lab count "$work/input.txt")
|
||||
[[ "$lines" -eq 3 && "$bytes" -eq 22 ]]
|
||||
printf 'PASS task02 lines=%s bytes=%s match=tool cat_exact=1\n' "$lines" "$bytes"
|
||||
Executable
+9
@@ -0,0 +1,9 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
root="${CARD_ROOT:?CARD_ROOT is required}"
|
||||
work="$(mktemp -d)"; trap 'rm -rf -- "$work"' EXIT
|
||||
cc -std=c11 -Wall -Wextra -Werror "$root/src/fixtures/multicall_lab.c" -o "$work/multicall-lab"
|
||||
hostname_value="$($work/multicall-lab hostname)"
|
||||
pid_value="$($work/multicall-lab pid)"
|
||||
[[ -n "$hostname_value" && "$pid_value" =~ ^[1-9][0-9]*$ ]]
|
||||
printf 'PASS task03 hostname_nonempty=1 pid_positive=1 process_applet=1 host_applet=1\n'
|
||||
Reference in New Issue
Block a user