xref: /qemu/bsd-user/freebsd/os-proc.h (revision 4edc98fc)
136999e6aSKarim Taha /*
236999e6aSKarim Taha  *  process related system call shims and definitions
336999e6aSKarim Taha  *
436999e6aSKarim Taha  *  Copyright (c) 2013-14 Stacey D. Son
536999e6aSKarim Taha  *
636999e6aSKarim Taha  *  This program is free software; you can redistribute it and/or modify
736999e6aSKarim Taha  *  it under the terms of the GNU General Public License as published by
836999e6aSKarim Taha  *  the Free Software Foundation; either version 2 of the License, or
936999e6aSKarim Taha  *  (at your option) any later version.
1036999e6aSKarim Taha  *
1136999e6aSKarim Taha  *  This program is distributed in the hope that it will be useful,
1236999e6aSKarim Taha  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
1336999e6aSKarim Taha  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1436999e6aSKarim Taha  *  GNU General Public License for more details.
1536999e6aSKarim Taha  *
1636999e6aSKarim Taha  *  You should have received a copy of the GNU General Public License
1736999e6aSKarim Taha  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
1836999e6aSKarim Taha  */
1936999e6aSKarim Taha 
2036999e6aSKarim Taha #ifndef BSD_USER_FREEBSD_OS_PROC_H
2136999e6aSKarim Taha #define BSD_USER_FREEBSD_OS_PROC_H
2236999e6aSKarim Taha 
2336999e6aSKarim Taha #include <sys/param.h>
2436999e6aSKarim Taha #include <sys/procctl.h>
2536999e6aSKarim Taha #include <sys/signal.h>
2636999e6aSKarim Taha #include <sys/types.h>
2736999e6aSKarim Taha #include <sys/procdesc.h>
2836999e6aSKarim Taha #include <sys/wait.h>
2936999e6aSKarim Taha #include <unistd.h>
3036999e6aSKarim Taha 
3136999e6aSKarim Taha #include "target_arch_cpu.h"
3236999e6aSKarim Taha 
33ae502887SStacey Son pid_t safe_wait4(pid_t wpid, int *status, int options, struct rusage *rusage);
34ae502887SStacey Son pid_t safe_wait6(idtype_t idtype, id_t id, int *status, int options,
35ae502887SStacey Son     struct __wrusage *wrusage, siginfo_t *infop);
36ae502887SStacey Son 
370571e3f5SStacey Son extern int __setugid(int flag);
380571e3f5SStacey Son 
3936999e6aSKarim Taha /* execve(2) */
do_freebsd_execve(abi_ulong path_or_fd,abi_ulong argp,abi_ulong envp)4036999e6aSKarim Taha static inline abi_long do_freebsd_execve(abi_ulong path_or_fd, abi_ulong argp,
4136999e6aSKarim Taha         abi_ulong envp)
4236999e6aSKarim Taha {
4336999e6aSKarim Taha 
4436999e6aSKarim Taha     return freebsd_exec_common(path_or_fd, argp, envp, 0);
4536999e6aSKarim Taha }
4636999e6aSKarim Taha 
4736999e6aSKarim Taha /* fexecve(2) */
do_freebsd_fexecve(abi_ulong path_or_fd,abi_ulong argp,abi_ulong envp)4836999e6aSKarim Taha static inline abi_long do_freebsd_fexecve(abi_ulong path_or_fd, abi_ulong argp,
4936999e6aSKarim Taha         abi_ulong envp)
5036999e6aSKarim Taha {
5136999e6aSKarim Taha 
5236999e6aSKarim Taha     return freebsd_exec_common(path_or_fd, argp, envp, 1);
5336999e6aSKarim Taha }
5436999e6aSKarim Taha 
55ae502887SStacey Son /* wait4(2) */
do_freebsd_wait4(abi_long arg1,abi_ulong target_status,abi_long arg3,abi_ulong target_rusage)56ae502887SStacey Son static inline abi_long do_freebsd_wait4(abi_long arg1, abi_ulong target_status,
57ae502887SStacey Son         abi_long arg3, abi_ulong target_rusage)
58ae502887SStacey Son {
59ae502887SStacey Son     abi_long ret;
60ae502887SStacey Son     int status;
61ae502887SStacey Son     struct rusage rusage, *rusage_ptr = NULL;
62ae502887SStacey Son 
63ae502887SStacey Son     if (target_rusage) {
64ae502887SStacey Son         rusage_ptr = &rusage;
65ae502887SStacey Son     }
66ae502887SStacey Son     ret = get_errno(safe_wait4(arg1, &status, arg3, rusage_ptr));
67ae502887SStacey Son 
68ae502887SStacey Son     if (ret < 0) {
69ae502887SStacey Son         return ret;
70ae502887SStacey Son     }
71ae502887SStacey Son     if (target_status != 0) {
72ae502887SStacey Son         status = host_to_target_waitstatus(status);
73ae502887SStacey Son         if (put_user_s32(status, target_status) != 0) {
74ae502887SStacey Son             return -TARGET_EFAULT;
75ae502887SStacey Son         }
76ae502887SStacey Son     }
77ae502887SStacey Son     if (target_rusage != 0) {
78ae502887SStacey Son         host_to_target_rusage(target_rusage, &rusage);
79ae502887SStacey Son     }
80ae502887SStacey Son     return ret;
81ae502887SStacey Son }
82ae502887SStacey Son 
83ae502887SStacey Son /* wait6(2) */
do_freebsd_wait6(void * cpu_env,abi_long idtype,abi_long id1,abi_long id2,abi_ulong target_status,abi_long options,abi_ulong target_wrusage,abi_ulong target_infop,abi_ulong pad1)84ae502887SStacey Son static inline abi_long do_freebsd_wait6(void *cpu_env, abi_long idtype,
85ae502887SStacey Son     abi_long id1, abi_long id2,
86ae502887SStacey Son     abi_ulong target_status, abi_long options, abi_ulong target_wrusage,
87ae502887SStacey Son     abi_ulong target_infop, abi_ulong pad1)
88ae502887SStacey Son {
89ae502887SStacey Son     abi_long ret;
90ae502887SStacey Son     int status;
91ae502887SStacey Son     struct __wrusage wrusage, *wrusage_ptr = NULL;
92ae502887SStacey Son     siginfo_t info;
93ae502887SStacey Son     void *p;
94ae502887SStacey Son 
95ae502887SStacey Son     if (regpairs_aligned(cpu_env) != 0) {
96ae502887SStacey Son         /* printf("shifting args\n"); */
97ae502887SStacey Son         /* 64-bit id is aligned, so shift all the arguments over by one */
98ae502887SStacey Son         id1 = id2;
99ae502887SStacey Son         id2 = target_status;
100ae502887SStacey Son         target_status = options;
101ae502887SStacey Son         options = target_wrusage;
102ae502887SStacey Son         target_wrusage = target_infop;
103ae502887SStacey Son         target_infop = pad1;
104ae502887SStacey Son     }
105ae502887SStacey Son 
106ae502887SStacey Son     if (target_wrusage) {
107ae502887SStacey Son         wrusage_ptr = &wrusage;
108ae502887SStacey Son     }
109ae502887SStacey Son     ret = get_errno(safe_wait6(idtype, target_arg64(id1, id2),
110ae502887SStacey Son                                &status, options, wrusage_ptr, &info));
111ae502887SStacey Son 
112ae502887SStacey Son     if (ret < 0) {
113ae502887SStacey Son         return ret;
114ae502887SStacey Son     }
115ae502887SStacey Son     if (target_status != 0) {
116ae502887SStacey Son         status = host_to_target_waitstatus(status);
117ae502887SStacey Son         if (put_user_s32(status, target_status) != 0) {
118ae502887SStacey Son             return -TARGET_EFAULT;
119ae502887SStacey Son         }
120ae502887SStacey Son     }
121ae502887SStacey Son     if (target_wrusage != 0) {
122ae502887SStacey Son         host_to_target_wrusage(target_wrusage, &wrusage);
123ae502887SStacey Son     }
124ae502887SStacey Son     if (target_infop != 0) {
125ae502887SStacey Son         p = lock_user(VERIFY_WRITE, target_infop, sizeof(target_siginfo_t), 0);
126ae502887SStacey Son         if (p == NULL) {
127ae502887SStacey Son             return -TARGET_EFAULT;
128ae502887SStacey Son         }
129ae502887SStacey Son         host_to_target_siginfo(p, &info);
130ae502887SStacey Son         unlock_user(p, target_infop, sizeof(target_siginfo_t));
131ae502887SStacey Son     }
132ae502887SStacey Son     return ret;
133ae502887SStacey Son }
134ae502887SStacey Son 
135159e5b0cSStacey Son /* setloginclass(2) */
do_freebsd_setloginclass(abi_ulong arg1)136159e5b0cSStacey Son static inline abi_long do_freebsd_setloginclass(abi_ulong arg1)
137159e5b0cSStacey Son {
138159e5b0cSStacey Son     abi_long ret;
139159e5b0cSStacey Son     void *p;
140159e5b0cSStacey Son 
141159e5b0cSStacey Son     p = lock_user_string(arg1);
142159e5b0cSStacey Son     if (p == NULL) {
143159e5b0cSStacey Son         return -TARGET_EFAULT;
144159e5b0cSStacey Son     }
145159e5b0cSStacey Son     ret = get_errno(setloginclass(p));
146159e5b0cSStacey Son     unlock_user(p, arg1, 0);
147159e5b0cSStacey Son 
148159e5b0cSStacey Son     return ret;
149159e5b0cSStacey Son }
150159e5b0cSStacey Son 
151159e5b0cSStacey Son /* getloginclass(2) */
do_freebsd_getloginclass(abi_ulong arg1,abi_ulong arg2)152159e5b0cSStacey Son static inline abi_long do_freebsd_getloginclass(abi_ulong arg1, abi_ulong arg2)
153159e5b0cSStacey Son {
154159e5b0cSStacey Son     abi_long ret;
155159e5b0cSStacey Son     void *p;
156159e5b0cSStacey Son 
157159e5b0cSStacey Son     p = lock_user(VERIFY_WRITE, arg1, arg2, 0);
158159e5b0cSStacey Son     if (p == NULL) {
159159e5b0cSStacey Son         return -TARGET_EFAULT;
160159e5b0cSStacey Son     }
161159e5b0cSStacey Son     ret = get_errno(getloginclass(p, arg2));
162159e5b0cSStacey Son     unlock_user(p, arg1, arg2);
163159e5b0cSStacey Son 
164159e5b0cSStacey Son     return ret;
165159e5b0cSStacey Son }
166159e5b0cSStacey Son 
1670571e3f5SStacey Son /* pdgetpid(2) */
do_freebsd_pdgetpid(abi_long fd,abi_ulong target_pidp)1680571e3f5SStacey Son static inline abi_long do_freebsd_pdgetpid(abi_long fd, abi_ulong target_pidp)
1690571e3f5SStacey Son {
1700571e3f5SStacey Son     abi_long ret;
1710571e3f5SStacey Son     pid_t pid;
1720571e3f5SStacey Son 
1730571e3f5SStacey Son     ret = get_errno(pdgetpid(fd, &pid));
1740571e3f5SStacey Son     if (!is_error(ret)) {
1750571e3f5SStacey Son         if (put_user_u32(pid, target_pidp)) {
1760571e3f5SStacey Son             return -TARGET_EFAULT;
1770571e3f5SStacey Son         }
1780571e3f5SStacey Son     }
1790571e3f5SStacey Son     return ret;
1800571e3f5SStacey Son }
1810571e3f5SStacey Son 
1820571e3f5SStacey Son /* undocumented __setugid */
do_freebsd___setugid(abi_long arg1)1830571e3f5SStacey Son static inline abi_long do_freebsd___setugid(abi_long arg1)
1840571e3f5SStacey Son {
1850571e3f5SStacey Son     return -TARGET_ENOSYS;
1860571e3f5SStacey Son }
1870571e3f5SStacey Son 
188831a5a7fSStacey Son /* fork(2) */
do_freebsd_fork(void * cpu_env)189831a5a7fSStacey Son static inline abi_long do_freebsd_fork(void *cpu_env)
190831a5a7fSStacey Son {
191831a5a7fSStacey Son     abi_long ret;
192831a5a7fSStacey Son     abi_ulong child_flag;
193831a5a7fSStacey Son 
194831a5a7fSStacey Son     fork_start();
195831a5a7fSStacey Son     ret = fork();
196831a5a7fSStacey Son     if (ret == 0) {
197831a5a7fSStacey Son         /* child */
198831a5a7fSStacey Son         child_flag = 1;
199831a5a7fSStacey Son         target_cpu_clone_regs(cpu_env, 0);
200831a5a7fSStacey Son     } else {
201831a5a7fSStacey Son         /* parent */
202831a5a7fSStacey Son         child_flag = 0;
203831a5a7fSStacey Son     }
204831a5a7fSStacey Son 
205831a5a7fSStacey Son     /*
206831a5a7fSStacey Son      * The fork system call sets a child flag in the second return
207831a5a7fSStacey Son      * value: 0 for parent process, 1 for child process.
208831a5a7fSStacey Son      */
209831a5a7fSStacey Son     set_second_rval(cpu_env, child_flag);
210831a5a7fSStacey Son 
211*4edc98fcSIlya Leoshkevich     fork_end(ret);
212831a5a7fSStacey Son 
213831a5a7fSStacey Son     return ret;
214831a5a7fSStacey Son }
215831a5a7fSStacey Son 
216831a5a7fSStacey Son /* vfork(2) */
do_freebsd_vfork(void * cpu_env)217831a5a7fSStacey Son static inline abi_long do_freebsd_vfork(void *cpu_env)
218831a5a7fSStacey Son {
219831a5a7fSStacey Son     return do_freebsd_fork(cpu_env);
220831a5a7fSStacey Son }
221831a5a7fSStacey Son 
222510eecbcSStacey Son /* rfork(2) */
do_freebsd_rfork(void * cpu_env,abi_long flags)223510eecbcSStacey Son static inline abi_long do_freebsd_rfork(void *cpu_env, abi_long flags)
224510eecbcSStacey Son {
225510eecbcSStacey Son     abi_long ret;
226510eecbcSStacey Son     abi_ulong child_flag;
227510eecbcSStacey Son 
228510eecbcSStacey Son     /*
229510eecbcSStacey Son      * XXX We need to handle RFMEM here, as well.  Neither are safe to execute
230510eecbcSStacey Son      * as-is on x86 hosts because they'll split memory but not the stack,
231510eecbcSStacey Son      * wreaking havoc on host architectures that use the stack to store the
232510eecbcSStacey Son      * return address as both threads try to pop it off.  Rejecting RFSPAWN
233510eecbcSStacey Son      * entirely for now is ok, the only consumer at the moment is posix_spawn
234510eecbcSStacey Son      * and it will fall back to classic vfork(2) if we return EINVAL.
235510eecbcSStacey Son      */
236510eecbcSStacey Son     if ((flags & TARGET_RFSPAWN) != 0) {
237510eecbcSStacey Son         return -TARGET_EINVAL;
238510eecbcSStacey Son     }
239510eecbcSStacey Son     fork_start();
240510eecbcSStacey Son     ret = rfork(flags);
241510eecbcSStacey Son     if (ret == 0) {
242510eecbcSStacey Son         /* child */
243510eecbcSStacey Son         child_flag = 1;
244510eecbcSStacey Son         target_cpu_clone_regs(cpu_env, 0);
245510eecbcSStacey Son     } else {
246510eecbcSStacey Son         /* parent */
247510eecbcSStacey Son         child_flag = 0;
248510eecbcSStacey Son     }
249510eecbcSStacey Son 
250510eecbcSStacey Son     /*
251510eecbcSStacey Son      * The fork system call sets a child flag in the second return
252510eecbcSStacey Son      * value: 0 for parent process, 1 for child process.
253510eecbcSStacey Son      */
254510eecbcSStacey Son     set_second_rval(cpu_env, child_flag);
255*4edc98fcSIlya Leoshkevich     fork_end(ret);
256510eecbcSStacey Son 
257510eecbcSStacey Son     return ret;
258510eecbcSStacey Son 
259510eecbcSStacey Son }
260510eecbcSStacey Son 
2616756ae28SStacey Son /* pdfork(2) */
do_freebsd_pdfork(void * cpu_env,abi_ulong target_fdp,abi_long flags)2626756ae28SStacey Son static inline abi_long do_freebsd_pdfork(void *cpu_env, abi_ulong target_fdp,
2636756ae28SStacey Son         abi_long flags)
2646756ae28SStacey Son {
2656756ae28SStacey Son     abi_long ret;
2666756ae28SStacey Son     abi_ulong child_flag;
2676756ae28SStacey Son     int fd;
2686756ae28SStacey Son 
2696756ae28SStacey Son     fork_start();
2706756ae28SStacey Son     ret = pdfork(&fd, flags);
2716756ae28SStacey Son     if (ret == 0) {
2726756ae28SStacey Son         /* child */
2736756ae28SStacey Son         child_flag = 1;
2746756ae28SStacey Son         target_cpu_clone_regs(cpu_env, 0);
2756756ae28SStacey Son     } else {
2766756ae28SStacey Son         /* parent */
2776756ae28SStacey Son         child_flag = 0;
2786756ae28SStacey Son         if (put_user_s32(fd, target_fdp)) {
2796756ae28SStacey Son             return -TARGET_EFAULT;
2806756ae28SStacey Son         }
2816756ae28SStacey Son     }
2826756ae28SStacey Son 
2836756ae28SStacey Son     /*
2846756ae28SStacey Son      * The fork system call sets a child flag in the second return
2856756ae28SStacey Son      * value: 0 for parent process, 1 for child process.
2866756ae28SStacey Son      */
2876756ae28SStacey Son     set_second_rval(cpu_env, child_flag);
288*4edc98fcSIlya Leoshkevich     fork_end(ret);
2896756ae28SStacey Son 
2906756ae28SStacey Son     return ret;
2916756ae28SStacey Son }
2926756ae28SStacey Son 
29336999e6aSKarim Taha #endif /* BSD_USER_FREEBSD_OS_PROC_H */
294