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
++) {
434 int flags
= fcntl(fd
, F_GETFL
, 0);
436 // Set modified flags
437 if (fcntl(fd
, F_SETFL
, flags
|O_NONBLOCK
) < 0) {
439 "Could not set file descriptor %d into non-blocking mode: %m\n", fd
);
446 if (epoll_ctl(epollfd
, EPOLL_CTL_ADD
, fd
, &ev
) < 0) {
447 ERROR(jail
->pakfire
, "Could not add file descriptor %d to epoll(): %m\n", fd
);
455 // Loop for as long as the process is alive
457 // If waitpid() returns non-zero, the process has ended, but we want to perform
458 // one last iteration over the loop to read any remaining content from the file
459 // descriptor buffers.
460 r
= waitpid(ctx
->pid
, &ctx
->status
, WNOHANG
);
464 int num
= epoll_wait(epollfd
, events
, EPOLL_MAX_EVENTS
, -1);
466 // Ignore if epoll_wait() has been interrupted
470 ERROR(jail
->pakfire
, "epoll_wait() failed: %m\n");
476 struct pakfire_log_buffer
* buffer
;
479 for (int i
= 0; i
< num
; i
++) {
480 int fd
= events
[i
].data
.fd
;
483 buffer
= &ctx
->buffers
.stdout
;
486 } else if (fd
== stderr
) {
487 buffer
= &ctx
->buffers
.stderr
;
491 DEBUG(jail
->pakfire
, "Received invalid file descriptor %d\n", fd
);
496 r
= pakfire_jail_handle_log(jail
, ctx
, priority
, fd
, buffer
);
511 static int pakfire_jail_drop_capabilities(struct pakfire_jail
* jail
) {
512 const int capabilities
[] = {
513 // Deny access to the kernel's audit system
518 // Deny suspending block devices
521 // Deny any stuff with BPF
524 // Deny checkpoint restore
525 CAP_CHECKPOINT_RESTORE
,
527 // Deny opening files by inode number (open_by_handle_at)
530 // Deny setting SUID bits
533 // Deny locking more memory
536 // Deny modifying any Apparmor/SELinux/SMACK configuration
540 // Deny creating any special devices
543 // Deny setting any capabilities
546 // Deny reading from syslog
549 // Deny any admin actions (mount, sethostname, ...)
552 // Deny rebooting the system
555 // Deny loading kernel modules
558 // Deny setting nice level
561 // Deny access to /proc/kcore, /dev/mem, /dev/kmem
564 // Deny circumventing any resource limits
567 // Deny setting the system time
570 // Deny playing with suspend
576 DEBUG(jail
->pakfire
, "Dropping capabilities...\n");
581 // Drop any capabilities
582 for (const int* cap
= capabilities
; *cap
; cap
++) {
583 r
= prctl(PR_CAPBSET_DROP
, *cap
, 0, 0, 0);
585 ERROR(jail
->pakfire
, "Could not drop capability %d: %m\n", *cap
);
592 // Fetch any capabilities
593 cap_t caps
= cap_get_proc();
595 ERROR(jail
->pakfire
, "Could not read capabilities: %m\n");
600 Set inheritable capabilities
602 This ensures that no processes will be able to gain any of the listed
605 r
= cap_set_flag(caps
, CAP_INHERITABLE
, num_caps
, capabilities
, CAP_CLEAR
);
607 ERROR(jail
->pakfire
, "cap_set_flag() failed: %m\n");
611 // Restore capabilities
612 r
= cap_set_proc(caps
);
614 ERROR(jail
->pakfire
, "Could not restore capabilities: %m\n");
627 static int pakfire_jail_limit_syscalls(struct pakfire_jail
* jail
) {
628 const int syscalls
[] = {
629 // The kernel's keyring isn't namespaced
632 SCMP_SYS(request_key
),
634 // Disable userfaultfd
635 SCMP_SYS(userfaultfd
),
637 // Disable perf which could leak a lot of information about the host
638 SCMP_SYS(perf_event_open
),
644 DEBUG(jail
->pakfire
, "Applying syscall filter...\n");
646 // Setup a syscall filter which allows everything by default
647 scmp_filter_ctx ctx
= seccomp_init(SCMP_ACT_ALLOW
);
649 ERROR(jail
->pakfire
, "Could not setup seccomp filter: %m\n");
654 for (const int* syscall
= syscalls
; *syscall
; syscall
++) {
655 r
= seccomp_rule_add(ctx
, SCMP_ACT_ERRNO(EPERM
), *syscall
, 0);
657 ERROR(jail
->pakfire
, "Could not configure syscall %d: %m\n", *syscall
);
662 // Load syscall filter into the kernel
663 r
= seccomp_load(ctx
);
665 ERROR(jail
->pakfire
, "Could not load syscall filter into the kernel: %m\n");
671 seccomp_release(ctx
);
678 static int pakfire_jail_write_uidgid_mapping(struct pakfire_jail
* jail
,
679 const char* path
, uid_t mapped_id
, size_t length
) {
682 // Open file for writing
683 FILE* f
= fopen(path
, "w");
685 ERROR(jail
->pakfire
, "Could not open %s for writing: %m\n", path
);
689 // Write configuration
690 int bytes_written
= fprintf(f
, "%d %d %ld\n", 0, mapped_id
, length
);
691 if (bytes_written
<= 0) {
692 ERROR(jail
->pakfire
, "Could not write UID/GID mapping: %m\n");
700 ERROR(jail
->pakfire
, "Could not write UID/GID mapping: %m\n");
715 static int pakfire_jail_setup_uid_mapping(struct pakfire_jail
* jail
, pid_t pid
) {
719 // XXX hard-coded values
720 const uid_t mapped_uid
= 100000;
721 const size_t length
= 64536;
724 r
= pakfire_string_format(path
, "/proc/%d/uid_map", pid
);
728 DEBUG(jail
->pakfire
, "Mapping UID range (%u - %lu)\n", mapped_uid
, mapped_uid
+ length
);
730 return pakfire_jail_write_uidgid_mapping(jail
, path
, mapped_uid
, length
);
733 static int pakfire_jail_setup_gid_mapping(struct pakfire_jail
* jail
, pid_t pid
) {
737 // XXX hard-coded values
738 const uid_t mapped_gid
= 100000;
739 const size_t length
= 64536;
742 r
= pakfire_string_format(path
, "/proc/%d/gid_map", pid
);
746 DEBUG(jail
->pakfire
, "Mapping GID range (%u - %lu)\n", mapped_gid
, mapped_gid
+ length
);
748 return pakfire_jail_write_uidgid_mapping(jail
, path
, mapped_gid
, length
);
751 static int pakfire_jail_setgroups(struct pakfire_jail
* jail
, pid_t pid
) {
756 r
= pakfire_string_format(path
, "/proc/%d/setgroups", pid
);
760 // Open file for writing
761 FILE* f
= fopen(path
, "w");
763 ERROR(jail
->pakfire
, "Could not open %s for writing: %m\n", path
);
768 int bytes_written
= fprintf(f
, "deny\n");
769 if (bytes_written
<= 0) {
770 ERROR(jail
->pakfire
, "Could not write to %s: %m\n", path
);
777 ERROR(jail
->pakfire
, "Could not close %s: %m\n", path
);
788 static int pakfire_jail_send_signal(struct pakfire_jail
* jail
, int fd
) {
789 const uint64_t val
= 1;
792 DEBUG(jail
->pakfire
, "Sending signal...\n");
794 // Write to the file descriptor
795 ssize_t bytes_written
= write(fd
, &val
, sizeof(val
));
796 if (bytes_written
< 0 || (size_t)bytes_written
< sizeof(val
)) {
797 ERROR(jail
->pakfire
, "Could not send signal: %m\n");
801 // Close the file descriptor
807 static int pakfire_jail_wait_for_signal(struct pakfire_jail
* jail
, int fd
) {
811 DEBUG(jail
->pakfire
, "Waiting for signal...\n");
813 ssize_t bytes_read
= read(fd
, &val
, sizeof(val
));
814 if (bytes_read
< 0 || (size_t)bytes_read
< sizeof(val
)) {
815 ERROR(jail
->pakfire
, "Error waiting for signal: %m\n");
819 // Close the file descriptor
826 Performs the initialisation that needs to happen in the parent part
828 static int pakfire_jail_parent(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
) {
832 r
= pakfire_jail_setup_uid_mapping(jail
, ctx
->pid
);
836 // Write "deny" to /proc/PID/setgroups
837 r
= pakfire_jail_setgroups(jail
, ctx
->pid
);
842 r
= pakfire_jail_setup_gid_mapping(jail
, ctx
->pid
);
846 // Parent has finished initialisation
847 DEBUG(jail
->pakfire
, "Parent has finished initialization\n");
849 // Send signal to client
850 r
= pakfire_jail_send_signal(jail
, ctx
->completed_fd
);
857 static int pakfire_jail_child(struct pakfire_jail
* jail
, struct pakfire_jail_exec
* ctx
,
858 const char* argv
[]) {
861 // XXX do we have to reconfigure logging here?
863 DEBUG(jail
->pakfire
, "Launched child process in jail with PID %d\n", getpid());
865 // Wait for the parent to finish initialization
866 r
= pakfire_jail_wait_for_signal(jail
, ctx
->completed_fd
);
870 // Perform further initialization
873 uid_t uid
= getuid();
874 gid_t gid
= getgid();
877 uid_t euid
= geteuid();
878 gid_t egid
= getegid();
880 DEBUG(jail
->pakfire
, " UID: %d (effective %d)\n", uid
, euid
);
881 DEBUG(jail
->pakfire
, " GID: %d (effective %d)\n", gid
, egid
);
883 // Check if we are (effectively running as root)
884 if (uid
!= 0 || gid
!= 0) {
885 ERROR(jail
->pakfire
, "Child process is not running as root\n");
889 const char* root
= pakfire_get_path(jail
->pakfire
);
890 const char* arch
= pakfire_get_arch(jail
->pakfire
);
892 // Change root (unless root is /)
893 if (!pakfire_on_root(jail
->pakfire
)) {
895 r
= pakfire_mount_all(jail
->pakfire
);
899 // Log all mountpoints
900 pakfire_mount_list(jail
->pakfire
);
905 ERROR(jail
->pakfire
, "chroot() to %s failed: %m\n", root
);
909 // Change directory to /
912 ERROR(jail
->pakfire
, "chdir() after chroot() failed: %m\n");
918 unsigned long persona
= pakfire_arch_personality(arch
);
920 r
= personality(persona
);
922 ERROR(jail
->pakfire
, "Could not set personality (%x)\n", (unsigned int)persona
);
927 // Reset open file limit (http://0pointer.net/blog/file-descriptor-limits.html)
928 r
= pakfire_rlimit_reset_nofile(jail
->pakfire
);
933 r
= pakfire_jail_drop_capabilities(jail
);
938 r
= pakfire_jail_limit_syscalls(jail
);
943 r
= execvpe(argv
[0], (char**)argv
, jail
->env
);
945 ERROR(jail
->pakfire
, "Could not execve(): %m\n");
947 // Translate errno into regular exit code
957 // We should not get here
961 // Run a command in the jail
962 int pakfire_jail_exec(struct pakfire_jail
* jail
, const char* argv
[]) {
966 // Check if argv is valid
967 if (!argv
|| !argv
[0]) {
972 // Initialize context for this call
973 struct pakfire_jail_exec ctx
= {
981 DEBUG(jail
->pakfire
, "Executing jail...\n");
984 Setup a file descriptor which can be used to notify the client that the parent
985 has completed configuration.
987 ctx
.completed_fd
= eventfd(0, EFD_CLOEXEC
);
988 if (ctx
.completed_fd
< 0) {
989 ERROR(jail
->pakfire
, "eventfd() failed: %m\n");
993 // Create pipes to communicate with child process if we are not running interactively
994 if (!pakfire_jail_has_flag(jail
, PAKFIRE_JAIL_INTERACTIVE
)) {
996 r
= pipe(ctx
.pipes
.stdout
);
998 ERROR(jail
->pakfire
, "Could not create file descriptors for stdout: %m\n");
1003 r
= pipe(ctx
.pipes
.stderr
);
1005 ERROR(jail
->pakfire
, "Could not create file descriptors for stderr: %m\n");
1010 // Configure child process
1011 struct clone_args args
= {
1019 .exit_signal
= SIGCHLD
,
1022 // Fork this process
1023 ctx
.pid
= clone3(&args
, sizeof(args
));
1025 ERROR(jail
->pakfire
, "Could not clone: %m\n");
1029 } else if (ctx
.pid
== 0) {
1030 r
= pakfire_jail_child(jail
, &ctx
, argv
);
1035 r
= pakfire_jail_parent(jail
, &ctx
);
1039 DEBUG(jail
->pakfire
, "Waiting for PID %d to finish its work\n", ctx
.pid
);
1041 // Read output of the child process
1042 if (!pakfire_jail_has_flag(jail
, PAKFIRE_JAIL_INTERACTIVE
)) {
1043 r
= pakfire_jail_logger(jail
, &ctx
);
1045 ERROR(jail
->pakfire
, "Log reading aborted: %m\n");
1049 waitpid(ctx
.pid
, &ctx
.status
, 0);
1051 if (WIFEXITED(ctx
.status
)) {
1052 exit
= WEXITSTATUS(ctx
.status
);
1054 DEBUG(jail
->pakfire
, "Child process exited with code: %d\n", exit
);
1056 ERROR(jail
->pakfire
, "Could not determine the exit status of process %d\n", ctx
.pid
);
1063 // Close any file descriptors
1064 if (ctx
.pipes
.stdout
[0])
1065 close(ctx
.pipes
.stdout
[0]);
1066 if (ctx
.pipes
.stdout
[1])
1067 close(ctx
.pipes
.stdout
[1]);
1068 if (ctx
.pipes
.stderr
[0])
1069 close(ctx
.pipes
.stderr
[0]);
1070 if (ctx
.pipes
.stderr
[1])
1071 close(ctx
.pipes
.stderr
[1]);
1073 // Umount everything
1074 if (!pakfire_on_root(jail
->pakfire
))
1075 pakfire_umount_all(jail
->pakfire
);
1080 int pakfire_jail_exec_script(struct pakfire_jail
* jail
,
1081 const char* script
, const size_t size
, const char* args
[]) {
1082 char path
[PATH_MAX
];
1083 const char** argv
= NULL
;
1086 const char* root
= pakfire_get_path(jail
->pakfire
);
1088 // Write the scriptlet to disk
1089 r
= pakfire_path_join(path
, root
, "pakfire-script.XXXXXX");
1093 // Open a temporary file
1094 int fd
= mkstemp(path
);
1096 ERROR(jail
->pakfire
, "Could not open a temporary file: %m\n");
1101 DEBUG(jail
->pakfire
, "Writing script to %s:\n%.*s\n", path
, (int)size
, script
);
1104 ssize_t bytes_written
= write(fd
, script
, size
);
1105 if (bytes_written
< (ssize_t
)size
) {
1106 ERROR(jail
->pakfire
, "Could not write script to file %s: %m\n", path
);
1111 // Make the script executable
1112 r
= fchmod(fd
, S_IRUSR
|S_IWUSR
|S_IXUSR
);
1114 ERROR(jail
->pakfire
, "Could not set executable permissions on %s: %m\n", path
);
1121 ERROR(jail
->pakfire
, "Could not close script file %s: %m\n", path
);
1126 // Count how many arguments were passed
1127 unsigned int argc
= 1;
1129 for (const char** arg
= args
; *arg
; arg
++)
1133 argv
= calloc(argc
+ 1, sizeof(*argv
));
1135 ERROR(jail
->pakfire
, "Could not allocate argv: %m\n");
1140 argv
[0] = (root
) ? pakfire_path_relpath(root
, path
) : path
;
1143 for (unsigned int i
= 1; i
< argc
; i
++)
1144 argv
[i
] = args
[i
-1];
1147 r
= pakfire_jail_exec(jail
, argv
);
1153 // Remove script from disk
1161 A convenience function that creates a new jail, runs the given command and destroys
1164 int pakfire_jail_run(struct pakfire
* pakfire
, const char* argv
[], int flags
) {
1165 struct pakfire_jail
* jail
= NULL
;
1168 // Create a new jail
1169 r
= pakfire_jail_create(&jail
, pakfire
, flags
);
1173 // Execute the command
1174 r
= pakfire_jail_exec(jail
, argv
);
1178 pakfire_jail_unref(jail
);