logo

bootstrap-initrd

Linux initrd generator to bootstrap a POSIX-ish system from a reasonably small binary seed git clone https://hacktivis.me/git/make-initrd.git
commit: 68fe03e68b424061a48b68214298bc4c292a3b37
parent 2dc9672700aba34c3c6bb3b4f97c89ccc5071e80
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date:   Sun, 28 Apr 2024 11:47:23 +0200

Replace hacky sed-based grep with better grep-stub

With said grep stub being complete enough for bmake configure script.

Diffstat:

Agrep-stub.c271+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Minit.sh37+++----------------------------------
Mmake-initrd.sh2+-
3 files changed, 275 insertions(+), 35 deletions(-)

diff --git a/grep-stub.c b/grep-stub.c @@ -0,0 +1,271 @@ +// utils-std: Collection of commonly available Unix tools +// SPDX-FileCopyrightText: 2017 Haelwenn (lanodan) Monnier <contact+utils@hacktivis.me> +// SPDX-License-Identifier: MPL-2.0 + +#define _POSIX_C_SOURCE 200809L + +#include <assert.h> +#include <errno.h> +#include <regex.h> +#include <stdbool.h> +#include <stdio.h> // getline +#include <stdlib.h> // free +#include <string.h> // strstr, strerror +#include <unistd.h> // getopt + +static char *argv0 = "grep"; + +struct char_list +{ + char *data; + struct char_list *next; +}; + +struct char_list *patterns; +struct char_list *files; + +size_t patterns_r_len = 0; +regex_t *patterns_r = NULL; + +bool fixed_str = false, invert = false, count_only = false; + +static int +do_grep(FILE *stream, char *filename) +{ + char *line = NULL; + size_t len = 0; + + int count = 0; + + while(getline(&line, &len, stream) != -1) + { + bool found = false; + if(fixed_str) + { + for(struct char_list *pattern = patterns; pattern != NULL; pattern = pattern->next) + { + if(strstr(line, pattern->data) != NULL) + { + found = true; + break; + } + } + } + else + { + assert(patterns_r != NULL); + assert(patterns_r_len != 0); + for(size_t i = 0; i < patterns_r_len; i++) + { + if(regexec(&patterns_r[i], line, 0, 0, 0) == 0) + { + found = true; + break; + } + } + } + + if(found != invert) + { + count++; + if(!count_only) printf("%s", line); + } + } + + if(count_only) printf("%d\n", count); + + free(line); + + if(ferror(stream)) + { + fprintf(stderr, "%s: Error while reading '%s': %s\n", argv0, filename, strerror(errno)); + return -1; + } + + return 0; +} + +static void +usage() +{ + fprintf(stderr, + "Usage: %s [-EFcilnqsvx] [-f patterns_file... | -e pattern... | pattern] [file...]\n", + argv0); +} + +int +main(int argc, char *argv[]) +{ + argv0 = argv[0]; + bool opt_l = false, nl = false, quiet = false; + int regcomp_flags = REG_NOSUB; + + struct char_list *patterns_last = NULL; + struct char_list *files_last = NULL; + + size_t patterns_len = 0; + + switch(argv0[0]) + { + case 'e': + regcomp_flags |= REG_EXTENDED; + break; + case 'f': + fixed_str = true; + break; + } + + int c = -1; + while((c = getopt(argc, argv, ":EFce:f:ilnqsvx")) != -1) + { + switch(c) + { + case 'E': + regcomp_flags |= REG_EXTENDED; + break; + case 'F': + fixed_str = true; + break; + case 'c': + count_only = true; + break; + case 'e': + if(patterns_last == NULL) + { + patterns = &(struct char_list){ + .data = optarg, + .next = NULL, + }; + patterns_last = patterns; + patterns_len++; + } + else + { + patterns->next = &(struct char_list){ + .data = optarg, + .next = NULL, + }; + patterns_last = patterns->next; + patterns_len++; + } + break; + case 'f': + if(files_last == NULL) + { + files = &(struct char_list){ + .data = optarg, + .next = NULL, + }; + files_last = files; + } + else + { + files->next = &(struct char_list){ + .data = optarg, + .next = NULL, + }; + files_last = files->next; + } + break; + case 'i': + regcomp_flags |= REG_ICASE; + break; + case 'l': + // (standard input) + opt_l = true; + break; + case 'n': + nl = true; + break; + case 'q': + quiet = true; + break; + case 's': + //no_warn = true; + break; + case 'v': + invert = true; + break; + case 'x': + //whole_line = true; + break; + } + } + + argc -= optind; + argv += optind; + + if(patterns_last == NULL && files_last == NULL) + { + if(argc == 0) + { + fprintf(stderr, "%s: No pattern given\n", argv0); + usage(); + return 1; + } + + patterns = &(struct char_list){ + .data = argv[0], + .next = NULL, + }; + patterns_last = patterns; + patterns_len++; + + argc -= 1; + argv += 1; + } + + int err = 0; + + if(!fixed_str) + { + patterns_r = calloc(patterns_len, sizeof(regex_t)); + if(patterns_r == NULL) + { + fprintf(stderr, "%s: Failed allocating memory for patterns: %s\n", argv0, strerror(errno)); + return 1; + } + + for(struct char_list *pattern = patterns; pattern != NULL; pattern = pattern->next) + { + int ret = regcomp(&patterns_r[patterns_r_len], pattern->data, regcomp_flags); + if(ret != 0) + { + char errbuf[100] = ""; + regerror(ret, &patterns_r[patterns_r_len], errbuf, sizeof(errbuf)); + fprintf(stderr, "%s: Error compiling regex /%s/: %s\n", pattern->data, errbuf, argv0); + + err = 1; + goto cleanup; + } + + patterns_r_len++; + } + } + + if(argc == 0) + { + if(do_grep(stdin, "(standard input)") < 0) return 1; + goto cleanup; + } + + for(int i = 0; i < argc; i++) + { + FILE *stream = fopen(argv[i], "r"); + if(stream == NULL) + { + fprintf(stderr, "%s: Failed opening '%s' for reading: %s\n", argv0, argv[i], strerror(errno)); + err = 1; + goto cleanup; + } + + if(do_grep(stream, argv[i]) < 0) return 1; + } + +cleanup: + for(size_t i = 0; i < patterns_r_len; i++) + { + regfree(&patterns_r[i]); + } + return err; +} diff --git a/init.sh b/init.sh @@ -23,10 +23,12 @@ build_awk() { } build_stubs() { - for i in ls mv + for i in ls mv grep do $CC $CFLAGS -o "/bin/$i" "/${i}-stub.c" || die "Failed compiling $i stub" done + ln -s grep /bin/egrep || die + ln -s grep /bin/fgrep || die } build_bmake() { @@ -77,39 +79,6 @@ EOF chmod +x /bin/hostname -cat >/bin/grep <<'EOF' -#!/bin/sh -set -e -while [ "$1" = "-*" ] -do - args="$args $1" - shift -done - -re="$1" -shift - -exec sed $args -n -e "/${re}/p" "$@" -EOF - -chmod +x /bin/grep - -cat >/bin/egrep <<'EOF' -#!/bin/sh -set -e -exec grep -E "$@" -EOF - -chmod +x /bin/egrep - -cat >/bin/fgrep <<'EOF' -#!/bin/sh -set -e -exec grep -F "$@" -EOF - -chmod +x /bin/fgrep - build_bmake cd / diff --git a/make-initrd.sh b/make-initrd.sh @@ -68,7 +68,7 @@ cp "${WORKDIR}/init.c" ./init || die "copying init" sed -i '1i#!/bin/tcc -run' ./init || die "failed adding tcc shebang to init" chmod 755 init || die "init chmod" -for i in init.sh ls-stub.c mv-stub.c +for i in init.sh ls-stub.c mv-stub.c grep-stub.c do cp -p "${WORKDIR}/$i" ./ || die "failed copying $i" done