From 9ef565a185e6438e272135b5955fd6e12cc1b111 Mon Sep 17 00:00:00 2001 From: Ethan Coe-Renner Date: Mon, 12 Dec 2022 15:30:51 -0800 Subject: [PATCH] Add color output to zfs diff. This adds support to color zfs diff (in the style of git diff) conditional on the ZFS_COLOR environment variable. Signed-off-by: Ethan Coe-Renner --- include/libzutil.h | 6 ++++-- lib/libzfs/libzfs_diff.c | 40 ++++++++++++++++++++++++++++++++++++++++ lib/libzfs/libzfs_util.c | 16 ++++++++++------ man/man8/zfs.8 | 6 ++++++ 4 files changed, 60 insertions(+), 8 deletions(-) diff --git a/include/libzutil.h b/include/libzutil.h index 6b9facdf9c..f63a1fa8c8 100644 --- a/include/libzutil.h +++ b/include/libzutil.h @@ -151,13 +151,15 @@ int zfs_ioctl_fd(int fd, unsigned long request, struct zfs_cmd *zc); * List of colors to use */ #define ANSI_RED "\033[0;31m" +#define ANSI_GREEN "\033[0;32m" #define ANSI_YELLOW "\033[0;33m" +#define ANSI_BLUE "\033[0;34m" #define ANSI_RESET "\033[0m" #define ANSI_BOLD "\033[1m" -void color_start(char *color); +void color_start(const char *color); void color_end(void); -int printf_color(char *color, char *format, ...); +int printf_color(const char *color, char *format, ...); /* * These functions are used by the ZFS libraries and cmd/zpool code, but are diff --git a/lib/libzfs/libzfs_diff.c b/lib/libzfs/libzfs_diff.c index 8884ac536a..b9698bb22b 100644 --- a/lib/libzfs/libzfs_diff.c +++ b/lib/libzfs/libzfs_diff.c @@ -45,6 +45,7 @@ #include #include #include +#include #include "libzfs_impl.h" #define ZDIFF_SNAPDIR "/.zfs/snapshot/" @@ -55,6 +56,10 @@ #define ZDIFF_REMOVED '-' #define ZDIFF_RENAMED "R" +#define ZDIFF_ADDED_COLOR ANSI_GREEN +#define ZDIFF_MODIFIED_COLOR ANSI_YELLOW +#define ZDIFF_REMOVED_COLOR ANSI_RED +#define ZDIFF_RENAMED_COLOR ANSI_BLUE /* * Given a {dsname, object id}, get the object path @@ -129,6 +134,25 @@ stream_bytes(FILE *fp, const char *string) } } +/* + * Takes the type of change (like `print_file`), outputs the appropriate color + */ +static const char * +type_to_color(char type) +{ + if (type == '+') + return (ZDIFF_ADDED_COLOR); + else if (type == '-') + return (ZDIFF_REMOVED_COLOR); + else if (type == 'M') + return (ZDIFF_MODIFIED_COLOR); + else if (type == 'R') + return (ZDIFF_RENAMED_COLOR); + else + return (NULL); +} + + static char get_what(mode_t what) { @@ -176,6 +200,8 @@ static void print_rename(FILE *fp, differ_info_t *di, const char *old, const char *new, zfs_stat_t *isb) { + if (isatty(fileno(fp))) + color_start(ZDIFF_RENAMED_COLOR); if (di->timestamped) (void) fprintf(fp, "%10lld.%09lld\t", (longlong_t)isb->zs_ctime[0], @@ -187,12 +213,18 @@ print_rename(FILE *fp, differ_info_t *di, const char *old, const char *new, (void) fputs(di->scripted ? "\t" : " -> ", fp); print_cmn(fp, di, new); (void) fputc('\n', fp); + + if (isatty(fileno(fp))) + color_end(); } static void print_link_change(FILE *fp, differ_info_t *di, int delta, const char *file, zfs_stat_t *isb) { + if (isatty(fileno(fp))) + color_start(ZDIFF_MODIFIED_COLOR); + if (di->timestamped) (void) fprintf(fp, "%10lld.%09lld\t", (longlong_t)isb->zs_ctime[0], @@ -202,12 +234,17 @@ print_link_change(FILE *fp, differ_info_t *di, int delta, const char *file, (void) fprintf(fp, "%c\t", get_what(isb->zs_mode)); print_cmn(fp, di, file); (void) fprintf(fp, "\t(%+d)\n", delta); + if (isatty(fileno(fp))) + color_end(); } static void print_file(FILE *fp, differ_info_t *di, char type, const char *file, zfs_stat_t *isb) { + if (isatty(fileno(fp))) + color_start(type_to_color(type)); + if (di->timestamped) (void) fprintf(fp, "%10lld.%09lld\t", (longlong_t)isb->zs_ctime[0], @@ -217,6 +254,9 @@ print_file(FILE *fp, differ_info_t *di, char type, const char *file, (void) fprintf(fp, "%c\t", get_what(isb->zs_mode)); print_cmn(fp, di, file); (void) fputc('\n', fp); + + if (isatty(fileno(fp))) + color_end(); } static int diff --git a/lib/libzfs/libzfs_util.c b/lib/libzfs/libzfs_util.c index 3adb785dda..8eb7582ba0 100644 --- a/lib/libzfs/libzfs_util.c +++ b/lib/libzfs/libzfs_util.c @@ -2082,22 +2082,26 @@ use_color(void) * color_end(); */ void -color_start(char *color) +color_start(const char *color) { - if (use_color()) - printf("%s", color); + if (use_color()) { + fputs(color, stdout); + fflush(stdout); + } } void color_end(void) { - if (use_color()) - printf(ANSI_RESET); + if (use_color()) { + fputs(ANSI_RESET, stdout); + fflush(stdout); + } } /* printf() with a color. If color is NULL, then do a normal printf. */ int -printf_color(char *color, char *format, ...) +printf_color(const char *color, char *format, ...) { va_list aptr; int rc; diff --git a/man/man8/zfs.8 b/man/man8/zfs.8 index a5c9441699..2fc2f3166a 100644 --- a/man/man8/zfs.8 +++ b/man/man8/zfs.8 @@ -704,6 +704,12 @@ command will be undone if the share is ever unshared (like via a reboot). .El . .Sh ENVIRONMENT VARIABLES +.Bl -tag -width "ZFS_COLOR" +.It Sy ZFS_COLOR +Use ANSI color in +.Nm zfs Cm diff +output. +.El .Bl -tag -width "ZFS_MOUNT_HELPER" .It Sy ZFS_MOUNT_HELPER Cause