]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
process-util: introduce get_process_cmdline_strv()
authorYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 22 Mar 2023 16:05:38 +0000 (01:05 +0900)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Tue, 28 Mar 2023 15:09:15 +0000 (17:09 +0200)
The reason why get_process_cmdline() is so complicated is that we
need to escape and quote arguments for building a single result
string.

That's necessary when we want to log or print the command line.
However, when we want to parse the command line, it is not necessary
that the result is a single string, but can be strv.

This will be used when we parse the command line.

src/basic/process-util.c
src/basic/process-util.h
src/test/test-process-util.c

index c891f74be8fea9eb2c76c5c2c511f28d5f6627a5..58503cf22dc2ad7f30246834b455ef7945267cd8 100644 (file)
@@ -253,6 +253,28 @@ int get_process_cmdline(pid_t pid, size_t max_columns, ProcessCmdlineFlags flags
         return 0;
 }
 
+int get_process_cmdline_strv(pid_t pid, ProcessCmdlineFlags flags, char ***ret) {
+        _cleanup_free_ char *t = NULL;
+        char **args;
+        size_t k;
+        int r;
+
+        assert(pid >= 0);
+        assert((flags & ~PROCESS_CMDLINE_COMM_FALLBACK) == 0);
+        assert(ret);
+
+        r = get_process_cmdline_nulstr(pid, SIZE_MAX, flags, &t, &k);
+        if (r < 0)
+                return r;
+
+        args = strv_parse_nulstr_full(t, k, /* drop_trailing_nuls = */ true);
+        if (!args)
+                return -ENOMEM;
+
+        *ret = args;
+        return 0;
+}
+
 int container_get_leader(const char *machine, pid_t *pid) {
         _cleanup_free_ char *s = NULL, *class = NULL;
         const char *p;
index 6f6fc7d94e7111f0a39b1630daacd44c16075703..5188f3c60584c5f11096f21bf7dc95753ac37905 100644 (file)
@@ -40,6 +40,7 @@ typedef enum ProcessCmdlineFlags {
 
 int get_process_comm(pid_t pid, char **ret);
 int get_process_cmdline(pid_t pid, size_t max_columns, ProcessCmdlineFlags flags, char **ret);
+int get_process_cmdline_strv(pid_t pid, ProcessCmdlineFlags flags, char ***ret);
 int get_process_exe(pid_t pid, char **ret);
 int get_process_uid(pid_t pid, uid_t *ret);
 int get_process_gid(pid_t pid, gid_t *ret);
index fc0d25ea2b7002e9b71f5078d89e1d7ae0adebf7..b90b8921926e3c15e06333454e8a8794c20caaeb 100644 (file)
@@ -112,7 +112,8 @@ TEST(get_process_comm) {
 }
 
 static void test_get_process_cmdline_one(pid_t pid) {
-        _cleanup_free_ char *c = NULL, *d = NULL, *e = NULL, *f = NULL, *g = NULL, *h = NULL;
+        _cleanup_free_ char *c = NULL, *d = NULL, *e = NULL, *f = NULL, *g = NULL, *h = NULL, *joined = NULL;
+        _cleanup_strv_free_ char **strv_a = NULL, **strv_b = NULL;
         int r;
 
         r = get_process_cmdline(pid, SIZE_MAX, 0, &c);
@@ -132,6 +133,18 @@ static void test_get_process_cmdline_one(pid_t pid) {
 
         r = get_process_cmdline(pid, SIZE_MAX, PROCESS_CMDLINE_QUOTE_POSIX | PROCESS_CMDLINE_COMM_FALLBACK, &h);
         log_info("      %s", r >= 0 ? h : errno_to_name(r));
+
+        r = get_process_cmdline_strv(pid, 0, &strv_a);
+        if (r >= 0)
+                assert_se(joined = strv_join(strv_a, "\", \""));
+        log_info("      \"%s\"", r >= 0 ? joined : errno_to_name(r));
+
+        joined = mfree(joined);
+
+        r = get_process_cmdline_strv(pid, PROCESS_CMDLINE_COMM_FALLBACK, &strv_b);
+        if (r >= 0)
+                assert_se(joined = strv_join(strv_b, "\", \""));
+        log_info("      \"%s\"", r >= 0 ? joined : errno_to_name(r));
 }
 
 TEST(get_process_cmdline) {
@@ -244,6 +257,7 @@ TEST(get_process_cmdline_harder) {
         char path[] = "/tmp/test-cmdlineXXXXXX";
         _cleanup_close_ int fd = -EBADF;
         _cleanup_free_ char *line = NULL;
+        _cleanup_strv_free_ char **args = NULL;
         pid_t pid;
         int r;
 
@@ -358,6 +372,10 @@ TEST(get_process_cmdline_harder) {
         assert_se(streq(line, "[testa]"));
         line = mfree(line);
 
+        assert_se(get_process_cmdline_strv(0, PROCESS_CMDLINE_COMM_FALLBACK, &args) >= 0);
+        assert_se(strv_equal(args, STRV_MAKE("[testa]")));
+        args = strv_free(args);
+
         /* Test with multiple arguments that don't require quoting */
 
         assert_se(write(fd, "foo\0bar", 8) == 8);
@@ -371,6 +389,10 @@ TEST(get_process_cmdline_harder) {
         assert_se(streq(line, "foo bar"));
         line = mfree(line);
 
+        assert_se(get_process_cmdline_strv(0, PROCESS_CMDLINE_COMM_FALLBACK, &args) >= 0);
+        assert_se(strv_equal(args, STRV_MAKE("foo", "bar")));
+        args = strv_free(args);
+
         assert_se(write(fd, "quux", 4) == 4);
         assert_se(get_process_cmdline(0, SIZE_MAX, 0, &line) >= 0);
         log_debug("'%s'", line);
@@ -457,6 +479,10 @@ TEST(get_process_cmdline_harder) {
         assert_se(streq(line, "foo bar quux"));
         line = mfree(line);
 
+        assert_se(get_process_cmdline_strv(0, PROCESS_CMDLINE_COMM_FALLBACK, &args) >= 0);
+        assert_se(strv_equal(args, STRV_MAKE("foo", "bar", "quux")));
+        args = strv_free(args);
+
         assert_se(ftruncate(fd, 0) >= 0);
         assert_se(prctl(PR_SET_NAME, "aaaa bbbb cccc") >= 0);
 
@@ -482,11 +508,17 @@ TEST(get_process_cmdline_harder) {
         assert_se(streq(line, "[aaaa bbbb …"));
         line = mfree(line);
 
+        assert_se(get_process_cmdline_strv(0, PROCESS_CMDLINE_COMM_FALLBACK, &args) >= 0);
+        assert_se(strv_equal(args, STRV_MAKE("[aaaa bbbb cccc]")));
+        args = strv_free(args);
+
         /* Test with multiple arguments that do require quoting */
 
 #define CMDLINE1 "foo\0'bar'\0\"bar$\"\0x y z\0!``\0"
 #define EXPECT1  "foo \"'bar'\" \"\\\"bar\\$\\\"\" \"x y z\" \"!\\`\\`\""
-#define EXPECT1p  "foo $'\\'bar\\'' $'\"bar$\"' $'x y z' $'!``'"
+#define EXPECT1p "foo $'\\'bar\\'' $'\"bar$\"' $'x y z' $'!``'"
+#define EXPECT1v STRV_MAKE("foo", "'bar'", "\"bar$\"", "x y z", "!``")
+
         assert_se(lseek(fd, SEEK_SET, 0) == 0);
         assert_se(write(fd, CMDLINE1, sizeof CMDLINE1) == sizeof CMDLINE1);
         assert_se(ftruncate(fd, sizeof CMDLINE1) == 0);
@@ -503,9 +535,15 @@ TEST(get_process_cmdline_harder) {
         assert_se(streq(line, EXPECT1p));
         line = mfree(line);
 
+        assert_se(get_process_cmdline_strv(0, 0, &args) >= 0);
+        assert_se(strv_equal(args, EXPECT1v));
+        args = strv_free(args);
+
 #define CMDLINE2 "foo\0\1\2\3\0\0"
 #define EXPECT2  "foo \"\\001\\002\\003\""
-#define EXPECT2p  "foo $'\\001\\002\\003'"
+#define EXPECT2p "foo $'\\001\\002\\003'"
+#define EXPECT2v STRV_MAKE("foo", "\1\2\3")
+
         assert_se(lseek(fd, SEEK_SET, 0) == 0);
         assert_se(write(fd, CMDLINE2, sizeof CMDLINE2) == sizeof CMDLINE2);
         assert_se(ftruncate(fd, sizeof CMDLINE2) == 0);
@@ -522,6 +560,10 @@ TEST(get_process_cmdline_harder) {
         assert_se(streq(line, EXPECT2p));
         line = mfree(line);
 
+        assert_se(get_process_cmdline_strv(0, 0, &args) >= 0);
+        assert_se(strv_equal(args, EXPECT2v));
+        args = strv_free(args);
+
         safe_close(fd);
         _exit(EXIT_SUCCESS);
 }