format-table: make UID/GID/PID fields first class citizens + add signal cell type

This way we can display invalid UIDs/GIDs/PIDs as n/a while still
storing them as is.

Also, let's add a new cell type for unix signal, that is stored as
integer, but displayed as signal name string.
This commit is contained in:
Lennart Poettering
2021-02-10 12:21:17 +01:00
parent 77552b9520
commit a7273eaf32
2 changed files with 132 additions and 10 deletions
+128
View File
@@ -20,11 +20,14 @@
#include "parse-util.h"
#include "path-util.h"
#include "pretty-print.h"
#include "process-util.h"
#include "signal-util.h"
#include "sort-util.h"
#include "string-util.h"
#include "strxcpyx.h"
#include "terminal-util.h"
#include "time-util.h"
#include "user-util.h"
#include "utf8.h"
#include "util.h"
@@ -100,6 +103,9 @@ typedef struct TableData {
int ifindex;
union in_addr_union address;
sd_id128_t id128;
uid_t uid;
gid_t gid;
pid_t pid;
/* … add more here as we start supporting more cell data types … */
};
} TableData;
@@ -284,6 +290,7 @@ static size_t table_data_size(TableDataType type, const void *data) {
case TABLE_UINT:
case TABLE_PERCENT:
case TABLE_IFINDEX:
case TABLE_SIGNAL:
return sizeof(int);
case TABLE_IN_ADDR:
@@ -296,6 +303,13 @@ static size_t table_data_size(TableDataType type, const void *data) {
case TABLE_ID128:
return sizeof(sd_id128_t);
case TABLE_UID:
return sizeof(uid_t);
case TABLE_GID:
return sizeof(gid_t);
case TABLE_PID:
return sizeof(pid_t);
default:
assert_not_reached("Uh? Unexpected cell type");
}
@@ -801,6 +815,9 @@ int table_add_many_internal(Table *t, TableDataType first_type, ...) {
bool b;
union in_addr_union address;
sd_id128_t id128;
uid_t uid;
gid_t gid;
pid_t pid;
} buffer;
switch (type) {
@@ -840,6 +857,7 @@ int table_add_many_internal(Table *t, TableDataType first_type, ...) {
break;
case TABLE_INT:
case TABLE_SIGNAL:
buffer.int_val = va_arg(ap, int);
data = &buffer.int_val;
break;
@@ -931,6 +949,21 @@ int table_add_many_internal(Table *t, TableDataType first_type, ...) {
data = &buffer.id128;
break;
case TABLE_UID:
buffer.uid = va_arg(ap, uid_t);
data = &buffer.uid;
break;
case TABLE_GID:
buffer.gid = va_arg(ap, gid_t);
data = &buffer.gid;
break;
case TABLE_PID:
buffer.pid = va_arg(ap, pid_t);
data = &buffer.pid;
break;
case TABLE_SET_MINIMUM_WIDTH: {
size_t w = va_arg(ap, size_t);
@@ -1189,6 +1222,7 @@ static int cell_data_compare(TableData *a, size_t index_a, TableData *b, size_t
return CMP(a->size, b->size);
case TABLE_INT:
case TABLE_SIGNAL:
return CMP(a->int_val, b->int_val);
case TABLE_INT8:
@@ -1234,6 +1268,15 @@ static int cell_data_compare(TableData *a, size_t index_a, TableData *b, size_t
case TABLE_ID128:
return memcmp(&a->id128, &b->id128, sizeof(sd_id128_t));
case TABLE_UID:
return CMP(a->uid, b->uid);
case TABLE_GID:
return CMP(a->gid, b->gid);
case TABLE_PID:
return CMP(a->pid, b->pid);
default:
;
}
@@ -1618,6 +1661,67 @@ static const char *table_data_format(Table *t, TableData *d, bool avoid_uppercas
break;
}
case TABLE_UID: {
_cleanup_free_ char *p = NULL;
if (!uid_is_valid(d->uid))
return "n/a";
p = new(char, DECIMAL_STR_WIDTH(d->uid) + 1);
if (!p)
return NULL;
sprintf(p, UID_FMT, d->uid);
d->formatted = TAKE_PTR(p);
break;
}
case TABLE_GID: {
_cleanup_free_ char *p = NULL;
if (!gid_is_valid(d->gid))
return "n/a";
p = new(char, DECIMAL_STR_WIDTH(d->gid) + 1);
if (!p)
return NULL;
sprintf(p, GID_FMT, d->gid);
d->formatted = TAKE_PTR(p);
break;
}
case TABLE_PID: {
_cleanup_free_ char *p = NULL;
if (!pid_is_valid(d->pid))
return "n/a";
p = new(char, DECIMAL_STR_WIDTH(d->pid) + 1);
if (!p)
return NULL;
sprintf(p, PID_FMT, d->pid);
d->formatted = TAKE_PTR(p);
break;
}
case TABLE_SIGNAL: {
_cleanup_free_ char *p = NULL;
const char *suffix;
suffix = signal_to_string(d->int_val);
if (!suffix)
return "n/a";
p = strjoin("SIG", suffix);
if (!p)
return NULL;
d->formatted = TAKE_PTR(p);
break;
}
default:
assert_not_reached("Unexpected type?");
}
@@ -2392,6 +2496,30 @@ static int table_data_to_json(TableData *d, JsonVariant **ret) {
return json_variant_new_string(ret, id128_to_uuid_string(d->id128, buf));
}
case TABLE_UID:
if (!uid_is_valid(d->uid))
return json_variant_new_null(ret);
return json_variant_new_integer(ret, d->uid);
case TABLE_GID:
if (!gid_is_valid(d->gid))
return json_variant_new_null(ret);
return json_variant_new_integer(ret, d->gid);
case TABLE_PID:
if (!pid_is_valid(d->pid))
return json_variant_new_null(ret);
return json_variant_new_integer(ret, d->pid);
case TABLE_SIGNAL:
if (!SIGNAL_VALID(d->int_val))
return json_variant_new_null(ret);
return json_variant_new_integer(ret, d->int_val);
default:
return -EINVAL;
}
+4 -10
View File
@@ -39,6 +39,10 @@ typedef enum TableDataType {
TABLE_IN6_ADDR, /* Takes a union in_addr_union (or a struct in6_addr) */
TABLE_ID128,
TABLE_UUID,
TABLE_UID,
TABLE_GID,
TABLE_PID,
TABLE_SIGNAL,
_TABLE_DATA_TYPE_MAX,
/* The following are not really data types, but commands for table_add_cell_many() to make changes to
@@ -57,16 +61,6 @@ typedef enum TableDataType {
_TABLE_DATA_TYPE_INVALID = -1,
} TableDataType;
/* PIDs are just 32bit signed integers on Linux */
#define TABLE_PID TABLE_INT32
assert_cc(sizeof(pid_t) == sizeof(int32_t));
/* UIDs/GIDs are just 32bit unsigned integers on Linux */
#define TABLE_UID TABLE_UINT32
#define TABLE_GID TABLE_UINT32
assert_cc(sizeof(uid_t) == sizeof(uint32_t));
assert_cc(sizeof(gid_t) == sizeof(uint32_t));
typedef struct Table Table;
typedef struct TableCell TableCell;