]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
basic/fileio: clean up executable_is_script() a bit 35559/head
authorMike Yuan <me@yhndnzj.com>
Tue, 10 Dec 2024 15:14:34 +0000 (16:14 +0100)
committerMike Yuan <me@yhndnzj.com>
Wed, 11 Dec 2024 18:11:22 +0000 (19:11 +0100)
- Rename to script_get_shebang_interpreter and return
  -EMEDIUMTYPE if the executable is not a script.
  We nowadays utilize the scheme of making ret param
  of getters optional, and use them directly as checkers.
- Don't unnecessarily read the whole line, but check
  only the shebang first.

src/basic/fileio.c
src/basic/fileio.h
src/journal/journalctl-filter.c
src/test/test-fileio.c

index 8cf7f21b6bbf3ea7ce709f1e67bcb4c8690d7e6a..9f2bbc13236d9699da0fc9bb6b2514e69624560f 100644 (file)
@@ -14,6 +14,7 @@
 
 #include "alloc-util.h"
 #include "chase.h"
+#include "extract-word.h"
 #include "fd-util.h"
 #include "fileio.h"
 #include "fs-util.h"
@@ -856,35 +857,49 @@ int read_full_file_full(
         return read_full_stream_full(f, filename, offset, size, flags, ret_contents, ret_size);
 }
 
-int executable_is_script(const char *path, char **interpreter) {
-        _cleanup_free_ char *line = NULL;
-        size_t len;
-        char *ans;
+int script_get_shebang_interpreter(const char *path, char **ret) {
+        _cleanup_fclose_ FILE *f = NULL;
         int r;
 
         assert(path);
 
-        r = read_one_line_file(path, &line);
-        if (r == -ENOBUFS) /* First line overly long? if so, then it's not a script */
-                return 0;
+        f = fopen(path, "re");
+        if (!f)
+                return -errno;
+
+        char c;
+        r = safe_fgetc(f, &c);
         if (r < 0)
                 return r;
+        if (r == 0)
+                return -EBADMSG;
+        if (c != '#')
+                return -EMEDIUMTYPE;
+        r = safe_fgetc(f, &c);
+        if (r < 0)
+                return r;
+        if (r == 0)
+                return -EBADMSG;
+        if (c != '!')
+                return -EMEDIUMTYPE;
 
-        if (!startswith(line, "#!"))
-                return 0;
-
-        ans = strstrip(line + 2);
-        len = strcspn(ans, " \t");
+        _cleanup_free_ char *line = NULL;
+        r = read_line(f, LONG_LINE_MAX, &line);
+        if (r < 0)
+                return r;
 
-        if (len == 0)
-                return 0;
+        _cleanup_free_ char *p = NULL;
+        const char *s = line;
 
-        ans = strndup(ans, len);
-        if (!ans)
-                return -ENOMEM;
+        r = extract_first_word(&s, &p, /* separators = */ NULL, /* flags = */ 0);
+        if (r < 0)
+                return r;
+        if (r == 0)
+                return -ENOEXEC;
 
-        *interpreter = ans;
-        return 1;
+        if (ret)
+                *ret = TAKE_PTR(p);
+        return 0;
 }
 
 /**
index 29518d201eec273104954f586e13cf1ca667a48b..bd053050e1a7d0717f86c9c4c5c73fe80d222082 100644 (file)
@@ -94,7 +94,7 @@ static inline int verify_file(const char *fn, const char *blob, bool accept_extr
         return verify_file_at(AT_FDCWD, fn, blob, accept_extra_nl);
 }
 
-int executable_is_script(const char *path, char **interpreter);
+int script_get_shebang_interpreter(const char *path, char **ret);
 
 int get_proc_field(const char *filename, const char *pattern, const char *terminator, char **field);
 
index 1c6348574c5f0cfead6351c1903eb380c3dc3984..378e90b3654fda94b01049883259927fb38b922b 100644 (file)
@@ -317,7 +317,7 @@ static int add_matches_for_executable(sd_journal *j, const char *path) {
         assert(j);
         assert(path);
 
-        if (executable_is_script(path, &interpreter) > 0) {
+        if (script_get_shebang_interpreter(path, &interpreter) >= 0) {
                 _cleanup_free_ char *comm = NULL;
 
                 r = path_extract_filename(path, &comm);
@@ -329,15 +329,16 @@ static int add_matches_for_executable(sd_journal *j, const char *path) {
                         return log_error_errno(r, "Failed to add match: %m");
 
                 /* Append _EXE only if the interpreter is not a link. Otherwise, it might be outdated often. */
-                path = is_symlink(interpreter) > 0 ? interpreter : NULL;
-        }
+                if (is_symlink(interpreter) > 0)
+                        return 0;
 
-        if (path) {
-                r = journal_add_match_pair(j, "_EXE", path);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to add match: %m");
+                path = interpreter;
         }
 
+        r = journal_add_match_pair(j, "_EXE", path);
+        if (r < 0)
+                return log_error_errno(r, "Failed to add match: %m");
+
         return 0;
 }
 
index 7c222b09327eaf54d82d22c628fbc978a93ab306..76f55983258a6886602e1d7598b5d2aa58251b2e 100644 (file)
@@ -311,26 +311,22 @@ TEST(merge_env_file_invalid) {
         assert_se(strv_isempty(a));
 }
 
-TEST(executable_is_script) {
+TEST(script_get_shebang_interpreter) {
         _cleanup_(unlink_tempfilep) char t[] = "/tmp/test-fileio-XXXXXX";
         _cleanup_fclose_ FILE *f = NULL;
         char *command;
-        int r;
 
         assert_se(fmkostemp_safe(t, "w", &f) == 0);
         fputs("#! /bin/script -a -b \ngoo goo", f);
         fflush(f);
 
-        r = executable_is_script(t, &command);
-        assert_se(r > 0);
+        ASSERT_OK(script_get_shebang_interpreter(t, &command));
         ASSERT_STREQ(command, "/bin/script");
         free(command);
 
-        r = executable_is_script("/bin/sh", &command);
-        assert_se(r == 0);
+        ASSERT_ERROR(script_get_shebang_interpreter("/bin/sh", NULL), EMEDIUMTYPE);
 
-        r = executable_is_script("/usr/bin/yum", &command);
-        if (r > 0) {
+        if (script_get_shebang_interpreter("/usr/bin/yum", &command) >= 0) {
                 assert_se(startswith(command, "/"));
                 free(command);
         }