diff --git a/seed/script-generator.c b/seed/script-generator.c index 4b2a01b..d4b1ad0 100644 --- a/seed/script-generator.c +++ b/seed/script-generator.c @@ -11,7 +11,6 @@ #include #include #include -#include struct Token { char *val; @@ -23,6 +22,7 @@ typedef struct Token Token; #define TYPE_IMPROVE 2 #define TYPE_DEFINE 3 #define TYPE_JUMP 4 +#define TYPE_UNINSTALL 5 struct Directive { Token *tok; @@ -212,12 +212,12 @@ Token *fill(Token *tok, Directive *directive, int type) { Token *logic(Token *tok, char **val) { /* logic = "(" - * (name | - * (name "==" value) | - * (name "!=" value) | - * (logic "||" logic) | - * (logic "&&" logic)) - * ")" + * (name | + * (name "==" value) | + * (name "!=" value) | + * (logic "||" logic) | + * (logic "&&" logic)) + * ")" */ char *lhs = tok->val; @@ -237,15 +237,15 @@ Token *logic(Token *tok, char **val) { lhs = "False"; } } else if (strcmp(tok->val, "!=") == 0) { - /* Case for inequality. */ - rhs = tok->next->val; - tok = tok->next->next; - if (strcmp(get_var(lhs), rhs) == 0) { - lhs = "False"; - } else { - lhs = "True"; - } - } else { + /* Case for inequality. */ + rhs = tok->next->val; + tok = tok->next->next; + if (strcmp(get_var(lhs), rhs) == 0) { + lhs = "False"; + } else { + lhs = "True"; + } + } else { fputs("Expected == or != after ", stderr); fputs(lhs, stderr); fputs(" in logic\n", stderr); @@ -360,7 +360,7 @@ Token *define(Token *tok, Directive *directive) { } int interpret(Directive *directive) { - /* directive = (build | improve | define | jump) predicate? */ + /* directive = (build | improve | define | jump | uninstall) predicate? */ Token *tok = directive->tok; if (strcmp(tok->val, "build:") == 0) { tok = fill(tok->next, directive, TYPE_BUILD); @@ -371,6 +371,20 @@ int interpret(Directive *directive) { } else if (strcmp(tok->val, "define:") == 0) { tok = define(tok->next, directive); return 1; /* There is no codegen for a define. */ + } else if (strcmp(tok->val, "uninstall:") == 0) { + tok = fill(tok->next, directive, TYPE_UNINSTALL); + while (tok != NULL) { + if (strcmp(tok->val, "(") == 0) { + break; + } + if (strlen(directive->arg) + strlen(tok->val) + 1 > MAX_STRING) { + fputs("somehow you have managed to have too many uninstall arguments.\n", stderr); + exit(1); + } + directive->arg = strcat(directive->arg, " "); + directive->arg = strcat(directive->arg, tok->val); + tok = tok->next; + } } if (tok != NULL) { @@ -618,6 +632,10 @@ void generate(Directive *directives) { fclose(out); out = start_script(counter, bash_build); counter += 1; + } else if (directive->type == TYPE_UNINSTALL) { + fputs("uninstall ", out); + fputs(directive->arg, out); + fputs("\n", out); } } fclose(out); diff --git a/steps/helpers.sh b/steps/helpers.sh index 5035186..1f539bc 100755 --- a/steps/helpers.sh +++ b/steps/helpers.sh @@ -79,9 +79,11 @@ _grep() { get_revision() { local pkg=$1 + local oldpwd="${PWD}" cd "/external/repo" # Get revision (n time this package has been built) revision=$( (ls -1 "${pkg}"* 2>/dev/null || true) | wc -l | sed 's/ *//g') + cd "${oldpwd}" } # Installs binary packages from an earlier run @@ -108,6 +110,64 @@ bin_preseed() { return 1 } +# Removes either an existing package or file +uninstall() { + local in_fs in_pkg symlinks + while [ $# -gt 0 ]; do + removing="$1" + case "${removing}" in + /*) + # Removing a file + echo "removing file: ${removing}." + rm -f "${removing}" + ;; + *) + echo "${removing}: uninstalling." + local oldpwd="${PWD}" + mkdir -p "/tmp/removing" + cd "/tmp/removing" + get_revision "${removing}" + local filename="/external/repo/${removing}_$((revision-1)).tar.bz2" + # Initial bzip2 built against meslibc has broken pipes + bzip2 -dc "${filename}" | tar -xf - + # reverse to have files before directories + if command -v find >/dev/null 2>&1; then + find . | sort -r > ../filelist + else + get_files . | tac > ../filelist + fi + # shellcheck disable=SC2162 + while read file; do + if [ -d "${file}" ]; then + if [ -z "$(ls -A "/${file}")" ]; then + rmdir "/${file}" + fi + else + # in some cases we might be uninstalling a file that has already been overwritten + # in this case we don't want to remove it + in_fs="$(sha256sum "${file}" 2>/dev/null | cut -d' ' -f1)" + in_pkg="$(sha256sum "/${file}" 2>/dev/null | cut -d' ' -f1)" + if [ "${in_fs}" = "${in_pkg}" ]; then + rm -f "/${file}" + fi + if [ -h "${file}" ]; then + symlinks="${symlinks} ${file}" + fi + fi + done < ../filelist + rm -f ../filelist + for link in ${symlinks}; do + if [ ! -e "/${link}" ]; then + rm -f "/${link}" + fi + done + cd "${oldpwd}" + ;; + esac + shift + done +} + # Common build steps # Build function provides a few common stages with default implementation # that can be overridden on per package basis in the build script. @@ -236,6 +296,7 @@ extract_file() { *) case "${f}" in *.tar* | *.tgz) + # shellcheck disable=SC2153 if test -e "${PREFIX}/libexec/rmt"; then # Again, we want to split out into words. # shellcheck disable=SC2086 diff --git a/steps/manifest b/steps/manifest index 2eff754..f8d171b 100644 --- a/steps/manifest +++ b/steps/manifest @@ -15,6 +15,9 @@ # eg, define: BUILD_FIWIX = KERNEL_BOOTSTRAP == True || BUILD_KERNELS == True # - jump: jump (usually) to a new kernel, executes a script with that name # eg, jump: fiwix +# - uninstall; removes a package or filenames +# eg, uninstall: perl-5.6.2 +# eg, uninstall: /usr/bin/lex /usr/bin/flex # # The following directives have special significance: # - build directives beginning with "bash" (as well as jumps) trigger the generation of