aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/codeql.yml4
-rw-r--r--include/c.h1
-rw-r--r--libblkid/src/superblocks/bcache.c9
-rw-r--r--libblkid/src/superblocks/superblocks.c6
-rw-r--r--libmount/src/context_mount.c6
-rw-r--r--misc-utils/lsclocks.1.adoc9
-rw-r--r--misc-utils/lsclocks.c331
-rw-r--r--misc-utils/lsfd.1.adoc5
-rw-r--r--misc-utils/lsfd.c78
-rw-r--r--tests/expected/blkid/low-probe-bcachefs2
-rw-r--r--tests/expected/blkid/low-probe-bcachefs-22
-rw-r--r--tests/expected/misc/lsclocks-basic20
-rw-r--r--tests/expected/misc/lsclocks-dynamic1
-rwxr-xr-xtests/ts/misc/lsclocks12
14 files changed, 331 insertions, 155 deletions
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
index 671e569daf..b7d98a0de7 100644
--- a/.github/workflows/codeql.yml
+++ b/.github/workflows/codeql.yml
@@ -39,6 +39,10 @@ jobs:
with:
languages: ${{ matrix.language }}
queries: +security-extended,security-and-quality
+ config: |
+ query-filters:
+ - exclude:
+ id: cpp/path-injection
- name: Install dependencies
run: sudo -E .github/workflows/cibuild-setup-ubuntu.sh
diff --git a/include/c.h b/include/c.h
index f9f90f3bbe..752f568c50 100644
--- a/include/c.h
+++ b/include/c.h
@@ -452,6 +452,7 @@ static inline void __attribute__((__noreturn__)) ul_sig_err(int excode, const ch
#define USAGE_COMMANDS _("\nCommands:\n")
#define USAGE_ARGUMENTS _("\nArguments:\n")
#define USAGE_COLUMNS _("\nAvailable output columns:\n")
+#define USAGE_DEFAULT_COLUMNS _("\nDefault columns:\n")
#define USAGE_SEPARATOR "\n"
#define USAGE_OPTSTR_HELP _("display this help")
diff --git a/libblkid/src/superblocks/bcache.c b/libblkid/src/superblocks/bcache.c
index bf7fed01fe..1a0c124d37 100644
--- a/libblkid/src/superblocks/bcache.c
+++ b/libblkid/src/superblocks/bcache.c
@@ -149,6 +149,9 @@ struct bcachefs_super_block {
#define BCACHEFS_SB_FIELDS_OFF offsetof(struct bcachefs_super_block, _start)
/* tag value for members field */
#define BCACHEFS_SB_FIELD_TYPE_MEMBERS 1
+/* version splitting helpers */
+#define BCH_VERSION_MAJOR(_v) ((uint16_t) ((_v) >> 10))
+#define BCH_VERSION_MINOR(_v) ((uint16_t) ((_v) & ~(~0U << 10)))
#define BYTES(f) ((((uint64_t) le32_to_cpu((f)->u64s)) * 8))
@@ -300,6 +303,7 @@ static int probe_bcachefs(blkid_probe pr, const struct blkid_idmag *mag)
struct bcachefs_super_block *bcs;
const unsigned char *sb, *sb_end;
uint64_t sb_size, blocksize;
+ uint16_t version;
bcs = blkid_probe_get_sb(pr, mag, struct bcachefs_super_block);
if (!bcs)
@@ -325,7 +329,10 @@ static int probe_bcachefs(blkid_probe pr, const struct blkid_idmag *mag)
blkid_probe_set_uuid(pr, bcs->user_uuid);
blkid_probe_set_label(pr, bcs->label, sizeof(bcs->label));
- blkid_probe_sprintf_version(pr, "%d", le16_to_cpu(bcs->version));
+ version = le16_to_cpu(bcs->version);
+ blkid_probe_sprintf_version(pr, "%"PRIu16".%"PRIu16,
+ BCH_VERSION_MAJOR(version),
+ BCH_VERSION_MINOR(version));
blocksize = le16_to_cpu(bcs->block_size);
blkid_probe_set_block_size(pr, blocksize * BCACHEFS_SECTOR_SIZE);
blkid_probe_set_fsblocksize(pr, blocksize * BCACHEFS_SECTOR_SIZE);
diff --git a/libblkid/src/superblocks/superblocks.c b/libblkid/src/superblocks/superblocks.c
index fb03927078..c7789a15be 100644
--- a/libblkid/src/superblocks/superblocks.c
+++ b/libblkid/src/superblocks/superblocks.c
@@ -94,11 +94,6 @@ static int blkid_probe_set_usage(blkid_probe pr, int usage);
*/
static const struct blkid_idinfo *idinfos[] =
{
- /* In case the volume is locked with OPAL we are going to get
- * an I/O error when reading past the LUKS header, so try it
- * first. */
- &luks_idinfo,
-
/* RAIDs */
&linuxraid_idinfo,
&ddfraid_idinfo,
@@ -124,6 +119,7 @@ static const struct blkid_idinfo *idinfos[] =
&snapcow_idinfo,
&verity_hash_idinfo,
&integrity_idinfo,
+ &luks_idinfo,
&vmfs_volume_idinfo,
&ubi_idinfo,
&vdo_idinfo,
diff --git a/libmount/src/context_mount.c b/libmount/src/context_mount.c
index 87387ae366..05c84f1702 100644
--- a/libmount/src/context_mount.c
+++ b/libmount/src/context_mount.c
@@ -1517,6 +1517,12 @@ int mnt_context_get_mount_excode(
* mount(2) syscall success, but something else failed
* (probably error in utab processing).
*/
+ if (rc == -MNT_ERR_APPLYFLAGS) {
+ if (buf)
+ snprintf(buf, bufsz, _("filesystem was mounted, but failed to apply flags"));
+ return MNT_EX_USAGE;
+ }
+
if (rc == -MNT_ERR_LOCK) {
if (buf)
snprintf(buf, bufsz, _("filesystem was mounted, but failed to update userspace mount table"));
diff --git a/misc-utils/lsclocks.1.adoc b/misc-utils/lsclocks.1.adoc
index 4024c93e4b..90497fba52 100644
--- a/misc-utils/lsclocks.1.adoc
+++ b/misc-utils/lsclocks.1.adoc
@@ -42,12 +42,21 @@ Use raw output format.
*-r*, *--time* _clock_
Show current time of one specific clocks.
+*--no-discover-dynamic*
+Do not try to discover dynamic clocks.
+
+*-d*, *--dynamic-clock* _path_
+Also display specified dynamic clock.
+
include::man-common/help-version.adoc[]
== OUTPUT COLUMNS
Each column has a type. Types are surround by < and >.
+TYPE <``string``>::
+Clock type.
+
ID <``number``>::
Numeric clock ID.
diff --git a/misc-utils/lsclocks.c b/misc-utils/lsclocks.c
index dd6fedda71..ec27b9a155 100644
--- a/misc-utils/lsclocks.c
+++ b/misc-utils/lsclocks.c
@@ -23,6 +23,7 @@
#include <time.h>
#include <inttypes.h>
#include <getopt.h>
+#include <glob.h>
#include <libsmartcols.h>
@@ -34,9 +35,24 @@
#include "xalloc.h"
#include "pathnames.h"
#include "all-io.h"
+#include "list.h"
#define CLOCKFD 3
-#define FD_TO_CLOCKID(fd) ((~(clockid_t) (fd) << 3) | CLOCKFD)
+
+static inline clockid_t FD_TO_CLOCKID(int fd)
+{
+ return (~(unsigned int) fd << 3) | CLOCKFD;
+}
+
+static inline int CLOCKID_TO_FD(clockid_t clk)
+{
+ return ~(clk >> 3);
+}
+
+static inline bool CLOCKID_IS_DYNAMIC(clockid_t clk)
+{
+ return CLOCKID_TO_FD(clk) <= 0;
+}
#ifndef CLOCK_REALTIME
#define CLOCK_REALTIME 0
@@ -74,7 +90,24 @@
#define CLOCK_TAI 11
#endif
+enum CLOCK_TYPE {
+ CT_SYS,
+ CT_PTP,
+};
+
+static const char *clock_type_name(enum CLOCK_TYPE type)
+{
+ switch (type) {
+ case CT_SYS:
+ return "sys";
+ case CT_PTP:
+ return "ptp";
+ }
+ errx(EXIT_FAILURE, _("Unknown clock type %d"), type);
+}
+
struct clockinfo {
+ enum CLOCK_TYPE type;
clockid_t id;
const char * const id_name;
const char * const name;
@@ -82,21 +115,22 @@ struct clockinfo {
};
static const struct clockinfo clocks[] = {
- { CLOCK_REALTIME, "CLOCK_REALTIME", "realtime" },
- { CLOCK_MONOTONIC, "CLOCK_MONOTONIC", "monotonic",
- .ns_offset_name = "monotonic" },
- { CLOCK_MONOTONIC_RAW, "CLOCK_MONOTONIC_RAW", "monotonic-raw" },
- { CLOCK_REALTIME_COARSE, "CLOCK_REALTIME_COARSE", "realtime-coarse" },
- { CLOCK_MONOTONIC_COARSE, "CLOCK_MONOTONIC_COARSE", "monotonic-coarse" },
- { CLOCK_BOOTTIME, "CLOCK_BOOTTIME", "boottime",
- .ns_offset_name = "boottime" },
- { CLOCK_REALTIME_ALARM, "CLOCK_REALTIME_ALARM", "realtime-alarm" },
- { CLOCK_BOOTTIME_ALARM, "CLOCK_BOOTTIME_ALARM", "boottime-alarm" },
- { CLOCK_TAI, "CLOCK_TAI", "tai" },
+ { CT_SYS, CLOCK_REALTIME, "CLOCK_REALTIME", "realtime" },
+ { CT_SYS, CLOCK_MONOTONIC, "CLOCK_MONOTONIC", "monotonic",
+ .ns_offset_name = "monotonic" },
+ { CT_SYS, CLOCK_MONOTONIC_RAW, "CLOCK_MONOTONIC_RAW", "monotonic-raw" },
+ { CT_SYS, CLOCK_REALTIME_COARSE, "CLOCK_REALTIME_COARSE", "realtime-coarse" },
+ { CT_SYS, CLOCK_MONOTONIC_COARSE, "CLOCK_MONOTONIC_COARSE", "monotonic-coarse" },
+ { CT_SYS, CLOCK_BOOTTIME, "CLOCK_BOOTTIME", "boottime",
+ .ns_offset_name = "boottime" },
+ { CT_SYS, CLOCK_REALTIME_ALARM, "CLOCK_REALTIME_ALARM", "realtime-alarm" },
+ { CT_SYS, CLOCK_BOOTTIME_ALARM, "CLOCK_BOOTTIME_ALARM", "boottime-alarm" },
+ { CT_SYS, CLOCK_TAI, "CLOCK_TAI", "tai" },
};
/* column IDs */
enum {
+ COL_TYPE,
COL_ID,
COL_CLOCK,
COL_NAME,
@@ -119,6 +153,7 @@ struct colinfo {
/* columns descriptions */
static const struct colinfo infos[] = {
+ [COL_TYPE] = { "TYPE", 1, 0, SCOLS_JSON_STRING, N_("type") },
[COL_ID] = { "ID", 1, SCOLS_FL_RIGHT, SCOLS_JSON_NUMBER, N_("numeric id") },
[COL_CLOCK] = { "CLOCK", 1, 0, SCOLS_JSON_STRING, N_("symbolic name") },
[COL_NAME] = { "NAME", 1, 0, SCOLS_JSON_STRING, N_("readable name") },
@@ -154,15 +189,17 @@ static void __attribute__((__noreturn__)) usage(void)
fprintf(out, _(" %s [options]\n"), program_invocation_short_name);
fputs(USAGE_OPTIONS, out);
- fputs(_(" -J, --json use JSON output format\n"), out);
- fputs(_(" -n, --noheadings don't print headings\n"), out);
- fputs(_(" -o, --output <list> output columns\n"), out);
- fputs(_(" --output-all output all columns\n"), out);
- fputs(_(" -r, --raw use raw output format\n"), out);
- fputs(_(" -t, --time <clock> show current time of single clock\n"), out);
+ fputs(_(" -J, --json use JSON output format\n"), out);
+ fputs(_(" -n, --noheadings don't print headings\n"), out);
+ fputs(_(" -o, --output <list> output columns\n"), out);
+ fputs(_(" --output-all output all columns\n"), out);
+ fputs(_(" -r, --raw use raw output format\n"), out);
+ fputs(_(" -t, --time <clock> show current time of single clock\n"), out);
+ fputs(_(" --no-discover-dynamic do not try to discover dynamic clocks\n"), out);
+ fputs(_(" -d, --dynamic-clock <path> also display specified dynamic clock\n"), out);
fputs(USAGE_SEPARATOR, out);
- printf(USAGE_HELP_OPTIONS(25));
+ printf(USAGE_HELP_OPTIONS(29));
fprintf(out, USAGE_COLUMNS);
@@ -249,38 +286,171 @@ static int64_t get_namespace_offset(const char *name)
return ret;
}
+static void add_clock_line(struct libscols_table *tb, const int *columns,
+ size_t ncolumns, const struct clockinfo *clockinfo)
+{
+ struct timespec resolution, now;
+ char buf[FORMAT_TIMESTAMP_MAX];
+ struct libscols_line *ln;
+ size_t i;
+ int rc;
+
+ ln = scols_table_new_line(tb, NULL);
+ if (!ln)
+ errx(EXIT_FAILURE, _("failed to allocate output line"));
+
+ /* outside the loop to guarantee consistency between COL_TIME and COL_ISO_TIME */
+ rc = clock_gettime(clockinfo->id, &now);
+ if (rc)
+ now.tv_nsec = -1;
+
+ rc = clock_getres(clockinfo->id, &resolution);
+ if (rc)
+ resolution.tv_nsec = -1;
+
+ for (i = 0; i < ncolumns; i++) {
+ switch (columns[i]) {
+ case COL_TYPE:
+ scols_line_set_data(ln, i, clock_type_name(clockinfo->type));
+ break;
+ case COL_ID:
+ if (CLOCKID_IS_DYNAMIC(clockinfo->id))
+ scols_line_asprintf(ln, i, "%ju", (uintmax_t) clockinfo->id);
+ break;
+ case COL_CLOCK:
+ scols_line_set_data(ln, i, clockinfo->id_name);
+ break;
+ case COL_NAME:
+ scols_line_set_data(ln, i, clockinfo->name);
+ break;
+ case COL_TIME:
+ if (now.tv_nsec == -1)
+ break;
+
+ scols_line_format_timespec(ln, i, &now);
+ break;
+ case COL_ISO_TIME:
+ if (now.tv_nsec == -1)
+ break;
+
+ rc = strtimespec_iso(&now,
+ ISO_GMTIME | ISO_DATE | ISO_TIME | ISO_T | ISO_DOTNSEC | ISO_TIMEZONE,
+ buf, sizeof(buf));
+ if (rc)
+ errx(EXIT_FAILURE, _("failed to format iso time"));
+ scols_line_set_data(ln, i, buf);
+ break;
+ case COL_RESOL:
+ if (resolution.tv_nsec == -1)
+ break;
+
+ rc = strtimespec_relative(&resolution, buf, sizeof(buf));
+ if (rc)
+ errx(EXIT_FAILURE, _("failed to format relative time"));
+ scols_line_set_data(ln, i, buf);
+ break;
+ case COL_RESOL_RAW:
+ if (resolution.tv_nsec == -1)
+ break;
+ scols_line_format_timespec(ln, i, &resolution);
+ break;
+ case COL_REL_TIME:
+ if (now.tv_nsec == -1)
+ break;
+ rc = strtimespec_relative(&now, buf, sizeof(buf));
+ if (rc)
+ errx(EXIT_FAILURE, _("failed to format relative time"));
+ scols_line_set_data(ln, i, buf);
+ break;
+ case COL_NS_OFFSET:
+ if (clockinfo->ns_offset_name)
+ scols_line_asprintf(ln, i, "%"PRId64,
+ get_namespace_offset(clockinfo->ns_offset_name));
+ break;
+ }
+ }
+}
+
+struct dynamic_clock {
+ struct list_head head;
+ const char * path;
+};
+
+static void add_dynamic_clock_from_path(struct libscols_table *tb,
+ const int *columns, size_t ncolumns,
+ const char *path, bool explicit)
+{
+ int fd = open(path, O_RDONLY);
+ if (fd == -1) {
+ if (explicit)
+ err(EXIT_FAILURE, _("Could not open %s"), path);
+ else
+ return;
+ }
+
+ struct clockinfo clockinfo = {
+ .type = CT_PTP,
+ .id = FD_TO_CLOCKID(fd),
+ .id_name = path,
+ .name = path,
+ };
+ add_clock_line(tb, columns, ncolumns, &clockinfo);
+ close(fd);
+}
+
+static void add_dynamic_clocks_from_discovery(struct libscols_table *tb,
+ const int *columns, size_t ncolumns)
+{
+ int rc;
+ size_t i;
+ glob_t state;
+
+ rc = glob("/dev/ptp*", 0, NULL, &state);
+ if (rc)
+ errx(EXIT_FAILURE, _("Could not glob: %d"), rc);
+
+ for (i = 0; i < state.gl_pathc; i++)
+ add_dynamic_clock_from_path(tb, columns, ncolumns,
+ state.gl_pathv[i], false);
+
+ globfree(&state);
+}
+
int main(int argc, char **argv)
{
- size_t i, j;
+ size_t i;
int c, rc;
const struct colinfo *colinfo;
- const struct clockinfo *clockinfo;
struct libscols_table *tb;
- struct libscols_line *ln;
struct libscols_column *col;
- bool noheadings = false, raw = false, json = false;
+ bool noheadings = false, raw = false, json = false, disc_dynamic = true;
const char *outarg = NULL;
int columns[ARRAY_SIZE(infos) * 2];
size_t ncolumns = 0;
clockid_t clock = -1;
+ struct dynamic_clock *dynamic_clock;
+ struct list_head *current_dynamic_clock;
+ struct list_head dynamic_clocks;
- struct timespec resolution, now;
- char buf[BUFSIZ];
+ struct timespec now;
enum {
- OPT_OUTPUT_ALL = CHAR_MAX + 1
+ OPT_OUTPUT_ALL = CHAR_MAX + 1,
+ OPT_NO_DISC_DYN,
};
static const struct option longopts[] = {
- { "noheadings", no_argument, NULL, 'n' },
- { "output", required_argument, NULL, 'o' },
- { "output-all", no_argument, NULL, OPT_OUTPUT_ALL },
- { "version", no_argument, NULL, 'V' },
- { "help", no_argument, NULL, 'h' },
- { "json", no_argument, NULL, 'J' },
- { "raw", no_argument, NULL, 'r' },
- { "time", required_argument, NULL, 't' },
+ { "noheadings", no_argument, NULL, 'n' },
+ { "output", required_argument, NULL, 'o' },
+ { "output-all", no_argument, NULL, OPT_OUTPUT_ALL },
+ { "version", no_argument, NULL, 'V' },
+ { "help", no_argument, NULL, 'h' },
+ { "json", no_argument, NULL, 'J' },
+ { "raw", no_argument, NULL, 'r' },
+ { "time", required_argument, NULL, 't' },
+ { "no-discover-dynamic", no_argument, NULL, OPT_NO_DISC_DYN },
+ { "dynamic-clock", required_argument, NULL, 'd' },
{ 0 }
};
@@ -289,7 +459,9 @@ int main(int argc, char **argv)
textdomain(PACKAGE);
close_stdout_atexit();
- while ((c = getopt_long(argc, argv, "no:Jrt:Vh", longopts, NULL)) != -1) {
+ INIT_LIST_HEAD(&dynamic_clocks);
+
+ while ((c = getopt_long(argc, argv, "no:Jrt:d:Vh", longopts, NULL)) != -1) {
switch (c) {
case 'n':
noheadings = true;
@@ -310,6 +482,14 @@ int main(int argc, char **argv)
case 't':
clock = parse_clock(optarg);
break;
+ case 'd':
+ dynamic_clock = xmalloc(sizeof(*dynamic_clock));
+ dynamic_clock->path = optarg;
+ list_add(&dynamic_clock->head, &dynamic_clocks);
+ break;
+ case OPT_NO_DISC_DYN:
+ disc_dynamic = false;
+ break;
case 'V':
print_version(EXIT_SUCCESS);
case 'h':
@@ -333,6 +513,7 @@ int main(int argc, char **argv)
if (!ncolumns) {
columns[ncolumns++] = COL_ID;
columns[ncolumns++] = COL_NAME;
+ columns[ncolumns++] = COL_TYPE;
columns[ncolumns++] = COL_TIME;
columns[ncolumns++] = COL_RESOL;
columns[ncolumns++] = COL_ISO_TIME;
@@ -359,81 +540,19 @@ int main(int argc, char **argv)
scols_column_set_json_type(col, colinfo->json_type);
}
- for (i = 0; i < ARRAY_SIZE(clocks); i++) {
- clockinfo = &clocks[i];
-
- ln = scols_table_new_line(tb, NULL);
- if (!ln)
- errx(EXIT_FAILURE, _("failed to allocate output line"));
-
- /* outside the loop to guarantee consistency between COL_TIME and COL_ISO_TIME */
- rc = clock_gettime(clockinfo->id, &now);
- if (rc)
- now.tv_nsec = -1;
+ for (i = 0; i < ARRAY_SIZE(clocks); i++)
+ add_clock_line(tb, columns, ncolumns, &clocks[i]);
- rc = clock_getres(clockinfo->id, &resolution);
- if (rc)
- resolution.tv_nsec = -1;
+ if (disc_dynamic)
+ add_dynamic_clocks_from_discovery(tb, columns, ncolumns);
- for (j = 0; j < ncolumns; j++) {
- switch (columns[j]) {
- case COL_ID:
- scols_line_asprintf(ln, j, "%ju", (uintmax_t) clockinfo->id);
- break;
- case COL_CLOCK:
- scols_line_set_data(ln, j, clockinfo->id_name);
- break;
- case COL_NAME:
- scols_line_set_data(ln, j, clockinfo->name);
- break;
- case COL_TIME:
- if (now.tv_nsec == -1)
- break;
-
- scols_line_format_timespec(ln, j, &now);
- break;
- case COL_ISO_TIME:
- if (now.tv_nsec == -1)
- break;
-
- rc = strtimespec_iso(&now,
- ISO_GMTIME | ISO_DATE | ISO_TIME | ISO_T | ISO_DOTNSEC | ISO_TIMEZONE,
- buf, sizeof(buf));
- if (rc)
- errx(EXIT_FAILURE, _("failed to format iso time"));
- scols_line_set_data(ln, j, buf);
- break;
- case COL_RESOL:
- if (resolution.tv_nsec == -1)
- break;
-
- rc = strtimespec_relative(&resolution, buf, sizeof(buf));
- if (rc)
- errx(EXIT_FAILURE, _("failed to format relative time"));
- scols_line_set_data(ln, j, buf);
- break;
- case COL_RESOL_RAW:
- if (resolution.tv_nsec == -1)
- break;
- scols_line_format_timespec(ln, j, &resolution);
- break;
- case COL_REL_TIME:
- if (now.tv_nsec == -1)
- break;
- rc = strtimespec_relative(&now, buf, sizeof(buf));
- if (rc)
- errx(EXIT_FAILURE, _("failed to format relative time"));
- scols_line_set_data(ln, j, buf);
- break;
- case COL_NS_OFFSET:
- if (clockinfo->ns_offset_name)
- scols_line_asprintf(ln, j, "%"PRId64,
- get_namespace_offset(clockinfo->ns_offset_name));
- break;
- }
- }
+ list_for_each(current_dynamic_clock, &dynamic_clocks) {
+ dynamic_clock = list_entry(current_dynamic_clock, struct dynamic_clock, head);
+ add_dynamic_clock_from_path(tb, columns, ncolumns, dynamic_clock->path, true);
}
+ list_free(&dynamic_clocks, struct dynamic_clock, head, free);
+
scols_table_enable_json(tb, json);
scols_table_enable_raw(tb, raw);
scols_table_enable_noheadings(tb, noheadings);
diff --git a/misc-utils/lsfd.1.adoc b/misc-utils/lsfd.1.adoc
index 720be374f0..b2a6aa5322 100644
--- a/misc-utils/lsfd.1.adoc
+++ b/misc-utils/lsfd.1.adoc
@@ -70,7 +70,7 @@ and *-p* option, e.g. -p 1, may print the same output but using *-p*
option is much more efficient because *-p* option works at a much earlier
stage of processing than the *-Q* option.
-*-i*[4|6], *--inet*[=4|6]::
+*-i*[4|6], *--inet*[=4|=6]::
List only IPv4 sockets and/or IPv6 sockets.
*-Q*, *--filter* _expr_::
@@ -110,6 +110,9 @@ only for *lsfd* developers.
*--dump-counters*::
Dump the definition of counters used in *--summary* output.
+*-H*, *--list-columns*::
+List available columns that you can specify at *--output* option.
+
include::man-common/help-version.adoc[]
== OUTPUT COLUMNS
diff --git a/misc-utils/lsfd.c b/misc-utils/lsfd.c
index 4a7bb5c57c..bc7f901d48 100644
--- a/misc-utils/lsfd.c
+++ b/misc-utils/lsfd.c
@@ -353,7 +353,7 @@ static const struct colinfo infos[] = {
N_("user of the process") },
[COL_XMODE] = { "XMODE",
0, SCOLS_FL_RIGHT, SCOLS_JSON_STRING,
- N_("access mode and more (rwx)") },
+ N_("extended version of MDOE (rwxD[Ll]m)") },
};
static const int default_columns[] = {
@@ -1578,45 +1578,62 @@ static void collect_processes(struct lsfd_control *ctl, const pid_t pids[], int
ul_unref_path(pc);
}
+static void __attribute__((__noreturn__)) list_colunms(FILE *out)
+{
+ fprintf(out, USAGE_COLUMNS);
+ for (size_t i = 0; i < ARRAY_SIZE(infos); i++)
+ fprintf(out, " %20s %-10s%s\n", infos[i].name,
+ infos[i].json_type == SCOLS_JSON_STRING? "<string>":
+ infos[i].json_type == SCOLS_JSON_ARRAY_STRING? "<string>":
+ infos[i].json_type == SCOLS_JSON_ARRAY_NUMBER? "<string>":
+ infos[i].json_type == SCOLS_JSON_NUMBER? "<number>":
+ "<boolean>",
+ _(infos[i].help));
+ exit(EXIT_SUCCESS);
+}
+
+static void print_columns(FILE *out, const char *prefix, const int cols[], size_t n_cols)
+{
+ fprintf(out, "%15s: ", prefix);
+ for (size_t i = 0; i < n_cols; i++) {
+ if (i)
+ fputc(',', out);
+ fputs(infos[cols[i]].name, out);
+ }
+ fputc('\n', out);
+}
+
static void __attribute__((__noreturn__)) usage(void)
{
FILE *out = stdout;
- size_t i;
fputs(USAGE_HEADER, out);
fprintf(out, _(" %s [options]\n"), program_invocation_short_name);
fputs(USAGE_OPTIONS, out);
- fputs(_(" -l, --threads list in threads level\n"), out);
- fputs(_(" -J, --json use JSON output format\n"), out);
- fputs(_(" -n, --noheadings don't print headings\n"), out);
- fputs(_(" -o, --output <list> output columns\n"), out);
- fputs(_(" -r, --raw use raw output format\n"), out);
- fputs(_(" -u, --notruncate don't truncate text in columns\n"), out);
- fputs(_(" -p, --pid <pid(s)> collect information only specified processes\n"), out);
- fputs(_(" -i[4|6], --inet[=4|6] list only IPv4 and/or IPv6 sockets\n"), out);
- fputs(_(" -Q, --filter <expr> apply display filter\n"), out);
- fputs(_(" --debug-filter dump the internal data structure of filter and exit\n"), out);
- fputs(_(" -C, --counter <name>:<expr>\n"
- " define custom counter for --summary output\n"), out);
- fputs(_(" --dump-counters dump counter definitions\n"), out);
- fputs(_(" --summary[=<when>] print summary information (only, append, or never)\n"), out);
+ fputs(_(" -l, --threads list in threads level\n"), out);
+ fputs(_(" -J, --json use JSON output format\n"), out);
+ fputs(_(" -n, --noheadings don't print headings\n"), out);
+ fputs(_(" -o, --output <list> output columns\n"), out);
+ fputs(_(" -r, --raw use raw output format\n"), out);
+ fputs(_(" -u, --notruncate don't truncate text in columns\n"), out);
+ fputs(_(" -p, --pid <pid(s)> collect information only specified processes\n"), out);
+ fputs(_(" -i[4|6], --inet[=4|=6] list only IPv4 and/or IPv6 sockets\n"), out);
+ fputs(_(" -Q, --filter <expr> apply display filter\n"), out);
+ fputs(_(" --debug-filter dump the internal data structure of filter and exit\n"), out);
+ fputs(_(" -C, --counter <name>:<expr> define custom counter for --summary output\n"), out);
+ fputs(_(" --dump-counters dump counter definitions\n"), out);
+ fputs(_(" --summary[=<when>] print summary information (only, append, or never)\n"), out);
fputs(USAGE_SEPARATOR, out);
- printf(USAGE_HELP_OPTIONS(30));
-
- fprintf(out, USAGE_COLUMNS);
+ fputs(_(" -H, --list-columns list the available columns\n"), out);
+ fprintf(out, USAGE_HELP_OPTIONS(30));
- for (i = 0; i < ARRAY_SIZE(infos); i++)
- fprintf(out, " %16s %-10s%s\n", infos[i].name,
- infos[i].json_type == SCOLS_JSON_STRING? "<string>":
- infos[i].json_type == SCOLS_JSON_ARRAY_STRING? "<string>":
- infos[i].json_type == SCOLS_JSON_ARRAY_NUMBER? "<string>":
- infos[i].json_type == SCOLS_JSON_NUMBER? "<number>":
- "<boolean>",
- _(infos[i].help));
+ fputs(USAGE_DEFAULT_COLUMNS, out);
+ print_columns(out, _("Default"), default_columns, ARRAY_SIZE(default_columns));
+ print_columns(out, _("With --threads"), default_threads_columns, ARRAY_SIZE(default_threads_columns));
- printf(USAGE_MAN_TAIL("lsfd(1)"));
+ fprintf(out, USAGE_MAN_TAIL("lsfd(1)"));
exit(EXIT_SUCCESS);
}
@@ -1927,6 +1944,7 @@ int main(int argc, char *argv[])
{ "summary", optional_argument, NULL, OPT_SUMMARY },
{ "counter", required_argument, NULL, 'C' },
{ "dump-counters",no_argument, NULL, OPT_DUMP_COUNTERS },
+ { "list-columns",no_argument, NULL, 'H' },
{ NULL, 0, NULL, 0 },
};
@@ -1935,7 +1953,7 @@ int main(int argc, char *argv[])
textdomain(PACKAGE);
close_stdout_atexit();
- while ((c = getopt_long(argc, argv, "no:JrVhluQ:p:i::C:s", longopts, NULL)) != -1) {
+ while ((c = getopt_long(argc, argv, "no:JrVhluQ:p:i::C:sH", longopts, NULL)) != -1) {
switch (c) {
case 'n':
ctl.noheadings = 1;
@@ -2007,6 +2025,8 @@ int main(int argc, char *argv[])
print_version(EXIT_SUCCESS);
case 'h':
usage();
+ case 'H':
+ list_colunms(stdout);
default:
errtryhelp(EXIT_FAILURE);
}
diff --git a/tests/expected/blkid/low-probe-bcachefs b/tests/expected/blkid/low-probe-bcachefs
index 70fddbee8e..510ec89448 100644
--- a/tests/expected/blkid/low-probe-bcachefs
+++ b/tests/expected/blkid/low-probe-bcachefs
@@ -9,4 +9,4 @@ ID_FS_UUID=46bd306f-80ad-4cd0-af4f-147e7d85f393
ID_FS_UUID_ENC=46bd306f-80ad-4cd0-af4f-147e7d85f393
ID_FS_UUID_SUB=72a60ede-4cb6-4374-aa70-cb38a50af5ef
ID_FS_UUID_SUB_ENC=72a60ede-4cb6-4374-aa70-cb38a50af5ef
-ID_FS_VERSION=13
+ID_FS_VERSION=0.13
diff --git a/tests/expected/blkid/low-probe-bcachefs-2 b/tests/expected/blkid/low-probe-bcachefs-2
index 4a6d664c09..b6e220ea0a 100644
--- a/tests/expected/blkid/low-probe-bcachefs-2
+++ b/tests/expected/blkid/low-probe-bcachefs-2
@@ -9,4 +9,4 @@ ID_FS_UUID=4fa11b1e-75e6-4210-9167-34e1769c0fe1
ID_FS_UUID_ENC=4fa11b1e-75e6-4210-9167-34e1769c0fe1
ID_FS_UUID_SUB=0a3643b7-c515-47f8-a0ea-91fc38d043d1
ID_FS_UUID_SUB_ENC=0a3643b7-c515-47f8-a0ea-91fc38d043d1
-ID_FS_VERSION=26
+ID_FS_VERSION=0.26
diff --git a/tests/expected/misc/lsclocks-basic b/tests/expected/misc/lsclocks-basic
index b3b25f4a63..1b375b83c1 100644
--- a/tests/expected/misc/lsclocks-basic
+++ b/tests/expected/misc/lsclocks-basic
@@ -1,10 +1,10 @@
-ID CLOCK NAME
- 0 CLOCK_REALTIME realtime
- 1 CLOCK_MONOTONIC monotonic
- 4 CLOCK_MONOTONIC_RAW monotonic-raw
- 5 CLOCK_REALTIME_COARSE realtime-coarse
- 6 CLOCK_MONOTONIC_COARSE monotonic-coarse
- 7 CLOCK_BOOTTIME boottime
- 8 CLOCK_REALTIME_ALARM realtime-alarm
- 9 CLOCK_BOOTTIME_ALARM boottime-alarm
-11 CLOCK_TAI tai
+TYPE ID CLOCK NAME
+sys 0 CLOCK_REALTIME realtime
+sys 1 CLOCK_MONOTONIC monotonic
+sys 4 CLOCK_MONOTONIC_RAW monotonic-raw
+sys 5 CLOCK_REALTIME_COARSE realtime-coarse
+sys 6 CLOCK_MONOTONIC_COARSE monotonic-coarse
+sys 7 CLOCK_BOOTTIME boottime
+sys 8 CLOCK_REALTIME_ALARM realtime-alarm
+sys 9 CLOCK_BOOTTIME_ALARM boottime-alarm
+sys 11 CLOCK_TAI tai
diff --git a/tests/expected/misc/lsclocks-dynamic b/tests/expected/misc/lsclocks-dynamic
new file mode 100644
index 0000000000..156ee3f8d8
--- /dev/null
+++ b/tests/expected/misc/lsclocks-dynamic
@@ -0,0 +1 @@
+ptp /dev/ptp0 /dev/ptp0
diff --git a/tests/ts/misc/lsclocks b/tests/ts/misc/lsclocks
index 55ee4df40e..48cd7d9092 100755
--- a/tests/ts/misc/lsclocks
+++ b/tests/ts/misc/lsclocks
@@ -29,7 +29,7 @@ mask_timestamps() {
ts_init_subtest basic
-"$TS_CMD_LSCLOCKS" -o ID,CLOCK,NAME > "$TS_OUTPUT" 2>> "$TS_ERRLOG"
+"$TS_CMD_LSCLOCKS" --no-discover-dynamic -o TYPE,ID,CLOCK,NAME > "$TS_OUTPUT" 2>> "$TS_ERRLOG"
ts_finalize_subtest
@@ -39,4 +39,14 @@ ts_init_subtest time
ts_finalize_subtest
+ts_init_subtest dynamic
+
+if [ -c /dev/ptp0 ] && [ -r /dev/ptp0 ]; then
+ "$TS_CMD_LSCLOCKS" --no-discover-dynamic --dynamic-clock /dev/ptp0 --output TYPE,ID,CLOCK,NAME \
+ | tail -1 > "$TS_OUTPUT" 2>> "$TS_ERRLOG"
+ ts_finalize_subtest
+else
+ ts_skip_subtest "/dev/ptp0 not usable"
+fi
+
ts_finalize