1 /*#############################################################################
3 # Pakfire - The IPFire package management system #
4 # Copyright (C) 2022 Pakfire development team #
6 # This program is free software: you can redistribute it and/or modify #
7 # it under the terms of the GNU General Public License as published by #
8 # the Free Software Foundation, either version 3 of the License, or #
9 # (at your option) any later version. #
11 # This program is distributed in the hope that it will be useful, #
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
14 # GNU General Public License for more details. #
16 # You should have received a copy of the GNU General Public License #
17 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
19 #############################################################################*/
23 #include <linux/capability.h>
24 #include <linux/sched.h>
29 #include <sys/capability.h>
30 #include <sys/epoll.h>
31 #include <sys/eventfd.h>
32 #include <sys/personality.h>
33 #include <sys/prctl.h>
34 #include <sys/types.h>
40 #include <pakfire/arch.h>
41 #include <pakfire/jail.h>
42 #include <pakfire/logging.h>
43 #include <pakfire/mount.h>
44 #include <pakfire/pakfire.h>
45 #include <pakfire/util.h>
47 #define BUFFER_SIZE 1024 * 64
48 #define ENVIRON_SIZE 128
49 #define EPOLL_MAX_EVENTS 2
51 // The default environment that will be set for every command
52 static const struct environ
{
56 { "LANG", "en_US.utf-8" },
62 struct pakfire
* pakfire
;
69 char* env
[ENVIRON_SIZE
];
72 pakfire_jail_log_callback log_callback
;
76 struct pakfire_log_buffer
{
77 char data
[BUFFER_SIZE
];
81 struct pakfire_jail_exec
{
85 // Process status (from waitpid)
88 // FD to notify the client that the parent has finished initialization
99 struct pakfire_log_buffer stdout
;
100 struct pakfire_log_buffer stderr
;
104 static int clone3(struct clone_args
* args
, size_t size
) {
105 return syscall(__NR_clone3
, args
, size
);
108 static void pakfire_jail_free(struct pakfire_jail
* jail
) {
109 DEBUG(jail
->pakfire
, "Freeing jail at %p\n", jail
);
112 for (unsigned int i
= 0; jail
->env
[i
]; i
++)
115 pakfire_unref(jail
->pakfire
);
119 static int pakfire_jail_default_log_callback(struct pakfire
* pakfire
, void* data
,
120 int priority
, const char* line
, size_t length
) {
123 INFO(pakfire
, "%s", line
);
127 ERROR(pakfire
, "%s", line
);
134 static int pakfire_jail_setup_interactive_env(struct pakfire_jail
* jail
) {
136 int r
= pakfire_jail_set_env(jail
, "PS1", "pakfire-jail \\w> ");
141 char* TERM
= secure_getenv("TERM");
143 r
= pakfire_jail_set_env(jail
, "TERM", TERM
);
149 char* LANG
= secure_getenv("LANG");
151 r
= pakfire_jail_set_env(jail
, "LANG", LANG
);
159 int pakfire_jail_create(struct pakfire_jail
** jail
, struct pakfire
* pakfire
, int flags
) {
162 // Allocate a new jail
163 struct pakfire_jail
* j
= calloc(1, sizeof(*j
));
168 j
->pakfire
= pakfire_ref(pakfire
);
170 // Initialize reference counter
176 DEBUG(j
->pakfire
, "Allocated new jail at %p\n", j
);
178 // Set default log callback
179 r
= pakfire_jail_set_log_callback(j
, pakfire_jail_default_log_callback
, NULL
);
183 // Set default environment
184 for (const struct environ
* e
= ENV
; e
->key
; e
++) {
185 r
= pakfire_jail_set_env(j
, e
->key
, e
->val
);
190 // Setup interactive stuff
191 if (j
->flags
& PAKFIRE_JAIL_INTERACTIVE
) {
192 r
= pakfire_jail_setup_interactive_env(j
);
202 pakfire_jail_free(j
);
207 struct pakfire_jail
* pakfire_jail_ref(struct pakfire_jail
* jail
) {
213 struct pakfire_jail
* pakfire_jail_unref(struct pakfire_jail
* jail
) {
214 if (--jail
->nrefs
> 0)
217 pakfire_jail_free(jail
);
221 static int pakfire_jail_has_flag(struct pakfire_jail
* jail
, int flag
) {
222 return jail
->flags
& flag
;
227 // Returns the length of the environment
228 static unsigned int pakfire_jail_env_length(struct pakfire_jail
* jail
) {
231 // Count everything in the environment
232 for (char** e
= jail
->env
; *e
; e
++)
238 // Finds an existing environment variable and returns its index or -1 if not found
239 static int pakfire_jail_find_env(struct pakfire_jail
* jail
, const char* key
) {
245 char buffer
[strlen(key
) + 2];
246 pakfire_string_format(buffer
, "%s=", key
);
248 for (unsigned int i
= 0; jail
->env
[i
]; i
++) {
249 if (pakfire_string_startswith(jail
->env
[i
], buffer
))
257 // Returns the value of an environment variable or NULL
258 const char* pakfire_jail_get_env(struct pakfire_jail
* jail
, const char* key
) {
259 int i
= pakfire_jail_find_env(jail
, key
);
263 return jail
->env
[i
] + strlen(key
) + 1;
266 // Sets an environment variable
267 int pakfire_jail_set_env(struct pakfire_jail
* jail
, const char* key
, const char* value
) {
268 // Find the index where to write this value to
269 int i
= pakfire_jail_find_env(jail
, key
);
271 i
= pakfire_jail_env_length(jail
);
273 // Return -ENOSPC when the environment is full
274 if (i
>= ENVIRON_SIZE
) {
279 // Free any previous value
283 // Format and set environment variable
284 asprintf(&jail
->env
[i
], "%s=%s", key
, value
);
286 DEBUG(jail
->pakfire
, "Set environment variable: %s\n", jail
->env
[i
]);
291 // Imports an environment
292 int pakfire_jail_import_env(struct pakfire_jail
* jail
, const char* env
[]) {
300 // Copy environment variables
301 for (unsigned int i
= 0; env
[i
]; i
++) {
302 r
= pakfire_string_partition(env
[i
], "=", &key
, &val
);
307 r
= pakfire_jail_set_env(jail
, key
, val
);
324 int pakfire_jail_set_log_callback(struct pakfire_jail
* jail
,
325 pakfire_jail_log_callback callback
, void* data
) {
326 jail
->log_callback
= callback
;
327 jail
->log_data
= data
;
332 static int pakfire_jail_log_buffer_is_full(const struct pakfire_log_buffer
* buffer
) {
333 return (sizeof(buffer
->data
) == buffer
->used
);
337 This function reads as much data as it can from the file descriptor.
338 If it finds a whole line in it, it will send it to the logger and repeat the process.
339 If not newline character is found, it will try to read more data until it finds one.
341 static int pakfire_jail_handle_log(struct pakfire_jail
* jail
,
342 struct pakfire_jail_exec
* ctx
, int priority
, int fd
, struct pakfire_log_buffer
* buffer
) {
343 char line
[BUFFER_SIZE
+ 1];
345 // Fill up buffer from fd
346 if (buffer
->used
< sizeof(buffer
->data
)) {
347 ssize_t bytes_read
= read(fd
, buffer
->data
+ buffer
->used
,
348 sizeof(buffer
->data
) - buffer
->used
);
351 if (bytes_read
< 0) {
352 ERROR(jail
->pakfire
, "Could not read from fd %d: %m\n", fd
);
356 // Update buffer size
357 buffer
->used
+= bytes_read
;
360 // See if we have any lines that we can write
361 while (buffer
->used
) {
362 // Search for the end of the first line
363 char* eol
= memchr(buffer
->data
, '\n', buffer
->used
);
367 // If the buffer is full, we send the content to the logger and try again
368 // This should not happen in practise
369 if (pakfire_jail_log_buffer_is_full(buffer
)) {
370 DEBUG(jail
->pakfire
, "Logging buffer is full. Sending all content\n");
372 eol
= buffer
->data
+ sizeof(buffer
->data
) - 1;
374 // Otherwise we might have only read parts of the output
379 // Find the length of the string
380 size_t length
= eol
- buffer
->data
+ 1;
382 // Copy the line into the buffer
383 memcpy(line
, buffer
->data
, length
);
385 // Terminate the string
389 if (jail
->log_callback
) {
390 int r
= jail
->log_callback(jail
->pakfire
, jail
->log_data
, priority
, line
, length
);
392 ERROR(jail
->pakfire
, "The logging callback returned an error: %d\n", r
);
397 // Remove line from buffer
398 memmove(buffer
->data
, buffer
->data
+ length
, buffer
->used
- length
);
399 buffer
->used
-= length
;
405 static int pakfire_jail_logger(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
407 struct epoll_event ev
;
408 struct epoll_event events
[EPOLL_MAX_EVENTS
];
411 // Fetch file descriptors from context
412 const int stdout
= ctx
->pipes
.stdout
[1];
413 const int stderr
= ctx
->pipes
.stderr
[1];
420 epollfd
= epoll_create1(0);
422 ERROR(jail
->pakfire
, "Could not initialize epoll(): %m\n");
429 // Turn file descriptors into non-blocking mode and add them to epoll()
430 for (unsigned int i
= 0; i
< 2; i
++) {
435 if (epoll_ctl(epollfd
, EPOLL_CTL_ADD
, fd
, &ev
) < 0) {
436 ERROR(jail
->pakfire
, "Could not add file descriptor %d to epoll(): %m\n", fd
);
444 // Loop for as long as the process is alive
446 // If waitpid() returns non-zero, the process has ended, but we want to perform
447 // one last iteration over the loop to read any remaining content from the file
448 // descriptor buffers.
449 r
= waitpid(ctx
->pid
, &ctx
->status
, WNOHANG
);
453 int num
= epoll_wait(epollfd
, events
, EPOLL_MAX_EVENTS
, -1);
455 // Ignore if epoll_wait() has been interrupted
459 ERROR(jail
->pakfire
, "epoll_wait() failed: %m\n");
465 struct pakfire_log_buffer
* buffer
;
468 for (int i
= 0; i
< num
; i
++) {
469 int fd
= events
[i
].data
.fd
;
472 buffer
= &ctx
->buffers
.stdout
;
475 } else if (fd
== stderr
) {
476 buffer
= &ctx
->buffers
.stderr
;
480 DEBUG(jail
->pakfire
, "Received invalid file descriptor %d\n", fd
);
485 r
= pakfire_jail_handle_log(jail
, ctx
, priority
, fd
, buffer
);
498 static int pakfire_jail_capture_stdout(struct pakfire
* pakfire
, void* data
, int priority
,
499 const char* line
, size_t length
) {
500 char*** array
= (char***)data
;
502 // Append everything from stdout to an array
503 if (priority
== LOG_INFO
) {
506 // Create a copy of line
507 char* message
= strdup(line
);
511 // Remove any trailing newline
512 pakfire_remove_trailing_newline(message
);
514 // Determine the length of the existing array
516 for (char** element
= *array
; *element
; element
++)
521 *array
= reallocarray(*array
, length
+ 2, sizeof(**array
));
525 // Append message and terminate the array
526 (*array
)[length
] = message
;
527 (*array
)[length
+ 1] = NULL
;
532 // Send everything else to the default logger
533 return pakfire_jail_default_log_callback(pakfire
, NULL
, priority
, line
, length
);
538 static int pakfire_jail_drop_capabilities(struct pakfire_jail
* jail
) {
539 const int capabilities
[] = {
540 // Deny access to the kernel's audit system
545 // Deny suspending block devices
548 // Deny any stuff with BPF
551 // Deny checkpoint restore
552 CAP_CHECKPOINT_RESTORE
,
554 // Deny opening files by inode number (open_by_handle_at)
557 // Deny setting SUID bits
560 // Deny locking more memory
563 // Deny modifying any Apparmor/SELinux/SMACK configuration
567 // Deny creating any special devices
570 // Deny setting any capabilities
573 // Deny reading from syslog
576 // Deny any admin actions (mount, sethostname, ...)
579 // Deny rebooting the system
582 // Deny loading kernel modules
585 // Deny setting nice level
588 // Deny access to /proc/kcore, /dev/mem, /dev/kmem
591 // Deny circumventing any resource limits
594 // Deny setting the system time
597 // Deny playing with suspend
603 DEBUG(jail
->pakfire
, "Dropping capabilities...\n");
608 // Drop any capabilities
609 for (const int* cap
= capabilities
; *cap
; cap
++) {
610 r
= prctl(PR_CAPBSET_DROP
, *cap
, 0, 0, 0);
612 ERROR(jail
->pakfire
, "Could not drop capability %d: %m\n", *cap
);
619 // Fetch any capabilities
620 cap_t caps
= cap_get_proc();
622 ERROR(jail
->pakfire
, "Could not read capabilities: %m\n");
627 Set inheritable capabilities
629 This ensures that no processes will be able to gain any of the listed
632 r
= cap_set_flag(caps
, CAP_INHERITABLE
, num_caps
, capabilities
, CAP_CLEAR
);
634 ERROR(jail
->pakfire
, "cap_set_flag() failed: %m\n");
638 // Restore capabilities
639 r
= cap_set_proc(caps
);
641 ERROR(jail
->pakfire
, "Could not restore capabilities: %m\n");
654 static int pakfire_jail_limit_syscalls(struct pakfire_jail
* jail
) {
655 const int syscalls
[] = {
656 // The kernel's keyring isn't namespaced
659 SCMP_SYS(request_key
),
661 // Disable userfaultfd
662 SCMP_SYS(userfaultfd
),
664 // Disable perf which could leak a lot of information about the host
665 SCMP_SYS(perf_event_open
),
671 DEBUG(jail
->pakfire
, "Applying syscall filter...\n");
673 // Setup a syscall filter which allows everything by default
674 scmp_filter_ctx ctx
= seccomp_init(SCMP_ACT_ALLOW
);
676 ERROR(jail
->pakfire
, "Could not setup seccomp filter: %m\n");
681 for (const int* syscall
= syscalls
; *syscall
; syscall
++) {
682 r
= seccomp_rule_add(ctx
, SCMP_ACT_ERRNO(EPERM
), *syscall
, 0);
684 ERROR(jail
->pakfire
, "Could not configure syscall %d: %m\n", *syscall
);
689 // Load syscall filter into the kernel
690 r
= seccomp_load(ctx
);
692 ERROR(jail
->pakfire
, "Could not load syscall filter into the kernel: %m\n");
698 seccomp_release(ctx
);
705 static int pakfire_jail_write_uidgid_mapping(struct pakfire_jail
* jail
,
706 const char* path
, uid_t mapped_id
, size_t length
) {
709 // Open file for writing
710 FILE* f
= fopen(path
, "w");
712 ERROR(jail
->pakfire
, "Could not open %s for writing: %m\n", path
);
716 // Write configuration
717 int bytes_written
= fprintf(f
, "%d %d %ld\n", 0, mapped_id
, length
);
718 if (bytes_written
<= 0) {
719 ERROR(jail
->pakfire
, "Could not write UID/GID mapping: %m\n");
727 ERROR(jail
->pakfire
, "Could not write UID/GID mapping: %m\n");
742 static int pakfire_jail_setup_uid_mapping(struct pakfire_jail
* jail
, pid_t pid
) {
746 uid_t mapped_uid
= 0;
747 const size_t length
= 1;
749 // Fetch the UID of the calling process
750 uid_t uid
= getuid();
752 // Have we been called by root?
756 // Have we been called by an unprivileged user?
763 r
= pakfire_string_format(path
, "/proc/%d/uid_map", pid
);
767 DEBUG(jail
->pakfire
, "Mapping UID range (%u - %lu)\n", mapped_uid
, mapped_uid
+ length
);
769 return pakfire_jail_write_uidgid_mapping(jail
, path
, mapped_uid
, length
);
772 static int pakfire_jail_setup_gid_mapping(struct pakfire_jail
* jail
, pid_t pid
) {
776 gid_t mapped_gid
= 0;
777 const size_t length
= 1;
779 // Fetch the GID of the calling process
780 gid_t gid
= getgid();
782 // Have we been called from the root group?
786 // Have we been called by an unprivileged group?
793 r
= pakfire_string_format(path
, "/proc/%d/gid_map", pid
);
797 DEBUG(jail
->pakfire
, "Mapping GID range (%u - %lu)\n", mapped_gid
, mapped_gid
+ length
);
799 return pakfire_jail_write_uidgid_mapping(jail
, path
, mapped_gid
, length
);
802 static int pakfire_jail_setgroups(struct pakfire_jail
* jail
, pid_t pid
) {
807 r
= pakfire_string_format(path
, "/proc/%d/setgroups", pid
);
811 // Open file for writing
812 FILE* f
= fopen(path
, "w");
814 ERROR(jail
->pakfire
, "Could not open %s for writing: %m\n", path
);
819 int bytes_written
= fprintf(f
, "deny\n");
820 if (bytes_written
<= 0) {
821 ERROR(jail
->pakfire
, "Could not write to %s: %m\n", path
);
828 ERROR(jail
->pakfire
, "Could not close %s: %m\n", path
);
839 static int pakfire_jail_send_signal(struct pakfire_jail
* jail
, int fd
) {
840 const uint64_t val
= 1;
843 DEBUG(jail
->pakfire
, "Sending signal...\n");
845 // Write to the file descriptor
846 ssize_t bytes_written
= write(fd
, &val
, sizeof(val
));
847 if (bytes_written
< 0 || (size_t)bytes_written
< sizeof(val
)) {
848 ERROR(jail
->pakfire
, "Could not send signal: %m\n");
852 // Close the file descriptor
858 static int pakfire_jail_wait_for_signal(struct pakfire_jail
* jail
, int fd
) {
862 DEBUG(jail
->pakfire
, "Waiting for signal...\n");
864 ssize_t bytes_read
= read(fd
, &val
, sizeof(val
));
865 if (bytes_read
< 0 || (size_t)bytes_read
< sizeof(val
)) {
866 ERROR(jail
->pakfire
, "Error waiting for signal: %m\n");
870 // Close the file descriptor
877 Performs the initialisation that needs to happen in the parent part
879 static int pakfire_jail_parent(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
883 r
= pakfire_jail_setup_uid_mapping(jail
, ctx
->pid
);
887 // Write "deny" to /proc/PID/setgroups
888 r
= pakfire_jail_setgroups(jail
, ctx
->pid
);
893 r
= pakfire_jail_setup_gid_mapping(jail
, ctx
->pid
);
897 // Parent has finished initialisation
898 DEBUG(jail
->pakfire
, "Parent has finished initialization\n");
900 // Send signal to client
901 r
= pakfire_jail_send_signal(jail
, ctx
->completed_fd
);
908 static int pakfire_jail_child(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
,
909 const char* argv
[]) {
912 // XXX do we have to reconfigure logging here?
914 DEBUG(jail
->pakfire
, "Launched child process in jail with PID %d\n", getpid());
916 // Wait for the parent to finish initialization
917 r
= pakfire_jail_wait_for_signal(jail
, ctx
->completed_fd
);
921 // Perform further initialization
924 uid_t uid
= getuid();
925 gid_t gid
= getgid();
928 uid_t euid
= geteuid();
929 gid_t egid
= getegid();
931 DEBUG(jail
->pakfire
, " UID: %d (effective %d)\n", uid
, euid
);
932 DEBUG(jail
->pakfire
, " GID: %d (effective %d)\n", gid
, egid
);
934 // Check if we are (effectively running as root)
935 if (uid
!= 0 || gid
!= 0) {
936 ERROR(jail
->pakfire
, "Child process is not running as root\n");
940 const char* root
= pakfire_get_path(jail
->pakfire
);
941 const char* arch
= pakfire_get_arch(jail
->pakfire
);
943 // Change root (unless root is /)
944 if (!pakfire_on_root(jail
->pakfire
)) {
946 r
= pakfire_mount_all(jail
->pakfire
);
950 // Log all mountpoints
951 pakfire_mount_list(jail
->pakfire
);
956 ERROR(jail
->pakfire
, "chroot() to %s failed: %m\n", root
);
960 // Change directory to /
963 ERROR(jail
->pakfire
, "chdir() after chroot() failed: %m\n");
969 unsigned long persona
= pakfire_arch_personality(arch
);
971 r
= personality(persona
);
973 ERROR(jail
->pakfire
, "Could not set personality (%x)\n", (unsigned int)persona
);
978 // Reset open file limit (http://0pointer.net/blog/file-descriptor-limits.html)
979 r
= pakfire_rlimit_reset_nofile(jail
->pakfire
);
984 r
= pakfire_jail_drop_capabilities(jail
);
989 r
= pakfire_jail_limit_syscalls(jail
);
994 r
= execvpe(argv
[0], (char**)argv
, jail
->env
);
996 ERROR(jail
->pakfire
, "Could not execve(): %m\n");
998 // Translate errno into regular exit code
1008 // We should not get here
1012 // Run a command in the jail
1013 static int __pakfire_jail_exec(struct pakfire_jail
* jail
, const char* argv
[]) {
1017 // Check if argv is valid
1018 if (!argv
|| !argv
[0]) {
1023 // Initialize context for this call
1024 struct pakfire_jail_exec ctx
= {
1026 .stdout
= { 0, 0, },
1027 .stderr
= { 0, 0, },
1032 DEBUG(jail
->pakfire
, "Executing jail...\n");
1035 Setup a file descriptor which can be used to notify the client that the parent
1036 has completed configuration.
1038 ctx
.completed_fd
= eventfd(0, EFD_CLOEXEC
);
1039 if (ctx
.completed_fd
< 0) {
1040 ERROR(jail
->pakfire
, "eventfd() failed: %m\n");
1044 // Create pipes to communicate with child process if we are not running interactively
1045 if (!pakfire_jail_has_flag(jail
, PAKFIRE_JAIL_INTERACTIVE
)) {
1047 r
= pipe2(ctx
.pipes
.stdout
, O_NONBLOCK
);
1049 ERROR(jail
->pakfire
, "Could not create file descriptors for stdout: %m\n");
1054 r
= pipe2(ctx
.pipes
.stderr
, O_NONBLOCK
);
1056 ERROR(jail
->pakfire
, "Could not create file descriptors for stderr: %m\n");
1061 // Configure child process
1062 struct clone_args args
= {
1070 .exit_signal
= SIGCHLD
,
1073 // Fork this process
1074 ctx
.pid
= clone3(&args
, sizeof(args
));
1076 ERROR(jail
->pakfire
, "Could not clone: %m\n");
1080 } else if (ctx
.pid
== 0) {
1081 r
= pakfire_jail_child(jail
, &ctx
, argv
);
1086 r
= pakfire_jail_parent(jail
, &ctx
);
1090 DEBUG(jail
->pakfire
, "Waiting for PID %d to finish its work\n", ctx
.pid
);
1092 // Read output of the child process
1093 if (!pakfire_jail_has_flag(jail
, PAKFIRE_JAIL_INTERACTIVE
)) {
1094 r
= pakfire_jail_logger(jail
, &ctx
);
1096 ERROR(jail
->pakfire
, "Log reading aborted: %m\n");
1100 waitpid(ctx
.pid
, &ctx
.status
, 0);
1102 if (WIFEXITED(ctx
.status
)) {
1103 exit
= WEXITSTATUS(ctx
.status
);
1105 DEBUG(jail
->pakfire
, "Child process exited with code: %d\n", exit
);
1107 ERROR(jail
->pakfire
, "Could not determine the exit status of process %d\n", ctx
.pid
);
1114 // Close any file descriptors
1115 if (ctx
.pipes
.stdout
[0])
1116 close(ctx
.pipes
.stdout
[0]);
1117 if (ctx
.pipes
.stdout
[1])
1118 close(ctx
.pipes
.stdout
[1]);
1119 if (ctx
.pipes
.stderr
[0])
1120 close(ctx
.pipes
.stderr
[0]);
1121 if (ctx
.pipes
.stderr
[1])
1122 close(ctx
.pipes
.stderr
[1]);
1124 // Umount everything
1125 if (!pakfire_on_root(jail
->pakfire
))
1126 pakfire_umount_all(jail
->pakfire
);
1131 int pakfire_jail_exec(struct pakfire_jail
* jail
, const char* argv
[], char*** output
) {
1134 // Store logging callback
1135 pakfire_jail_log_callback log_callback
= jail
->log_callback
;
1136 void* log_data
= jail
->log_data
;
1138 // Capture output if requested by user
1140 pakfire_jail_set_log_callback(jail
, pakfire_jail_capture_stdout
, output
);
1143 r
= __pakfire_jail_exec(jail
, argv
);
1145 // Restore log callback
1146 pakfire_jail_set_log_callback(jail
, log_callback
, log_data
);
1151 int pakfire_jail_exec_script(struct pakfire_jail
* jail
,
1152 const char* script
, const size_t size
, const char* args
[], char*** output
) {
1153 char path
[PATH_MAX
];
1154 const char** argv
= NULL
;
1157 const char* root
= pakfire_get_path(jail
->pakfire
);
1159 // Write the scriptlet to disk
1160 r
= pakfire_path_join(path
, root
, "pakfire-script.XXXXXX");
1164 // Open a temporary file
1165 int fd
= mkstemp(path
);
1167 ERROR(jail
->pakfire
, "Could not open a temporary file: %m\n");
1172 DEBUG(jail
->pakfire
, "Writing script to %s:\n%.*s\n", path
, (int)size
, script
);
1175 ssize_t bytes_written
= write(fd
, script
, size
);
1176 if (bytes_written
< (ssize_t
)size
) {
1177 ERROR(jail
->pakfire
, "Could not write script to file %s: %m\n", path
);
1182 // Make the script executable
1183 r
= fchmod(fd
, S_IRUSR
|S_IWUSR
|S_IXUSR
);
1185 ERROR(jail
->pakfire
, "Could not set executable permissions on %s: %m\n", path
);
1192 ERROR(jail
->pakfire
, "Could not close script file %s: %m\n", path
);
1197 // Count how many arguments were passed
1198 unsigned int argc
= 1;
1200 for (const char** arg
= args
; *arg
; arg
++)
1204 argv
= calloc(argc
+ 1, sizeof(*argv
));
1206 ERROR(jail
->pakfire
, "Could not allocate argv: %m\n");
1211 argv
[0] = (root
) ? pakfire_path_relpath(root
, path
) : path
;
1214 for (unsigned int i
= 1; i
< argc
; i
++)
1215 argv
[i
] = args
[i
-1];
1218 r
= pakfire_jail_exec(jail
, argv
, output
);
1224 // Remove script from disk
1232 A convenience function that creates a new jail, runs the given command and destroys
1235 int pakfire_jail_run(struct pakfire
* pakfire
, const char* argv
[], int flags
, char*** output
) {
1236 struct pakfire_jail
* jail
= NULL
;
1239 // Create a new jail
1240 r
= pakfire_jail_create(&jail
, pakfire
, flags
);
1244 // Execute the command
1245 r
= pakfire_jail_exec(jail
, argv
, output
);
1249 pakfire_jail_unref(jail
);
1254 int pakfire_jail_run_script(struct pakfire
* pakfire
,
1255 const char* script
, const size_t length
, const char* argv
[], int flags
, char*** output
) {
1256 struct pakfire_jail
* jail
= NULL
;
1259 // Create a new jail
1260 r
= pakfire_jail_create(&jail
, pakfire
, flags
);
1264 // Execute the command
1265 r
= pakfire_jail_exec_script(jail
, script
, length
, argv
, output
);
1269 pakfire_jail_unref(jail
);