1 /* 2 * process related system call shims and definitions 3 * 4 * Copyright (c) 2013-14 Stacey D. Son 5 * 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 2 of the License, or 9 * (at your option) any later version. 10 * 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. 15 * 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/>. 18 */ 19 20 #ifndef BSD_USER_FREEBSD_OS_PROC_H 21 #define BSD_USER_FREEBSD_OS_PROC_H 22 23 #include <sys/param.h> 24 #include <sys/procctl.h> 25 #include <sys/signal.h> 26 #include <sys/types.h> 27 #include <sys/procdesc.h> 28 #include <sys/wait.h> 29 #include <unistd.h> 30 31 #include "target_arch_cpu.h" 32 33 pid_t safe_wait4(pid_t wpid, int *status, int options, struct rusage *rusage); 34 pid_t safe_wait6(idtype_t idtype, id_t id, int *status, int options, 35 struct __wrusage *wrusage, siginfo_t *infop); 36 37 extern int __setugid(int flag); 38 39 /* execve(2) */ 40 static inline abi_long do_freebsd_execve(abi_ulong path_or_fd, abi_ulong argp, 41 abi_ulong envp) 42 { 43 44 return freebsd_exec_common(path_or_fd, argp, envp, 0); 45 } 46 47 /* fexecve(2) */ 48 static inline abi_long do_freebsd_fexecve(abi_ulong path_or_fd, abi_ulong argp, 49 abi_ulong envp) 50 { 51 52 return freebsd_exec_common(path_or_fd, argp, envp, 1); 53 } 54 55 /* wait4(2) */ 56 static inline abi_long do_freebsd_wait4(abi_long arg1, abi_ulong target_status, 57 abi_long arg3, abi_ulong target_rusage) 58 { 59 abi_long ret; 60 int status; 61 struct rusage rusage, *rusage_ptr = NULL; 62 63 if (target_rusage) { 64 rusage_ptr = &rusage; 65 } 66 ret = get_errno(safe_wait4(arg1, &status, arg3, rusage_ptr)); 67 68 if (ret < 0) { 69 return ret; 70 } 71 if (target_status != 0) { 72 status = host_to_target_waitstatus(status); 73 if (put_user_s32(status, target_status) != 0) { 74 return -TARGET_EFAULT; 75 } 76 } 77 if (target_rusage != 0) { 78 host_to_target_rusage(target_rusage, &rusage); 79 } 80 return ret; 81 } 82 83 /* wait6(2) */ 84 static inline abi_long do_freebsd_wait6(void *cpu_env, abi_long idtype, 85 abi_long id1, abi_long id2, 86 abi_ulong target_status, abi_long options, abi_ulong target_wrusage, 87 abi_ulong target_infop, abi_ulong pad1) 88 { 89 abi_long ret; 90 int status; 91 struct __wrusage wrusage, *wrusage_ptr = NULL; 92 siginfo_t info; 93 void *p; 94 95 if (regpairs_aligned(cpu_env) != 0) { 96 /* printf("shifting args\n"); */ 97 /* 64-bit id is aligned, so shift all the arguments over by one */ 98 id1 = id2; 99 id2 = target_status; 100 target_status = options; 101 options = target_wrusage; 102 target_wrusage = target_infop; 103 target_infop = pad1; 104 } 105 106 if (target_wrusage) { 107 wrusage_ptr = &wrusage; 108 } 109 ret = get_errno(safe_wait6(idtype, target_arg64(id1, id2), 110 &status, options, wrusage_ptr, &info)); 111 112 if (ret < 0) { 113 return ret; 114 } 115 if (target_status != 0) { 116 status = host_to_target_waitstatus(status); 117 if (put_user_s32(status, target_status) != 0) { 118 return -TARGET_EFAULT; 119 } 120 } 121 if (target_wrusage != 0) { 122 host_to_target_wrusage(target_wrusage, &wrusage); 123 } 124 if (target_infop != 0) { 125 p = lock_user(VERIFY_WRITE, target_infop, sizeof(target_siginfo_t), 0); 126 if (p == NULL) { 127 return -TARGET_EFAULT; 128 } 129 host_to_target_siginfo(p, &info); 130 unlock_user(p, target_infop, sizeof(target_siginfo_t)); 131 } 132 return ret; 133 } 134 135 /* setloginclass(2) */ 136 static inline abi_long do_freebsd_setloginclass(abi_ulong arg1) 137 { 138 abi_long ret; 139 void *p; 140 141 p = lock_user_string(arg1); 142 if (p == NULL) { 143 return -TARGET_EFAULT; 144 } 145 ret = get_errno(setloginclass(p)); 146 unlock_user(p, arg1, 0); 147 148 return ret; 149 } 150 151 /* getloginclass(2) */ 152 static inline abi_long do_freebsd_getloginclass(abi_ulong arg1, abi_ulong arg2) 153 { 154 abi_long ret; 155 void *p; 156 157 p = lock_user(VERIFY_WRITE, arg1, arg2, 0); 158 if (p == NULL) { 159 return -TARGET_EFAULT; 160 } 161 ret = get_errno(getloginclass(p, arg2)); 162 unlock_user(p, arg1, arg2); 163 164 return ret; 165 } 166 167 /* pdgetpid(2) */ 168 static inline abi_long do_freebsd_pdgetpid(abi_long fd, abi_ulong target_pidp) 169 { 170 abi_long ret; 171 pid_t pid; 172 173 ret = get_errno(pdgetpid(fd, &pid)); 174 if (!is_error(ret)) { 175 if (put_user_u32(pid, target_pidp)) { 176 return -TARGET_EFAULT; 177 } 178 } 179 return ret; 180 } 181 182 /* undocumented __setugid */ 183 static inline abi_long do_freebsd___setugid(abi_long arg1) 184 { 185 return -TARGET_ENOSYS; 186 } 187 188 /* fork(2) */ 189 static inline abi_long do_freebsd_fork(void *cpu_env) 190 { 191 abi_long ret; 192 abi_ulong child_flag; 193 194 fork_start(); 195 ret = fork(); 196 if (ret == 0) { 197 /* child */ 198 child_flag = 1; 199 target_cpu_clone_regs(cpu_env, 0); 200 } else { 201 /* parent */ 202 child_flag = 0; 203 } 204 205 /* 206 * The fork system call sets a child flag in the second return 207 * value: 0 for parent process, 1 for child process. 208 */ 209 set_second_rval(cpu_env, child_flag); 210 211 fork_end(ret); 212 213 return ret; 214 } 215 216 /* vfork(2) */ 217 static inline abi_long do_freebsd_vfork(void *cpu_env) 218 { 219 return do_freebsd_fork(cpu_env); 220 } 221 222 /* rfork(2) */ 223 static inline abi_long do_freebsd_rfork(void *cpu_env, abi_long flags) 224 { 225 abi_long ret; 226 abi_ulong child_flag; 227 228 /* 229 * XXX We need to handle RFMEM here, as well. Neither are safe to execute 230 * as-is on x86 hosts because they'll split memory but not the stack, 231 * wreaking havoc on host architectures that use the stack to store the 232 * return address as both threads try to pop it off. Rejecting RFSPAWN 233 * entirely for now is ok, the only consumer at the moment is posix_spawn 234 * and it will fall back to classic vfork(2) if we return EINVAL. 235 */ 236 if ((flags & TARGET_RFSPAWN) != 0) { 237 return -TARGET_EINVAL; 238 } 239 fork_start(); 240 ret = rfork(flags); 241 if (ret == 0) { 242 /* child */ 243 child_flag = 1; 244 target_cpu_clone_regs(cpu_env, 0); 245 } else { 246 /* parent */ 247 child_flag = 0; 248 } 249 250 /* 251 * The fork system call sets a child flag in the second return 252 * value: 0 for parent process, 1 for child process. 253 */ 254 set_second_rval(cpu_env, child_flag); 255 fork_end(ret); 256 257 return ret; 258 259 } 260 261 /* pdfork(2) */ 262 static inline abi_long do_freebsd_pdfork(void *cpu_env, abi_ulong target_fdp, 263 abi_long flags) 264 { 265 abi_long ret; 266 abi_ulong child_flag; 267 int fd; 268 269 fork_start(); 270 ret = pdfork(&fd, flags); 271 if (ret == 0) { 272 /* child */ 273 child_flag = 1; 274 target_cpu_clone_regs(cpu_env, 0); 275 } else { 276 /* parent */ 277 child_flag = 0; 278 if (put_user_s32(fd, target_fdp)) { 279 return -TARGET_EFAULT; 280 } 281 } 282 283 /* 284 * The fork system call sets a child flag in the second return 285 * value: 0 for parent process, 1 for child process. 286 */ 287 set_second_rval(cpu_env, child_flag); 288 fork_end(ret); 289 290 return ret; 291 } 292 293 #endif /* BSD_USER_FREEBSD_OS_PROC_H */ 294