]> git.ipfire.org Git - pakfire.git/commitdiff
file: Replace /usr/bin/env with the absolute path if possible
authorMichael Tremer <michael.tremer@ipfire.org>
Thu, 25 May 2023 13:32:30 +0000 (13:32 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Thu, 25 May 2023 13:32:30 +0000 (13:32 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/libpakfire/file.c
src/libpakfire/include/pakfire/util.h
src/libpakfire/util.c

index 663c2e38ff57ad522d85bd706e0efd3aaefc00e8..f308ea02cccb2b4ec173fcd0db2e2f3c3e000705 100644 (file)
@@ -1253,7 +1253,7 @@ static int pakfire_file_levels(struct pakfire_file* file) {
 }
 
 FILE* pakfire_file_open(struct pakfire_file* file) {
-       FILE* f = fopen(file->abspath, "r");
+       FILE* f = fopen(file->abspath, "r+");
        if (!f)
                ERROR(file->pakfire, "Could not open %s: %m\n", file->abspath);
 
@@ -2519,6 +2519,133 @@ ERROR:
        return r;
 }
 
+static int pakfire_file_fix_interpreter(struct pakfire_file* file, const char* interpreter) {
+       FILE* f = NULL;
+       char path[PATH_MAX];
+       int r;
+
+       char* data = NULL;
+       size_t length = 0;
+
+       DEBUG(file->pakfire, "%s: Fixing interpreter %s\n", file->path, interpreter);
+
+       // Open the file
+       f = pakfire_file_open(file);
+       if (!f) {
+               ERROR(file->pakfire, "Could not open %s: %m\n", file->path);
+               r = 1;
+               goto ERROR;
+       }
+
+       // Read the entire content into the buffer
+       r = pakfire_read_file_into_buffer(f, &data, &length);
+       if (r) {
+               ERROR(file->pakfire, "Could not read file into memory: %m\n");
+               goto ERROR;
+       }
+
+       // Find the end of the first line
+       char* eol = memchr(data, '\n', length);
+       if (!eol) {
+               DEBUG(file->pakfire, "Could not find the end of the first line\n");
+               errno = EINVAL;
+               r = 0;
+               goto ERROR;
+       }
+
+       // Terminate the first line
+       *eol = '\0';
+
+       // Pointer to the beginning of the first line
+       char* p = data;
+
+       // Pointer to the beginning of the rest of the script
+       const char* rest = eol + 1;
+
+       DEBUG(file->pakfire, "First line: %s\n", p);
+
+       // Read shebang
+       if (pakfire_string_startswith(p, "#!")) {
+               p += 2;
+       } else {
+               ERROR(file->pakfire, "%s: Could not find shebang\n", file->path);
+               errno = EINVAL;
+               r = 1;
+               goto ERROR;
+       }
+
+       // Consume any whitespace
+       while (isspace(*p))
+               p++;
+
+       // Consume the old interpreter
+       while (!isspace(*p))
+               p++;
+
+       // Consume any whitespace
+       while (isspace(*p))
+               p++;
+
+       // The command begins here
+       const char* command = p;
+
+       // Find the end of the command
+       while (!isspace(*p))
+               p++;
+
+       // Terminate the command
+       *p++ = '\0';
+
+       DEBUG(file->pakfire, "%s: Found command: %s\n", file->path, command);
+
+       // Find the absolute path to the command
+       r = pakfire_which(file->pakfire, path, command);
+       if (r) {
+               DEBUG(file->pakfire, "%s: Could not resolve command %s: %m\n", file->path, command);
+               goto ERROR;
+       }
+
+       // If we could not resolve the command, this file has an invalid interpreter
+       if (!*path) {
+               file->issues |= PAKFIRE_FILE_INVALID_INTERPRETER;
+               r = 0;
+               goto ERROR;
+       }
+
+       // Go back to the beginning of the file
+       rewind(f);
+
+       // Write shebang
+       r = fprintf(f, (*p) ? "#!%s %s\n" : "#!%s\n", path, p);
+       if (r < 0) {
+               ERROR(file->pakfire, "%s: Could not write back first line: %m\n", file->path);
+               r = 1;
+               goto ERROR;
+       }
+
+       // Determine the length of the payload
+       length -= rest - data;
+
+       // Write the rest
+       size_t bytes_written = fwrite(rest, 1, length, f);
+       if (bytes_written < length) {
+               ERROR(file->pakfire, "%s: Could not write the payload: %m\n", file->path);
+               r = 1;
+               goto ERROR;
+       }
+
+       // Success!
+       r = 0;
+
+ERROR:
+       if (data)
+               free(data);
+       if (f)
+               fclose(f);
+
+       return r;
+}
+
 static int pakfire_file_check_interpreter(struct pakfire_file* file) {
        char* interpreter = NULL;
        int r;
@@ -2542,15 +2669,20 @@ static int pakfire_file_check_interpreter(struct pakfire_file* file) {
        else if (pakfire_string_startswith(interpreter, "/usr/local/"))
                file->issues |= PAKFIRE_FILE_INVALID_INTERPRETER;
 
-       // We don't support "env"
-       else if (strcmp(interpreter, "/usr/bin/env") == 0)
-               file->issues |= PAKFIRE_FILE_INVALID_INTERPRETER;
+       // We don't support "env", but will automatically fix it
+       else if (strcmp(interpreter, "/usr/bin/env") == 0) {
+               r = pakfire_file_fix_interpreter(file, interpreter);
+               if (r) {
+                       ERROR(file->pakfire, "%s: Could not fix interpreter: %m\n", file->path);
+                       goto ERROR;
+               }
+       }
 
-       // Cleanup
+ERROR:
        if (interpreter)
                free(interpreter);
 
-       return 0;
+       return r;
 }
 
 static int pakfire_file_check_capabilities(struct pakfire_file* file) {
index af56678e3d87ca6bdddab359f19adf88cc608599..d9a1505d53646cc3348b18b386d034def9d6de1f 100644 (file)
@@ -84,6 +84,10 @@ FILE* pakfire_mktemp(char* path, const mode_t mode);
 char* pakfire_mkdtemp(char* path);
 int pakfire_rmtree(const char* path, int flags);
 
+#define pakfire_which(pakfire, path, what) \
+       __pakfire_which(pakfire, path, sizeof(path), what)
+int __pakfire_which(struct pakfire* pakfire, char* path, const size_t length, const char* what);
+
 char* pakfire_generate_uuid(void);
 
 int pakfire_tty_is_noninteractive(void);
index 12a8666e316986bce63c3ff9dbc857fe8ecd5d6a..79cd196b1b4612de5483f793a8f45ea8f0afd890 100644 (file)
@@ -660,6 +660,46 @@ int pakfire_rmtree(const char* path, int flags) {
        return r;
 }
 
+int __pakfire_which(struct pakfire* pakfire, char* path, const size_t length,
+               const char* what) {
+       char buffer[PATH_MAX];
+       int r;
+
+       // Check input
+       if (!what) {
+               errno = EINVAL;
+               return 1;
+       }
+
+       static const char* paths[] = {
+               "/usr/sbin",
+               "/sbin",
+               "/usr/bin",
+               "/bin",
+               NULL,
+       };
+
+       // Clear path
+       *path = '\0';
+
+       for (const char** p = paths; *p; p++) {
+               // Compose path
+               r = pakfire_path(pakfire, buffer, "%s/%s", *p, what);
+               if (r)
+                       return r;
+
+               // If the path exists and is executable we are done
+               if (access(buffer, X_OK) == 0) {
+                       const char* relpath = pakfire_relpath(pakfire, buffer);
+
+                       // Store the result in path
+                       return __pakfire_string_set(path, length, relpath);
+               }
+       }
+
+       return 0;
+}
+
 // Archive Stuff
 
 int pakfire_archive_copy_data_from_file(struct pakfire* pakfire,