}
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);
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;
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) {
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,