From d7b1dce054139646e936da5cab11353965bc66c3 Mon Sep 17 00:00:00 2001 From: Jonas 'Sortie' Termansen Date: Mon, 13 Apr 2015 22:08:00 +0200 Subject: [PATCH] Dumb down echo(1). Options and escape sequences are fatally incompatible with historic echo that has no room for such extensions. Instead they pose risk because it is harder to use echo on unvalidated input safely and because any further extensions potentially break existing scripts. Use printf(1) instead. --- Makefile | 2 +- build-aux/build-ports.sh | 8 +- utils/echo.cpp | 186 ++------------------------------------- 3 files changed, 13 insertions(+), 183 deletions(-) diff --git a/Makefile b/Makefile index 1378a334..c59406a8 100644 --- a/Makefile +++ b/Makefile @@ -293,7 +293,7 @@ sortix.bin: kernel $(INITRD): sysroot mkdir -p `dirname $(INITRD)` - echo -n > $(INITRD).filter + printf '' > $(INITRD).filter echo "exclude /boot" >> $(INITRD).filter echo "exclude /dev" >> $(INITRD).filter echo "exclude /next" >> $(INITRD).filter diff --git a/build-aux/build-ports.sh b/build-aux/build-ports.sh index 7074f042..a1cc0b50 100755 --- a/build-aux/build-ports.sh +++ b/build-aux/build-ports.sh @@ -101,8 +101,8 @@ get_package_dependencies() {( continue fi fi - if $PRINTED_ANY; then echo -n ' '; fi - echo -n "$DEPENDENCY" + if $PRINTED_ANY; then printf ' '; fi + printf "%s" "$DEPENDENCY" PRINTED_ANY=true done if $PRINTED_ANY; then echo; fi @@ -114,9 +114,9 @@ DEPENDENCY_MAKEFILE=$(mktemp) echo "$PACKAGE: $(get_package_dependencies $PACKAGE)" echo " @echo $PACKAGE" done; - echo -n ".PHONY:" + printf ".PHONY:" for PACKAGE in $PACKAGES; do - echo -n " $PACKAGE" + printf " $PACKAGE" done; echo) > "$DEPENDENCY_MAKEFILE" diff --git a/utils/echo.cpp b/utils/echo.cpp index 4ce3854f..193d1e81 100644 --- a/utils/echo.cpp +++ b/utils/echo.cpp @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2011, 2013. + Copyright(C) Jonas 'Sortie' Termansen 2015. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free @@ -23,190 +23,20 @@ #include #include #include -#include -#include -#include - -#if !defined(VERSIONSTR) -#define VERSIONSTR "unknown version" -#endif - -static void help(FILE* fp, const char* argv0) -{ - fprintf(fp, "Usage: %s [SHORT-OPTION]... [STRING]...\n", argv0); - fprintf(fp, " or: %s [LONG-OPTION]\n", argv0); - fprintf(fp, "Echo the STRING(s) to standard output.\n"); - fprintf(fp, "\n"); - fprintf(fp, " -n do not output the trailing newline\n"); - fprintf(fp, " -e enable interpretation of backslash escapes\n"); - fprintf(fp, " -E disable interpretation of backslash escapes (default)\n"); - fprintf(fp, " --help display this help and exit\n"); - fprintf(fp, " --version output version information and exit\n"); - fprintf(fp, "\n"); - fprintf(fp, "If -e is in effect, the following sequences are recognized:\n"); - fprintf(fp, "\n"); - fprintf(fp, " \\\\ backslash\n"); - fprintf(fp, " \\a alert (BEL)\n"); - fprintf(fp, " \\b backspace\n"); - fprintf(fp, " \\c produce no further output\n"); - fprintf(fp, " \\e escape\n"); - fprintf(fp, " \\f form feed\n"); - fprintf(fp, " \\n new line\n"); - fprintf(fp, " \\r carriage return\n"); - fprintf(fp, " \\t horizontal tab\n"); - fprintf(fp, " \\v vertical tab\n"); - fprintf(fp, " \\0NNN byte with octal value NNN (1 to 3 digits)\n"); - fprintf(fp, " \\xHH byte with hexadecimal value HH (1 to 2 digits)\n"); - fprintf(fp, "\n"); -} - -static void version(FILE* fp, const char* argv0) -{ - fprintf(fp, "%s (Sortix) %s\n", argv0, VERSIONSTR); - fprintf(fp, "License GPLv3+: GNU GPL version 3 or later .\n"); - fprintf(fp, "This is free software: you are free to change and redistribute it.\n"); - fprintf(fp, "There is NO WARRANTY, to the extent permitted by law.\n"); -} - -static bool is_allowed_short_argument(const char* argument) -{ - if ( argument[0] != '-' ) - return false; - if ( !argument[1] ) - return false; - for ( size_t i = 1; argument[i]; i++ ) - { - switch ( argument[i] ) - { - case 'e': break; - case 'E': break; - case 'n': break; - default: return false; - } - } - return true; -} int main(int argc, char* argv[]) { - bool newline = true; - bool escape_sequences = false; - - if ( 2 == argc && !strcmp(argv[1], "--help") ) - help(stdout, argv[0]), exit(0); - if ( 2 == argc && !strcmp(argv[1], "--version") ) - version(stdout, argv[0]), exit(0); - for ( int i = 1; i < argc; i++ ) { - const char* arg = argv[i]; - if ( !is_allowed_short_argument(arg) ) - break; - argv[i] = NULL; - for ( size_t n = 1; arg[n]; n++ ) - { - switch ( arg[n] ) - { - case 'e': escape_sequences = true; break; - case 'E': escape_sequences = false; break; - case 'n': newline = false; break; - default: break; - } - } + if ( i != 1 ) + putchar(' '); + fputs(argv[i], stdout); } - - const char* prefix = ""; - for ( int i = 1; i < argc; i++ ) + putchar('\n'); + if ( ferror(stdout) || fflush(stdout) == EOF ) { - const char* arg = argv[i]; - if ( !arg ) - continue; - if ( !escape_sequences ) - { - if ( printf("%s%s", prefix, arg) < 0 ) - error(1, errno, ""); - } - else - { - if ( printf("%s", prefix) < 0 ) - error(1, errno, ""); - bool escaped = false; - for ( size_t i = 0; arg[i]; i++ ) - { - char c = arg[i]; - if ( escaped && (escaped = false, true) ) - { - if ( c == '0' && (i++, true) ) - { - int value = 0; - if ( '0' <= arg[i] && arg[i] <= '7' ) - value = value * 8 + arg[i] - '0', i++; - if ( '0' <= arg[i] && arg[i] <= '7' ) - value = value * 8 + arg[i] - '0', i++; - if ( '0' <= arg[i] && arg[i] <= '7' ) - value = value * 8 + arg[i] - '0', i++; - if ( 255 < value ) - value &= 255; - if ( putchar(value) == EOF ) - error(1, errno, ""); - i--; - continue; - } - if ( c == 'x' && (i++, true) ) - { - int value = 0; - if ( '0' <= arg[i] && arg[i] <= '7' ) - value = value * 16 + arg[i] - '0', i++; - else if ( 'a' <= arg[i] && arg[i] <= 'f' ) - value = value * 16 + arg[i] - 'a' + 10, i++; - else if ( 'A' <= arg[i] && arg[i] <= 'F' ) - value = value * 16 + arg[i] - 'A' + 10, i++; - if ( '0' <= arg[i] && arg[i] <= '7' ) - value = value * 16 + arg[i] - '0', i++; - else if ( 'a' <= arg[i] && arg[i] <= 'f' ) - value = value * 16 + arg[i] - 'a' + 10, i++; - else if ( 'A' <= arg[i] && arg[i] <= 'F' ) - value = value * 16 + arg[i] - 'A' + 10, i++; - if ( putchar(value) == EOF ) - error(1, errno, ""); - i--; - continue; - } - switch ( c ) - { - case '\\': c = '\\'; break; - case 'a': c = '\a'; break; - case 'b': c = '\b'; break; - case 'c': goto no_futher_output; - case 'e': c = '\e'; break; - case 'f': c = '\f'; break; - case 'n': c = '\n'; break; - case 'r': c = '\r'; break; - case 't': c = '\t'; break; - case 'v': c = '\v'; break; - default: break; - } - } - else if ( c == '\\' ) - { - escaped = true; - continue; - } - if ( putchar((unsigned char) c) == EOF ) - error(1, errno, ""); - } - if ( escaped && putchar('\\') == EOF ) - error(1, errno, ""); - } - prefix = " "; + error(1, errno, ""); + return 1; } - - if ( newline && printf("\n") < 0 ) - error(1, errno, ""); - -no_futher_output: - if ( fflush(stdout) != 0 || fsync(1) != 0 ) - error(1, errno, ""); - return 0; }