diff --git a/src/analyze/analyze-security.c b/src/analyze/analyze-security.c index 2691dc2c868..3ee7644a89f 100644 --- a/src/analyze/analyze-security.c +++ b/src/analyze/analyze-security.c @@ -1902,7 +1902,7 @@ static int assess(const SecurityInfo *info, name = info->id; printf("\n%s %sOverall exposure level for %s%s: %s%" PRIu64 ".%" PRIu64 " %s%s %s\n", - special_glyph(SPECIAL_GLYPH_ARROW), + special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), ansi_highlight(), name, ansi_normal(), diff --git a/src/basic/chase-symlinks.c b/src/basic/chase-symlinks.c index 344e7e1bb74..61f8b3351be 100644 --- a/src/basic/chase-symlinks.c +++ b/src/basic/chase-symlinks.c @@ -41,7 +41,7 @@ static int log_unsafe_transition(int a, int b, const char *path, unsigned flags) return log_warning_errno(SYNTHETIC_ERRNO(ENOLINK), "Detected unsafe path transition %s (owned by %s) %s %s (owned by %s) during canonicalization of %s.", - strna(n1), strna(user_a), special_glyph(SPECIAL_GLYPH_ARROW), strna(n2), strna(user_b), path); + strna(n1), strna(user_a), special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), strna(n2), strna(user_b), path); } static int log_autofs_mount_point(int fd, const char *path, unsigned flags) { diff --git a/src/basic/glyph-util.c b/src/basic/glyph-util.c index 8810738fc3a..4583b7412cc 100644 --- a/src/basic/glyph-util.c +++ b/src/basic/glyph-util.c @@ -39,6 +39,7 @@ const char *special_glyph(SpecialGlyph code) { [SPECIAL_GLYPH_TREE_BRANCH] = "|-", [SPECIAL_GLYPH_TREE_RIGHT] = "`-", [SPECIAL_GLYPH_TREE_SPACE] = " ", + [SPECIAL_GLYPH_TREE_TOP] = ",-", [SPECIAL_GLYPH_TRIANGULAR_BULLET] = ">", [SPECIAL_GLYPH_BLACK_CIRCLE] = "*", [SPECIAL_GLYPH_WHITE_CIRCLE] = "*", @@ -51,7 +52,9 @@ const char *special_glyph(SpecialGlyph code) { [SPECIAL_GLYPH_LIGHT_SHADE] = "-", [SPECIAL_GLYPH_DARK_SHADE] = "X", [SPECIAL_GLYPH_SIGMA] = "S", - [SPECIAL_GLYPH_ARROW] = "->", + [SPECIAL_GLYPH_ARROW_RIGHT] = "->", + [SPECIAL_GLYPH_ARROW_UP] = "^", + [SPECIAL_GLYPH_ARROW_DOWN] = "v", [SPECIAL_GLYPH_ELLIPSIS] = "...", [SPECIAL_GLYPH_EXTERNAL_LINK] = "[LNK]", [SPECIAL_GLYPH_ECSTATIC_SMILEY] = ":-]", @@ -75,6 +78,7 @@ const char *special_glyph(SpecialGlyph code) { [SPECIAL_GLYPH_TREE_BRANCH] = "\342\224\234\342\224\200", /* ├─ */ [SPECIAL_GLYPH_TREE_RIGHT] = "\342\224\224\342\224\200", /* └─ */ [SPECIAL_GLYPH_TREE_SPACE] = " ", /* */ + [SPECIAL_GLYPH_TREE_TOP] = "\u250C\342\224\200", /* ┌─ */ /* Single glyphs in both cases */ [SPECIAL_GLYPH_TRIANGULAR_BULLET] = "\342\200\243", /* ‣ */ @@ -89,9 +93,11 @@ const char *special_glyph(SpecialGlyph code) { [SPECIAL_GLYPH_LIGHT_SHADE] = "\342\226\221", /* ░ */ [SPECIAL_GLYPH_DARK_SHADE] = "\342\226\223", /* ▒ */ [SPECIAL_GLYPH_SIGMA] = "\316\243", /* Σ */ + [SPECIAL_GLYPH_ARROW_UP] = "\u2191", /* ↑ (actually called: UPWARDS ARROW) */ + [SPECIAL_GLYPH_ARROW_DOWN] = "\u2193", /* ↓ (actually called: DOWNWARDS ARROW) */ /* Single glyph in Unicode, two in ASCII */ - [SPECIAL_GLYPH_ARROW] = "\342\206\222", /* → (actually called: RIGHTWARDS ARROW) */ + [SPECIAL_GLYPH_ARROW_RIGHT] = "\342\206\222", /* → (actually called: RIGHTWARDS ARROW) */ /* Single glyph in Unicode, three in ASCII */ [SPECIAL_GLYPH_ELLIPSIS] = "\342\200\246", /* … (actually called: HORIZONTAL ELLIPSIS) */ diff --git a/src/basic/glyph-util.h b/src/basic/glyph-util.h index ddee210041b..7e0a73842a8 100644 --- a/src/basic/glyph-util.h +++ b/src/basic/glyph-util.h @@ -11,6 +11,7 @@ typedef enum SpecialGlyph { SPECIAL_GLYPH_TREE_BRANCH, SPECIAL_GLYPH_TREE_RIGHT, SPECIAL_GLYPH_TREE_SPACE, + SPECIAL_GLYPH_TREE_TOP, SPECIAL_GLYPH_TRIANGULAR_BULLET, SPECIAL_GLYPH_BLACK_CIRCLE, SPECIAL_GLYPH_WHITE_CIRCLE, @@ -20,7 +21,9 @@ typedef enum SpecialGlyph { SPECIAL_GLYPH_MU, SPECIAL_GLYPH_CHECK_MARK, SPECIAL_GLYPH_CROSS_MARK, - SPECIAL_GLYPH_ARROW, + SPECIAL_GLYPH_ARROW_RIGHT, + SPECIAL_GLYPH_ARROW_UP, + SPECIAL_GLYPH_ARROW_DOWN, SPECIAL_GLYPH_ELLIPSIS, SPECIAL_GLYPH_LIGHT_SHADE, SPECIAL_GLYPH_DARK_SHADE, diff --git a/src/basic/user-util.h b/src/basic/user-util.h index bc76de6b411..40979d10801 100644 --- a/src/basic/user-util.h +++ b/src/basic/user-util.h @@ -12,6 +12,14 @@ #include #include +/* Users managed by systemd-homed. See https://systemd.io/UIDS-GIDS for details how this range fits into the rest of the world */ +#define HOME_UID_MIN 60001 +#define HOME_UID_MAX 60513 + +/* Users mapped from host into a container */ +#define MAP_UID_MIN 60514 +#define MAP_UID_MAX 60577 + bool uid_is_valid(uid_t uid); static inline bool gid_is_valid(gid_t gid) { diff --git a/src/delta/delta.c b/src/delta/delta.c index 3f1b206e6cc..e14ad36d03d 100644 --- a/src/delta/delta.c +++ b/src/delta/delta.c @@ -91,7 +91,7 @@ static int notify_override_masked(const char *top, const char *bottom) { printf("%s%s%s %s %s %s\n", ansi_highlight_red(), "[MASKED]", ansi_normal(), - top, special_glyph(SPECIAL_GLYPH_ARROW), bottom); + top, special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), bottom); return 1; } @@ -101,7 +101,7 @@ static int notify_override_equivalent(const char *top, const char *bottom) { printf("%s%s%s %s %s %s\n", ansi_highlight_green(), "[EQUIVALENT]", ansi_normal(), - top, special_glyph(SPECIAL_GLYPH_ARROW), bottom); + top, special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), bottom); return 1; } @@ -111,7 +111,7 @@ static int notify_override_redirected(const char *top, const char *bottom) { printf("%s%s%s %s %s %s\n", ansi_highlight(), "[REDIRECTED]", ansi_normal(), - top, special_glyph(SPECIAL_GLYPH_ARROW), bottom); + top, special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), bottom); return 1; } @@ -121,7 +121,7 @@ static int notify_override_overridden(const char *top, const char *bottom) { printf("%s%s%s %s %s %s\n", ansi_highlight(), "[OVERRIDDEN]", ansi_normal(), - top, special_glyph(SPECIAL_GLYPH_ARROW), bottom); + top, special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), bottom); return 1; } @@ -131,7 +131,7 @@ static int notify_override_extended(const char *top, const char *bottom) { printf("%s%s%s %s %s %s\n", ansi_highlight(), "[EXTENDED]", ansi_normal(), - top, special_glyph(SPECIAL_GLYPH_ARROW), bottom); + top, special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), bottom); return 1; } @@ -236,7 +236,7 @@ static int enumerate_dir_d( return -ENOMEM; d = p + strlen(toppath) + 1; - log_debug("Adding at top: %s %s %s", d, special_glyph(SPECIAL_GLYPH_ARROW), p); + log_debug("Adding at top: %s %s %s", d, special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), p); k = ordered_hashmap_put(top, d, p); if (k >= 0) { p = strdup(p); @@ -248,7 +248,7 @@ static int enumerate_dir_d( return k; } - log_debug("Adding at bottom: %s %s %s", d, special_glyph(SPECIAL_GLYPH_ARROW), p); + log_debug("Adding at bottom: %s %s %s", d, special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), p); free(ordered_hashmap_remove(bottom, d)); k = ordered_hashmap_put(bottom, d, p); if (k < 0) { @@ -272,7 +272,7 @@ static int enumerate_dir_d( return -ENOMEM; log_debug("Adding to drops: %s %s %s %s %s", - unit, special_glyph(SPECIAL_GLYPH_ARROW), basename(p), special_glyph(SPECIAL_GLYPH_ARROW), p); + unit, special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), basename(p), special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), p); k = ordered_hashmap_put(h, basename(p), p); if (k < 0) { free(p); @@ -349,7 +349,7 @@ static int enumerate_dir( if (!p) return -ENOMEM; - log_debug("Adding at top: %s %s %s", basename(p), special_glyph(SPECIAL_GLYPH_ARROW), p); + log_debug("Adding at top: %s %s %s", basename(p), special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), p); r = ordered_hashmap_put(top, basename(p), p); if (r >= 0) { p = strdup(p); @@ -358,7 +358,7 @@ static int enumerate_dir( } else if (r != -EEXIST) return r; - log_debug("Adding at bottom: %s %s %s", basename(p), special_glyph(SPECIAL_GLYPH_ARROW), p); + log_debug("Adding at bottom: %s %s %s", basename(p), special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), p); free(ordered_hashmap_remove(bottom, basename(p))); r = ordered_hashmap_put(bottom, basename(p), p); if (r < 0) diff --git a/src/home/home-util.h b/src/home/home-util.h index 69a88000f84..36b301d2360 100644 --- a/src/home/home-util.h +++ b/src/home/home-util.h @@ -8,10 +8,6 @@ #include "time-util.h" #include "user-record.h" -/* See https://systemd.io/UIDS-GIDS for details how this range fits into the rest of the world */ -#define HOME_UID_MIN 60001 -#define HOME_UID_MAX 60513 - /* Put some limits on disk sizes: not less than 5M, not more than 5T */ #define USER_DISK_SIZE_MIN (UINT64_C(5)*1024*1024) #define USER_DISK_SIZE_MAX (UINT64_C(5)*1024*1024*1024*1024) diff --git a/src/nspawn/nspawn-bind-user.c b/src/nspawn/nspawn-bind-user.c index d3113c303e6..97761cb6f0b 100644 --- a/src/nspawn/nspawn-bind-user.c +++ b/src/nspawn/nspawn-bind-user.c @@ -10,9 +10,6 @@ #include "user-util.h" #include "userdb.h" -#define MAP_UID_START 60514 -#define MAP_UID_END 60577 - static int check_etc_passwd_collisions( const char *directory, const char *name, @@ -157,11 +154,11 @@ static int find_free_uid(const char *directory, uid_t max_uid, uid_t *current_ui assert(current_uid); for (;; (*current_uid) ++) { - if (*current_uid > MAP_UID_END || *current_uid > max_uid) + if (*current_uid > MAP_UID_MAX || *current_uid > max_uid) return log_error_errno( SYNTHETIC_ERRNO(EBUSY), "No suitable available UID in range " UID_FMT "…" UID_FMT " in container detected, can't map user.", - MAP_UID_START, MAP_UID_END); + MAP_UID_MIN, MAP_UID_MAX); r = check_etc_passwd_collisions(directory, NULL, *current_uid); if (r < 0) @@ -202,7 +199,7 @@ int bind_user_prepare( BindUserContext **ret) { _cleanup_(bind_user_context_freep) BindUserContext *c = NULL; - uid_t current_uid = MAP_UID_START; + uid_t current_uid = MAP_UID_MIN; char **n; int r; diff --git a/src/partition/repart.c b/src/partition/repart.c index abdf947dbff..91645202fca 100644 --- a/src/partition/repart.c +++ b/src/partition/repart.c @@ -1969,9 +1969,9 @@ static int format_size_change(uint64_t from, uint64_t to, char **ret) { if (from == to || to == UINT64_MAX) t = strdup(FORMAT_BYTES(from)); else - t = strjoin(FORMAT_BYTES(from), " ", special_glyph(SPECIAL_GLYPH_ARROW), " ", FORMAT_BYTES(to)); + t = strjoin(FORMAT_BYTES(from), " ", special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), " ", FORMAT_BYTES(to)); } else if (to != UINT64_MAX) - t = strjoin(special_glyph(SPECIAL_GLYPH_ARROW), " ", FORMAT_BYTES(to)); + t = strjoin(special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), " ", FORMAT_BYTES(to)); else { *ret = NULL; return 0; diff --git a/src/portable/portable.c b/src/portable/portable.c index d91ce7bc71c..a54e091185c 100644 --- a/src/portable/portable.c +++ b/src/portable/portable.c @@ -1052,14 +1052,14 @@ static int install_profile_dropin( r = copy_file_atomic(from, dropin, 0644, 0, 0, COPY_REFLINK); if (r < 0) - return log_debug_errno(r, "Failed to copy %s %s %s: %m", from, special_glyph(SPECIAL_GLYPH_ARROW), dropin); + return log_debug_errno(r, "Failed to copy %s %s %s: %m", from, special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), dropin); (void) portable_changes_add(changes, n_changes, PORTABLE_COPY, dropin, from); } else { if (symlink(from, dropin) < 0) - return log_debug_errno(errno, "Failed to link %s %s %s: %m", from, special_glyph(SPECIAL_GLYPH_ARROW), dropin); + return log_debug_errno(errno, "Failed to link %s %s %s: %m", from, special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), dropin); (void) portable_changes_add(changes, n_changes, PORTABLE_SYMLINK, dropin, from); } @@ -1229,7 +1229,7 @@ static int install_image_symlink( (void) mkdir_parents(sl, 0755); if (symlink(image_path, sl) < 0) - return log_debug_errno(errno, "Failed to link %s %s %s: %m", image_path, special_glyph(SPECIAL_GLYPH_ARROW), sl); + return log_debug_errno(errno, "Failed to link %s %s %s: %m", image_path, special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), sl); (void) portable_changes_add(changes, n_changes, PORTABLE_SYMLINK, sl, image_path); return 0; diff --git a/src/portable/portablectl.c b/src/portable/portablectl.c index eee26d00331..bc7a4ddc210 100644 --- a/src/portable/portablectl.c +++ b/src/portable/portablectl.c @@ -502,12 +502,12 @@ static int print_changes(sd_bus_message *m) { break; if (streq(type, "symlink")) - log_info("Created symlink %s %s %s.", path, special_glyph(SPECIAL_GLYPH_ARROW), source); + log_info("Created symlink %s %s %s.", path, special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), source); else if (streq(type, "copy")) { if (isempty(source)) log_info("Copied %s.", path); else - log_info("Copied %s %s %s.", source, special_glyph(SPECIAL_GLYPH_ARROW), path); + log_info("Copied %s %s %s.", source, special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), path); } else if (streq(type, "unlink")) log_info("Removed %s.", path); else if (streq(type, "write")) diff --git a/src/shared/cgroup-show.c b/src/shared/cgroup-show.c index 48dd4d80013..f18420c1b68 100644 --- a/src/shared/cgroup-show.c +++ b/src/shared/cgroup-show.c @@ -228,7 +228,7 @@ static int show_cgroup_name( printf("%s%s%s %s%s%s: %s\n", prefix, glyph == SPECIAL_GLYPH_TREE_BRANCH ? special_glyph(SPECIAL_GLYPH_TREE_VERTICAL) : " ", - special_glyph(SPECIAL_GLYPH_ARROW), + special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), ansi_blue(), x, ansi_normal(), y); } diff --git a/src/shared/install.c b/src/shared/install.c index 8f1af755fa9..d0b3b68b4e8 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -336,7 +336,7 @@ void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *chang if (!quiet) log_info("Created symlink %s %s %s.", changes[i].path, - special_glyph(SPECIAL_GLYPH_ARROW), + special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), changes[i].source); break; case UNIT_FILE_UNLINK: diff --git a/src/test/test-locale-util.c b/src/test/test-locale-util.c index 55f86f7c2f5..9bbc5917a1e 100644 --- a/src/test/test-locale-util.c +++ b/src/test/test-locale-util.c @@ -93,13 +93,16 @@ TEST(dump_special_glyphs) { dump_glyph(SPECIAL_GLYPH_TREE_BRANCH); dump_glyph(SPECIAL_GLYPH_TREE_RIGHT); dump_glyph(SPECIAL_GLYPH_TREE_SPACE); + dump_glyph(SPECIAL_GLYPH_TREE_TOP); dump_glyph(SPECIAL_GLYPH_TRIANGULAR_BULLET); dump_glyph(SPECIAL_GLYPH_BLACK_CIRCLE); dump_glyph(SPECIAL_GLYPH_WHITE_CIRCLE); dump_glyph(SPECIAL_GLYPH_MULTIPLICATION_SIGN); dump_glyph(SPECIAL_GLYPH_CIRCLE_ARROW); dump_glyph(SPECIAL_GLYPH_BULLET); - dump_glyph(SPECIAL_GLYPH_ARROW); + dump_glyph(SPECIAL_GLYPH_ARROW_RIGHT); + dump_glyph(SPECIAL_GLYPH_ARROW_UP); + dump_glyph(SPECIAL_GLYPH_ARROW_DOWN); dump_glyph(SPECIAL_GLYPH_ELLIPSIS); dump_glyph(SPECIAL_GLYPH_MU); dump_glyph(SPECIAL_GLYPH_CHECK_MARK); diff --git a/src/userdb/userdbctl.c b/src/userdb/userdbctl.c index c2acd85742d..0b65ae92102 100644 --- a/src/userdb/userdbctl.c +++ b/src/userdb/userdbctl.c @@ -39,6 +39,29 @@ static bool arg_chain = false; STATIC_DESTRUCTOR_REGISTER(arg_services, strv_freep); +static const char *user_disposition_to_color(UserDisposition d) { + assert(d >= 0); + assert(d < _USER_DISPOSITION_MAX); + + switch (d) { + case USER_INTRINSIC: + return ansi_red(); + + case USER_SYSTEM: + case USER_DYNAMIC: + return ansi_green(); + + case USER_CONTAINER: + return ansi_cyan(); + + case USER_RESERVED: + return ansi_red(); + + default: + return NULL; + } +} + static int show_user(UserRecord *ur, Table *table) { int r; @@ -74,23 +97,29 @@ static int show_user(UserRecord *ur, Table *table) { break; - case OUTPUT_TABLE: + case OUTPUT_TABLE: { + UserDisposition d; + assert(table); + d = user_record_disposition(ur); r = table_add_many( table, + TABLE_STRING, "", TABLE_STRING, ur->user_name, - TABLE_STRING, user_disposition_to_string(user_record_disposition(ur)), + TABLE_SET_COLOR, user_disposition_to_color(d), + TABLE_STRING, user_disposition_to_string(d), TABLE_UID, ur->uid, TABLE_GID, user_record_gid(ur), TABLE_STRING, empty_to_null(ur->real_name), TABLE_STRING, user_record_home_directory(ur), TABLE_STRING, user_record_shell(ur), - TABLE_INT, (int) user_record_disposition(ur)); + TABLE_INT, 0); if (r < 0) return table_log_add_error(r); break; + } default: assert_not_reached(); @@ -99,6 +128,115 @@ static int show_user(UserRecord *ur, Table *table) { return 0; } +static const struct { + uid_t first, last; + const char *name; + UserDisposition disposition; +} uid_range_table[] = { + { + .first = 1, + .last = SYSTEM_UID_MAX, + .name = "system", + .disposition = USER_SYSTEM, + }, + { + .first = DYNAMIC_UID_MIN, + .last = DYNAMIC_UID_MAX, + .name = "dynamic system", + .disposition = USER_DYNAMIC, + }, + { + .first = CONTAINER_UID_BASE_MIN, + .last = CONTAINER_UID_BASE_MAX, + .name = "container", + .disposition = USER_CONTAINER, + }, +#if ENABLE_HOMED + { + .first = HOME_UID_MIN, + .last = HOME_UID_MAX, + .name = "systemd-homed", + .disposition = USER_REGULAR, + }, +#endif + { + .first = MAP_UID_MIN, + .last = MAP_UID_MAX, + .name = "mapped", + .disposition = USER_REGULAR, + }, +}; + +static int table_add_uid_boundaries(Table *table) { + int r; + + assert(table); + + for (size_t i = 0; i < ELEMENTSOF(uid_range_table); i++) { + _cleanup_free_ char *name = NULL, *comment = NULL; + + name = strjoin(special_glyph(SPECIAL_GLYPH_ARROW_DOWN), + " begin ", uid_range_table[i].name, " users ", + special_glyph(SPECIAL_GLYPH_ARROW_DOWN)); + if (!name) + return log_oom(); + + comment = strjoin("First ", uid_range_table[i].name, " user"); + if (!comment) + return log_oom(); + + r = table_add_many( + table, + TABLE_STRING, special_glyph(SPECIAL_GLYPH_TREE_TOP), + TABLE_STRING, name, + TABLE_SET_COLOR, ansi_grey(), + TABLE_STRING, user_disposition_to_string(uid_range_table[i].disposition), + TABLE_SET_COLOR, ansi_grey(), + TABLE_UID, uid_range_table[i].first, + TABLE_SET_COLOR, ansi_grey(), + TABLE_EMPTY, + TABLE_STRING, comment, + TABLE_SET_COLOR, ansi_grey(), + TABLE_EMPTY, + TABLE_EMPTY, + TABLE_INT, -1); /* sort before an other entry with the same UID */ + if (r < 0) + return table_log_add_error(r); + + free(name); + name = strjoin(special_glyph(SPECIAL_GLYPH_ARROW_UP), + " end ", uid_range_table[i].name, " users ", + special_glyph(SPECIAL_GLYPH_ARROW_UP)); + if (!name) + return log_oom(); + + free(comment); + comment = strjoin("Last ", uid_range_table[i].name, " user"); + if (!comment) + return log_oom(); + + r = table_add_many( + table, + TABLE_STRING, special_glyph(SPECIAL_GLYPH_TREE_RIGHT), + TABLE_STRING, name, + TABLE_SET_COLOR, ansi_grey(), + TABLE_STRING, user_disposition_to_string(uid_range_table[i].disposition), + TABLE_SET_COLOR, ansi_grey(), + TABLE_UID, uid_range_table[i].last, + TABLE_SET_COLOR, ansi_grey(), + TABLE_EMPTY, + TABLE_STRING, comment, + TABLE_SET_COLOR, ansi_grey(), + TABLE_EMPTY, + TABLE_EMPTY, + TABLE_INT, 1); /* sort after an other entry with the same UID */ + if (r < 0) + return table_log_add_error(r); + } + + return ELEMENTSOF(uid_range_table) * 2; +} + static int display_user(int argc, char *argv[], void *userdata) { _cleanup_(table_unrefp) Table *table = NULL; bool draw_separator = false; @@ -108,15 +246,15 @@ static int display_user(int argc, char *argv[], void *userdata) { arg_output = argc > 1 ? OUTPUT_FRIENDLY : OUTPUT_TABLE; if (arg_output == OUTPUT_TABLE) { - table = table_new("name", "disposition", "uid", "gid", "realname", "home", "shell", "disposition-numeric"); + table = table_new(" ", "name", "disposition", "uid", "gid", "realname", "home", "shell", "order"); if (!table) return log_oom(); - (void) table_set_align_percent(table, table_get_cell(table, 0, 2), 100); (void) table_set_align_percent(table, table_get_cell(table, 0, 3), 100); + (void) table_set_align_percent(table, table_get_cell(table, 0, 4), 100); (void) table_set_empty_string(table, "-"); - (void) table_set_sort(table, (size_t) 7, (size_t) 2); - (void) table_set_display(table, (size_t) 0, (size_t) 1, (size_t) 2, (size_t) 3, (size_t) 4, (size_t) 5, (size_t) 6); + (void) table_set_sort(table, (size_t) 3, (size_t) 8); + (void) table_set_display(table, (size_t) 0, (size_t) 1, (size_t) 2, (size_t) 3, (size_t) 4, (size_t) 5, (size_t) 6, (size_t) 7); } if (argc > 1) { @@ -186,6 +324,12 @@ static int display_user(int argc, char *argv[], void *userdata) { } if (table) { + int boundary_lines; + + boundary_lines = table_add_uid_boundaries(table); + if (boundary_lines < 0) + return boundary_lines; + if (table_get_rows(table) > 1) { r = table_print_with_pager(table, arg_json_format_flags, arg_pager_flags, arg_legend); if (r < 0) @@ -194,7 +338,7 @@ static int display_user(int argc, char *argv[], void *userdata) { if (arg_legend) { if (table_get_rows(table) > 1) - printf("\n%zu users listed.\n", table_get_rows(table) - 1); + printf("\n%zu users listed.\n", table_get_rows(table) - 1 - boundary_lines); else printf("No users.\n"); } @@ -241,20 +385,26 @@ static int show_group(GroupRecord *gr, Table *table) { break; - case OUTPUT_TABLE: + case OUTPUT_TABLE: { + UserDisposition d; + assert(table); + d = group_record_disposition(gr); r = table_add_many( table, + TABLE_STRING, "", TABLE_STRING, gr->group_name, - TABLE_STRING, user_disposition_to_string(group_record_disposition(gr)), + TABLE_SET_COLOR, user_disposition_to_color(d), + TABLE_STRING, user_disposition_to_string(d), TABLE_GID, gr->gid, TABLE_STRING, gr->description, - TABLE_INT, (int) group_record_disposition(gr)); + TABLE_INT, 0); if (r < 0) return table_log_add_error(r); break; + } default: assert_not_reached(); @@ -263,6 +413,69 @@ static int show_group(GroupRecord *gr, Table *table) { return 0; } +static int table_add_gid_boundaries(Table *table) { + int r; + + assert(table); + + for (size_t i = 0; i < ELEMENTSOF(uid_range_table); i++) { + _cleanup_free_ char *name = NULL, *comment = NULL; + + name = strjoin(special_glyph(SPECIAL_GLYPH_ARROW_DOWN), + " begin ", uid_range_table[i].name, " groups ", + special_glyph(SPECIAL_GLYPH_ARROW_DOWN)); + if (!name) + return log_oom(); + + comment = strjoin("First ", uid_range_table[i].name, " group"); + if (!comment) + return log_oom(); + + r = table_add_many( + table, + TABLE_STRING, special_glyph(SPECIAL_GLYPH_TREE_TOP), + TABLE_STRING, name, + TABLE_SET_COLOR, ansi_grey(), + TABLE_STRING, user_disposition_to_string(uid_range_table[i].disposition), + TABLE_SET_COLOR, ansi_grey(), + TABLE_GID, uid_range_table[i].first, + TABLE_SET_COLOR, ansi_grey(), + TABLE_STRING, comment, + TABLE_SET_COLOR, ansi_grey(), + TABLE_INT, -1); /* sort before an other entry with the same GID */ + if (r < 0) + return table_log_add_error(r); + + free(name); + name = strjoin(special_glyph(SPECIAL_GLYPH_ARROW_UP), + " end ", uid_range_table[i].name, " groups ", + special_glyph(SPECIAL_GLYPH_ARROW_UP)); + if (!name) + return log_oom(); + + free(comment); + comment = strjoin("Last ", uid_range_table[i].name, " group"); + if (!comment) + return log_oom(); + + r = table_add_many( + table, + TABLE_STRING, special_glyph(SPECIAL_GLYPH_TREE_RIGHT), + TABLE_STRING, name, + TABLE_SET_COLOR, ansi_grey(), + TABLE_STRING, user_disposition_to_string(uid_range_table[i].disposition), + TABLE_SET_COLOR, ansi_grey(), + TABLE_GID, uid_range_table[i].last, + TABLE_SET_COLOR, ansi_grey(), + TABLE_STRING, comment, + TABLE_SET_COLOR, ansi_grey(), + TABLE_INT, 1); /* sort after an other entry with the same GID */ + if (r < 0) + return table_log_add_error(r); + } + + return ELEMENTSOF(uid_range_table) * 2; +} static int display_group(int argc, char *argv[], void *userdata) { _cleanup_(table_unrefp) Table *table = NULL; @@ -273,14 +486,14 @@ static int display_group(int argc, char *argv[], void *userdata) { arg_output = argc > 1 ? OUTPUT_FRIENDLY : OUTPUT_TABLE; if (arg_output == OUTPUT_TABLE) { - table = table_new("name", "disposition", "gid", "description", "disposition-numeric"); + table = table_new(" ", "name", "disposition", "gid", "description", "order"); if (!table) return log_oom(); - (void) table_set_align_percent(table, table_get_cell(table, 0, 2), 100); + (void) table_set_align_percent(table, table_get_cell(table, 0, 3), 100); (void) table_set_empty_string(table, "-"); - (void) table_set_sort(table, (size_t) 3, (size_t) 2); - (void) table_set_display(table, (size_t) 0, (size_t) 1, (size_t) 2, (size_t) 3); + (void) table_set_sort(table, (size_t) 3, (size_t) 5); + (void) table_set_display(table, (size_t) 0, (size_t) 1, (size_t) 2, (size_t) 3, (size_t) 4); } if (argc > 1) { @@ -351,6 +564,12 @@ static int display_group(int argc, char *argv[], void *userdata) { } if (table) { + int boundary_lines; + + boundary_lines = table_add_gid_boundaries(table); + if (boundary_lines < 0) + return boundary_lines; + if (table_get_rows(table) > 1) { r = table_print_with_pager(table, arg_json_format_flags, arg_pager_flags, arg_legend); if (r < 0) @@ -359,7 +578,7 @@ static int display_group(int argc, char *argv[], void *userdata) { if (arg_legend) { if (table_get_rows(table) > 1) - printf("\n%zu groups listed.\n", table_get_rows(table) - 1); + printf("\n%zu groups listed.\n", table_get_rows(table) - 1 - boundary_lines); else printf("No groups.\n"); }