PAKFIRE_BUILD_ERROR_IF_NOT_EMPTY);
}
+static int pakfire_build_fix_script_interpreter(
+ struct pakfire_ctx* ctx, struct pakfire_file* file, void* data) {
+ // Only run this for regular files
+ switch (pakfire_file_get_type(file)) {
+ case S_IFREG:
+ break;
+
+ // Ignore anything that isn't a symlink
+ default:
+ return 0;
+ }
+
+ // The file must be executable
+ if (!pakfire_file_is_executable(file))
+ return 0;
+
+ // Do not run this on ELF files
+ else if (pakfire_file_is_elf(file))
+ return 0;
+
+ // Fix the interpreter
+ return pakfire_file_fix_interpreter(file);
+}
+
/*
File Issues
*/
if (r)
goto ERROR;
+ // Fix script interpreters
+ r = pakfire_filelist_walk(filelist,
+ pakfire_build_fix_script_interpreter, NULL, 0, NULL);
+ if (r)
+ goto ERROR;
+
ERROR:
if (filelist)
pakfire_filelist_unref(filelist);
return pakfire_path_match(pattern, path);
}
+static int pakfire_file_fconsume(struct pakfire_file* file, FILE* src) {
+ FILE* dst = NULL;
+ int fd = -EBADF;
+ int r;
+
+ // Use sendfile if we have a file descriptor
+ fd = fileno(src);
+ if (fd >= 0)
+ return pakfire_file_consume(file, fd);
+
+ // Rewind the file
+ r = pakfire_rewind(src);
+ if (r < 0) {
+ ERROR(file->ctx, "Could not rewind file descriptor: %m\n");
+ r = -errno;
+ goto ERROR;
+ }
+
+ // Open the file for writing
+ dst = pakfire_file_fopen(file, "w");
+ if (!dst)
+ goto ERROR;
+
+ // Copy the content
+ r = pakfire_copy(file->ctx, src, dst);
+ if (r < 0) {
+ ERROR(file->ctx, "Could not consume to %s: %m\n", pakfire_file_get_path(file));
+ goto ERROR;
+ }
+
+ERROR:
+ if (dst)
+ fclose(dst);
+
+ return r;
+}
+
int pakfire_file_consume(struct pakfire_file* file, int srcfd) {
ssize_t bytes_written = 0;
struct stat st = {};
return r;
}
+
+int pakfire_file_fix_interpreter(struct pakfire_file* file) {
+ const char* interpreter = NULL;
+ char* buffer = NULL;
+ FILE* f = NULL;
+ FILE* b = NULL;
+ size_t l = 0;
+ int r;
+
+ char* line = NULL;
+ size_t length = 0;
+ char* p = NULL;
+
+ char command[PATH_MAX];
+ const char* args = NULL;
+
+ const char* path = pakfire_file_get_path(file);
+
+ // Create a place where we can write all the data to
+ b = open_memstream(&buffer, &l);
+ if (!b) {
+ ERROR(file->ctx, "Could not open a memory buffer: %m\n");
+ r = -errno;
+ goto ERROR;
+ }
+
+ // Open the file
+ f = pakfire_file_fopen(file, "r");
+ if (!f) {
+ ERROR(file->ctx, "Could not open %s: %m\n", path);
+ r = -errno;
+ goto ERROR;
+ }
+
+ for (unsigned int lineno = 0;; lineno++) {
+ r = getline(&line, &length, f);
+ if (r < 0) {
+ // We finished reading when we reach the end
+ if (feof(f))
+ break;
+
+ ERROR(file->ctx, "Could not read line from %s: %m\n", path);
+ r = -errno;
+ goto ERROR;
+ }
+
+ switch (lineno) {
+ case 0:
+ // Check if the first line starts with #!
+ if (!pakfire_string_startswith(line, "#!")) {
+ r = 0;
+ goto ERROR;
+ }
+
+ // Remove the trailing newline
+ pakfire_string_rstrip(line);
+
+ // Start at the beginning of the line (after shebang)
+ p = line + 2;
+
+ // Consume any whitespace
+ while (*p && isspace(*p))
+ p++;
+
+ // Consume the old interpreter
+ while (*p && !isspace(*p))
+ p++;
+
+ // Consume any whitespace
+ while (*p && isspace(*p))
+ p++;
+
+ // The actual interpreter begins here
+ interpreter = p;
+
+ // Find the end of the interpreter
+ while (*p && !isspace(*p))
+ p++;
+
+ // Terminate the interpreter
+ *p++ = '\0';
+
+ // Any arguments begin here (if we didn't consume the entire string, yet)
+ if (*p)
+ args = p;
+
+ DEBUG(file->ctx, "%s: Found command %s (%s)\n", path, interpreter, args);
+
+ // Find the real path
+ r = pakfire_which(file->pakfire, command, interpreter);
+ if (r < 0) {
+ ERROR(file->ctx, "%s: Could not resolve %s: %m\n", path, interpreter);
+ goto ERROR;
+ }
+
+ // If we could not resolve the command, this file has an invalid interpreter
+ if (!*command) {
+ ERROR(file->ctx, "%s: Could not find path for command %s\n", path, interpreter);
+ r = -ENOENT;
+ goto ERROR;
+ }
+
+ // Write the new first line to the buffer
+ r = fprintf(b, "#!%s", command);
+ if (r < 0)
+ goto ERROR;
+
+ // Append arguments if any
+ if (args) {
+ r = fprintf(b, " %s", args);
+ if (r < 0)
+ goto ERROR;
+ }
+
+ // Terminate the line
+ r = fprintf(b, "\n");
+ if (r < 0)
+ goto ERROR;
+
+ // Process the next line
+ break;
+
+ default:
+ // Append the line to the buffer
+ r = fprintf(b, "%s", line);
+ if (r < 0)
+ goto ERROR;
+
+ break;
+ }
+ }
+
+ // Write back the new content
+ r = pakfire_file_fconsume(file, b);
+ if (r < 0)
+ goto ERROR;
+
+ERROR:
+ if (b)
+ fclose(b);
+ if (buffer)
+ free(buffer);
+ if (line)
+ free(line);
+ if (f)
+ fclose(f);
+
+ return r;
+}