diff options
-rw-r--r-- | build/flags.mk | 9 | ||||
-rwxr-xr-x | configure | 6 | ||||
-rw-r--r-- | src/bfs.h | 5 | ||||
-rw-r--r-- | src/color.c | 189 | ||||
-rw-r--r-- | src/diag.h | 4 | ||||
-rw-r--r-- | src/prelude.h | 3 | ||||
-rw-r--r-- | tests/bfs/color_bsd.out | 54 | ||||
-rw-r--r-- | tests/bfs/color_bsd.sh | 2 | ||||
-rw-r--r-- | tests/bfs/color_bsd_fail.sh | 2 |
9 files changed, 180 insertions, 94 deletions
diff --git a/build/flags.mk b/build/flags.mk index 3748a8a..d6f9499 100644 --- a/build/flags.mk +++ b/build/flags.mk @@ -26,6 +26,7 @@ _ASAN := ${TRUTHY,${ASAN}} _LSAN := ${TRUTHY,${LSAN}} _MSAN := ${TRUTHY,${MSAN}} _TSAN := ${TRUTHY,${TSAN}} +_TYSAN := ${TRUTHY,${TYSAN}} _UBSAN := ${TRUTHY,${UBSAN}} _GCOV := ${TRUTHY,${GCOV}} _LINT := ${TRUTHY,${LINT}} @@ -38,21 +39,23 @@ ASAN_CFLAGS,y := -fsanitize=address LSAN_CFLAGS,y := -fsanitize=leak MSAN_CFLAGS,y := -fsanitize=memory -fsanitize-memory-track-origins TSAN_CFLAGS,y := -fsanitize=thread +TYSAN_CFLAGS,y := -fsanitize=type UBSAN_CFLAGS,y := -fsanitize=undefined _CFLAGS += ${ASAN_CFLAGS,${_ASAN}} _CFLAGS += ${LSAN_CFLAGS,${_LSAN}} _CFLAGS += ${MSAN_CFLAGS,${_MSAN}} _CFLAGS += ${TSAN_CFLAGS,${_TSAN}} +_CFLAGS += ${TYSAN_CFLAGS,${_TYSAN}} _CFLAGS += ${UBSAN_CFLAGS,${_UBSAN}} SAN_CFLAGS,y := -fno-sanitize-recover=all -INSANE := ${NOT,${_ASAN}${_LSAN}${_MSAN}${_TSAN}${_UBSAN}} +INSANE := ${NOT,${_ASAN}${_LSAN}${_MSAN}${_TSAN}${_TYSAN}${_UBSAN}} SAN := ${NOT,${INSANE}} _CFLAGS += ${SAN_CFLAGS,${SAN}} -# MSAN and TSAN both need all code to be instrumented -YESLIBS := ${NOT,${_MSAN}${_TSAN}} +# MSan, TSan, and TySan need all code to be instrumented +YESLIBS := ${NOT,${_MSAN}${_TSAN}${_TYSAN}} NOLIBS ?= ${NOT,${YESLIBS}} # gcov only intercepts fork()/exec() with -std=gnu* @@ -40,7 +40,7 @@ The default flags result in a plain debug build. Other build profiles include: --enable-release Enable optimizations, disable assertions - --enable-{asan,lsan,msan,tsan,ubsan} + --enable-{asan,lsan,msan,tsan,tysan,ubsan} Enable sanitizers --enable-gcov Enable code coverage instrumentation @@ -164,7 +164,7 @@ for arg; do --enable-*|--disable-*) case "$name" in - release|lto|asan|lsan|msan|tsan|ubsan|lint|gcov) + release|lto|asan|lsan|msan|tsan|tysan|ubsan|lint|gcov) set -- "$@" "$NAME=$yn" ;; *) @@ -197,7 +197,7 @@ for arg; do ;; # Warn about MAKE variables that have documented configure flags - RELEASE=*|LTO=*|ASAN=*|LSAN=*|MSAN=*|TSAN=*|UBSAN=*|LINT=*|GCOV=*) + RELEASE=*|LTO=*|ASAN=*|LSAN=*|MSAN=*|TSAN=*|TYSAN=*|UBSAN=*|LINT=*|GCOV=*) name=$(printf '%s' "$NAME" | tr 'A-Z_' 'a-z-') warn '"%s" is deprecated; use --enable-%s' "$arg" "$name" set -- "$@" "$arg" @@ -202,7 +202,10 @@ extern const char bfs_ldlibs[]; * Disabled on TSan due to https://github.com/google/sanitizers/issues/342. */ #ifndef BFS_USE_TARGET_CLONES -# if __has_attribute(target_clones) && (__GLIBC__ || __FreeBSD__) && !__SANITIZE_THREAD__ +# if __has_attribute(target_clones) \ + && (__GLIBC__ || __FreeBSD__) \ + && !__SANITIZE_THREAD__ \ + && !__SANITIZE_TYPE__ # define BFS_USE_TARGET_CLONES true # else # define BFS_USE_TARGET_CLONES false diff --git a/src/color.c b/src/color.c index f77877d..926cf2b 100644 --- a/src/color.c +++ b/src/color.c @@ -103,6 +103,8 @@ struct colors { struct esc_seq *pipe; struct esc_seq *socket; + struct esc_seq *dataless; + /** A mapping from color names (fi, di, ln, etc.) to struct fields. */ struct trie names; @@ -161,26 +163,32 @@ static int cat_esc(dchar **dstr, const struct esc_seq *seq) { return dstrxcat(dstr, seq->seq, seq->len); } -/** Set a named escape sequence. */ -static int set_esc(struct colors *colors, const char *name, dchar *value) { - struct esc_seq **field = get_esc(colors, name); - if (!field) { - return 0; +/** Set an escape sequence field. */ +static int set_esc_field(struct colors *colors, struct esc_seq **field, const dchar *value) { + struct esc_seq *seq = NULL; + if (value) { + seq = new_esc(colors, value, dstrlen(value)); + if (!seq) { + return -1; + } } if (*field) { free_esc(colors, *field); - *field = NULL; } + *field = seq; - if (value) { - *field = new_esc(colors, value, dstrlen(value)); - if (!*field) { - return -1; - } + return 0; +} + +/** Set a named escape sequence. */ +static int set_esc(struct colors *colors, const char *name, const dchar *value) { + struct esc_seq **field = get_esc(colors, name); + if (!field) { + return 0; } - return 0; + return set_esc_field(colors, field, value); } /** Reverse a string, to turn suffix matches into prefix matches. */ @@ -609,59 +617,101 @@ fail: /** Parse the FreeBSD $LSCOLORS format. */ static int parse_bsd_ls_colors(struct colors *colors, const char *lscolors) { - static const char *keys[] = { - "di", "ln", "so", "pi", "ex", "bd", "cd", "su", "sg", "tw", "ow" - }; - static const char *fg_codes[256] = { - ['a'] = "30", ['b'] = "31", ['c'] = "32", ['d'] = "33", - ['e'] = "34", ['f'] = "35", ['g'] = "36", ['h'] = "37", ['x'] = "39", + // 0-7: deprecated aliases for a-h + ['0'] = "30", ['1'] = "31", ['2'] = "32", ['3'] = "33", + ['4'] = "34", ['5'] = "35", ['6'] = "36", ['7'] = "37", + // a-h: first 8 ANSI foreground colors + ['a'] = "30", ['b'] = "31", ['c'] = "32", ['d'] = "33", + ['e'] = "34", ['f'] = "35", ['g'] = "36", ['h'] = "37", + // x: default foreground + ['x'] = "39", + // A-H: bold foreground colors ['A'] = "1;30", ['B'] = "1;31", ['C'] = "1;32", ['D'] = "1;33", - ['E'] = "1;34", ['F'] = "1;35", ['G'] = "1;36", ['H'] = "1;37", ['X'] = "1" + ['E'] = "1;34", ['F'] = "1;35", ['G'] = "1;36", ['H'] = "1;37", + // X: bold default foreground + ['X'] = "1;39", }; static const char *bg_codes[256] = { - ['a'] = "40", ['b'] = "41", ['c'] = "42", ['d'] = "43", - ['e'] = "44", ['f'] = "45", ['g'] = "46", ['h'] = "47", ['x'] = "49", - ['A'] = "4;100", ['B'] = "4;101", ['C'] = "4;102", ['D'] = "4;103", - ['E'] = "4;104", ['F'] = "4;105", ['G'] = "4;106", ['H'] = "4;107", ['X'] = "4;49" + // 0-7: deprecated aliases for a-h + ['0'] = "40", ['1'] = "41", ['2'] = "42", ['3'] = "43", + ['4'] = "44", ['5'] = "45", ['6'] = "46", ['7'] = "47", + // a-h: first 8 ANSI background colors + ['a'] = "40", ['b'] = "41", ['c'] = "42", ['d'] = "43", + ['e'] = "44", ['f'] = "45", ['g'] = "46", ['h'] = "47", + // x: default background + ['x'] = "49", + // A-H: background colors + underline + ['A'] = "4;40", ['B'] = "4;41", ['C'] = "4;42", ['D'] = "4;43", + ['E'] = "4;44", ['F'] = "4;45", ['G'] = "4;46", ['H'] = "4;47", + // X: default background + underline + ['X'] = "4;49", }; // Please refer to https://man.freebsd.org/cgi/man.cgi?ls(1)#ENVIRONMENT - char complete_colors[] = "exfxcxdxbxegedabagacad"; + char complete_colors[] = "exfxcxdxbxegedabagacadah"; + // For short $LSCOLORS, use the default colors for the rest size_t max = strlen(complete_colors); - size_t len = strnlen(lscolors, max + 1); - if (len == 0 || len % 2 != 0 || len > max) { - errno = EINVAL; + size_t len = strnlen(lscolors, max); + memcpy(complete_colors, lscolors, len); + + struct esc_seq **keys[] = { + &colors->directory, + &colors->link, + &colors->socket, + &colors->pipe, + &colors->executable, + &colors->blockdev, + &colors->chardev, + &colors->setuid, + &colors->setgid, + &colors->sticky_other_writable, + &colors->other_writable, + &colors->dataless, + }; + + dchar *buf = dstralloc(8); + if (!buf) { return -1; } - memcpy(complete_colors, lscolors, len); + int ret = -1; for (size_t i = 0; i < countof(keys); ++i) { - uint8_t fg = complete_colors[i * 2]; - uint8_t bg = complete_colors[(i * 2) + 1]; + uint8_t fg = complete_colors[2 * i]; + uint8_t bg = complete_colors[2 * i + 1]; const char *fg_code = fg_codes[fg]; const char *bg_code = bg_codes[bg]; - if (!fg_code || !bg_code) { - continue; + dstrshrink(buf, 0); + if (fg_code) { + if (dstrcat(&buf, fg_code) != 0) { + goto fail; + } } - - dchar *esc = dstrprintf("%s;%s", fg_code, bg_code); - if (!esc) { - return -1; + if (fg_code && bg_code) { + if (dstrcat(&buf, ";") != 0) { + goto fail; + } + } + if (bg_code) { + if (dstrcat(&buf, bg_code) != 0) { + goto fail; + } } - int ret = set_esc(colors, keys[i], esc); - dstrfree(esc); - if (ret != 0) { - return -1; + const dchar *value = dstrlen(buf) > 0 ? buf : NULL; + if (set_esc_field(colors, keys[i], value) != 0) { + goto fail; } } - return 0; + ret = 0; +fail: + dstrfree(buf); + return ret; } static bool str_isset(const char *str) { @@ -733,6 +783,8 @@ struct colors *parse_colors(void) { fail = fail || init_esc(colors, "pi", "33", &colors->pipe); fail = fail || init_esc(colors, "so", "01;35", &colors->socket); + colors->dataless = NULL; + if (fail) { goto fail; } @@ -1020,6 +1072,34 @@ static bool cpath_is_broken(const struct cpath *cpath) { } } +/** Check if we need a statbuf to colorize a file. */ +static bool must_stat(const struct colors *colors, enum bfs_type type) { + switch (type) { + case BFS_REG: + if (colors->setuid || colors->setgid || colors->executable || colors->multi_hard) { + return true; + } + +#ifdef ST_DATALESS + if (colors->dataless) { + return true; + } +#endif + + return false; + + case BFS_DIR: + if (colors->sticky_other_writable || colors->other_writable || colors->sticky) { + return true; + } + + return false; + + default: + return false; + } +} + /** Get the color for a file. */ static const struct esc_seq *file_color(const struct colors *colors, const struct cpath *cpath) { enum bfs_type type; @@ -1034,17 +1114,17 @@ static const struct esc_seq *file_color(const struct colors *colors, const struc } const struct bfs_stat *statbuf = NULL; + if (must_stat(colors, type)) { + statbuf = cpath_stat(cpath); + if (!statbuf) { + goto error; + } + } + const struct esc_seq *color = NULL; switch (type) { case BFS_REG: - if (colors->setuid || colors->setgid || colors->executable || colors->multi_hard) { - statbuf = cpath_stat(cpath); - if (!statbuf) { - goto error; - } - } - if (colors->setuid && (statbuf->mode & 04000)) { color = colors->setuid; } else if (colors->setgid && (statbuf->mode & 02000)) { @@ -1057,6 +1137,12 @@ static const struct esc_seq *file_color(const struct colors *colors, const struc color = colors->multi_hard; } +#ifdef SF_DATALESS + if (!color && colors->dataless && (statbuf->attrs & SF_DATALESS)) { + color = colors->dataless; + } +#endif + if (!color) { const char *name = cpath->path + cpath->nameoff; size_t namelen = cpath->valid - cpath->nameoff; @@ -1070,13 +1156,6 @@ static const struct esc_seq *file_color(const struct colors *colors, const struc break; case BFS_DIR: - if (colors->sticky_other_writable || colors->other_writable || colors->sticky) { - statbuf = cpath_stat(cpath); - if (!statbuf) { - goto error; - } - } - if (colors->sticky_other_writable && (statbuf->mode & 01002) == 01002) { color = colors->sticky_other_writable; } else if (colors->other_writable && (statbuf->mode & 00002)) { @@ -18,6 +18,7 @@ * * bfs: func@src/file.c:0: Message */ +// Use (format) ? "..." : "" so the format string is required #define BFS_DIAG_FORMAT_(format) \ ((format) ? "%s: %s@%s:%d: " format "%s" : "") @@ -75,7 +76,7 @@ void bfs_abortf(const char *format, ...); bfs_eabort_(__VA_ARGS__, ) #define bfs_eabort_(format, ...) \ - ((format) ? bfs_abort_(format ": %s", __VA_ARGS__ errstr(), ) : (void)0) + bfs_abort_(format "%s%s", __VA_ARGS__ (sizeof("" format) > 1 ? ": " : ""), errstr(), ) /** * Abort in debug builds; no-op in release builds. @@ -116,7 +117,6 @@ void bfs_abortf(const char *format, ...); #define bfs_everify(...) \ bfs_everify_(#__VA_ARGS__, __VA_ARGS__, "", ) - #define bfs_everify_(str, cond, format, ...) \ ((cond) ? (void)0 : bfs_everify__(format, BFS_DIAG_MSG_(format, str), __VA_ARGS__)) diff --git a/src/prelude.h b/src/prelude.h index de89a6c..3b1c4e5 100644 --- a/src/prelude.h +++ b/src/prelude.h @@ -126,5 +126,8 @@ #if __has_feature(thread_sanitizer) && !defined(__SANITIZE_THREAD__) # define __SANITIZE_THREAD__ true #endif +#if __has_feature(type_sanitizer) && !defined(__SANITIZE_TYPE__) +# define __SANITIZE_TYPE__ true +#endif #endif // BFS_PRELUDE_H diff --git a/tests/bfs/color_bsd.out b/tests/bfs/color_bsd.out index f7c577c..2ad656f 100644 --- a/tests/bfs/color_bsd.out +++ b/tests/bfs/color_bsd.out @@ -1,27 +1,27 @@ -[34;4;101m$'rainbow/\e[1m'[0m -[34;4;101m$'rainbow/\e[1m/'[0m$'\e[0m' -[34;4;101mrainbow[0m -[34;4;101mrainbow/[0m[30;41msugid[0m -[34;4;101mrainbow/[0m[30;41msuid[0m -[34;4;101mrainbow/[0m[30;42msticky_ow[0m -[34;4;101mrainbow/[0m[30;43mow[0m -[34;4;101mrainbow/[0m[30;46msgid[0m -[34;4;101mrainbow/[0m[31;49mexec.sh[0m -[34;4;101mrainbow/[0m[32;49msocket[0m -[34;4;101mrainbow/[0m[33;49mpipe[0m -[34;4;101mrainbow/[0m[35;49mbroken[0m -[34;4;101mrainbow/[0m[35;49mchardev_link[0m -[34;4;101mrainbow/[0m[35;49mlink.txt[0m -[34;4;101mrainbow/[0m[37;44msticky[0m -[34;4;101mrainbow/[0mfile.dat -[34;4;101mrainbow/[0mfile.txt -[34;4;101mrainbow/[0mlower.gz -[34;4;101mrainbow/[0mlower.tar -[34;4;101mrainbow/[0mlower.tar.gz -[34;4;101mrainbow/[0mlu.tar.GZ -[34;4;101mrainbow/[0mmh1 -[34;4;101mrainbow/[0mmh2 -[34;4;101mrainbow/[0mul.TAR.gz -[34;4;101mrainbow/[0mupper.GZ -[34;4;101mrainbow/[0mupper.TAR -[34;4;101mrainbow/[0mupper.TAR.GZ +[34;49m$'rainbow/\e[1m'[0m +[34;49m$'rainbow/\e[1m/'[0m$'\e[0m' +[34;49mrainbow[0m +[34;49mrainbow/[0m[1;33;4;49mpipe[0m +[34;49mrainbow/[0m[1;35;49mbroken[0m +[34;49mrainbow/[0m[1;35;49mchardev_link[0m +[34;49mrainbow/[0m[1;35;49mlink.txt[0m +[34;49mrainbow/[0m[1;39;41msugid[0m +[34;49mrainbow/[0m[1;39;41msuid[0m +[34;49mrainbow/[0m[30;42msticky_ow[0m +[34;49mrainbow/[0m[30;43mow[0m +[34;49mrainbow/[0m[30;46msgid[0m +[34;49mrainbow/[0m[31;49mexec.sh[0m +[34;49mrainbow/[0m[32;4;49msocket[0m +[34;49mrainbow/[0m[37;44msticky[0m +[34;49mrainbow/[0mfile.dat +[34;49mrainbow/[0mfile.txt +[34;49mrainbow/[0mlower.gz +[34;49mrainbow/[0mlower.tar +[34;49mrainbow/[0mlower.tar.gz +[34;49mrainbow/[0mlu.tar.GZ +[34;49mrainbow/[0mmh1 +[34;49mrainbow/[0mmh2 +[34;49mrainbow/[0mul.TAR.gz +[34;49mrainbow/[0mupper.GZ +[34;49mrainbow/[0mupper.TAR +[34;49mrainbow/[0mupper.TAR.GZ diff --git a/tests/bfs/color_bsd.sh b/tests/bfs/color_bsd.sh index f8a777f..2e99f0b 100644 --- a/tests/bfs/color_bsd.sh +++ b/tests/bfs/color_bsd.sh @@ -1 +1 @@ -LSCOLORS="eB" bfs_diff rainbow -color +LSCOLORS="exFxcXDXbxeGxdXb" bfs_diff rainbow -color diff --git a/tests/bfs/color_bsd_fail.sh b/tests/bfs/color_bsd_fail.sh deleted file mode 100644 index 94e1209..0000000 --- a/tests/bfs/color_bsd_fail.sh +++ /dev/null @@ -1,2 +0,0 @@ -# LSCOLORS can be at most 22 characters long (11 color pairs); this one has 24. -! LSCOLORS="exfxcxdxbxegedabagacadeB" invoke_bfs rainbow -color |