1 /* $NetBSD: linux32_misc.c,v 1.21 2010/11/02 18:18:07 chs Exp $ */ 2 3 /*- 4 * Copyright (c) 1995, 1998, 1999 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Frank van der Linden and Eric Haszlakiewicz; by Jason R. Thorpe 9 * of the Numerical Aerospace Simulation Facility, NASA Ames Research Center; 10 * by Edgar Fu\ss, Mathematisches Institut der Uni Bonn. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 23 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 * POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include <sys/cdefs.h> 35 __KERNEL_RCSID(0, "$NetBSD: linux32_misc.c,v 1.21 2010/11/02 18:18:07 chs Exp $"); 36 37 #include <sys/param.h> 38 #include <sys/proc.h> 39 #include <sys/time.h> 40 #include <sys/types.h> 41 #include <sys/malloc.h> 42 #include <sys/fstypes.h> 43 #include <sys/vfs_syscalls.h> 44 #include <sys/ptrace.h> 45 #include <sys/syscall.h> 46 47 #include <compat/netbsd32/netbsd32.h> 48 #include <compat/netbsd32/netbsd32_syscallargs.h> 49 50 #include <compat/linux32/common/linux32_types.h> 51 #include <compat/linux32/common/linux32_signal.h> 52 #include <compat/linux32/linux32_syscallargs.h> 53 54 #include <compat/linux/common/linux_ptrace.h> 55 #include <compat/linux/common/linux_types.h> 56 #include <compat/linux/common/linux_emuldata.h> 57 #include <compat/linux/common/linux_signal.h> 58 #include <compat/linux/common/linux_misc.h> 59 #include <compat/linux/common/linux_statfs.h> 60 #include <compat/linux/common/linux_ipc.h> 61 #include <compat/linux/common/linux_sem.h> 62 #include <compat/linux/common/linux_futex.h> 63 #include <compat/linux/linux_syscallargs.h> 64 65 extern const struct linux_mnttypes linux_fstypes[]; 66 extern const int linux_fstypes_cnt; 67 68 void linux32_to_native_timespec(struct timespec *, struct linux32_timespec *); 69 70 /* 71 * Implement the fs stat functions. Straightforward. 72 */ 73 int 74 linux32_sys_statfs(struct lwp *l, const struct linux32_sys_statfs_args *uap, register_t *retval) 75 { 76 /* { 77 syscallarg(const netbsd32_charp char) path; 78 syscallarg(linux32_statfsp) sp; 79 } */ 80 struct statvfs *sb; 81 struct linux_statfs ltmp; 82 int error; 83 84 sb = STATVFSBUF_GET(); 85 error = do_sys_pstatvfs(l, SCARG_P32(uap, path), ST_WAIT, sb); 86 if (error == 0) { 87 bsd_to_linux_statfs(sb, <mp); 88 error = copyout(<mp, SCARG_P32(uap, sp), sizeof ltmp); 89 } 90 91 STATVFSBUF_PUT(sb); 92 return error; 93 } 94 95 int 96 linux32_sys_fstatfs(struct lwp *l, const struct linux32_sys_fstatfs_args *uap, register_t *retval) 97 { 98 /* { 99 syscallarg(int) fd; 100 syscallarg(linux32_statfsp) sp; 101 } */ 102 struct statvfs *sb; 103 struct linux_statfs ltmp; 104 int error; 105 106 sb = STATVFSBUF_GET(); 107 error = do_sys_fstatvfs(l, SCARG(uap, fd), ST_WAIT, sb); 108 if (error == 0) { 109 bsd_to_linux_statfs(sb, <mp); 110 error = copyout(<mp, SCARG_P32(uap, sp), sizeof ltmp); 111 } 112 STATVFSBUF_PUT(sb); 113 114 return error; 115 } 116 117 int 118 linux32_sys_statfs64(struct lwp *l, const struct linux32_sys_statfs64_args *uap, register_t *retval) 119 { 120 /* { 121 syscallarg(const netbsd32_charp char) path; 122 syscallarg(linux32_statfs64p) sp; 123 } */ 124 struct statvfs *sb; 125 struct linux_statfs64 ltmp; 126 int error; 127 128 sb = STATVFSBUF_GET(); 129 error = do_sys_pstatvfs(l, SCARG_P32(uap, path), ST_WAIT, sb); 130 if (error == 0) { 131 bsd_to_linux_statfs64(sb, <mp); 132 error = copyout(<mp, SCARG_P32(uap, sp), sizeof ltmp); 133 } 134 135 STATVFSBUF_PUT(sb); 136 return error; 137 } 138 139 int 140 linux32_sys_fstatfs64(struct lwp *l, const struct linux32_sys_fstatfs64_args *uap, register_t *retval) 141 { 142 /* { 143 syscallarg(int) fd; 144 syscallarg(linux32_statfs64p) sp; 145 } */ 146 struct statvfs *sb; 147 struct linux_statfs64 ltmp; 148 int error; 149 150 sb = STATVFSBUF_GET(); 151 error = do_sys_fstatvfs(l, SCARG(uap, fd), ST_WAIT, sb); 152 if (error == 0) { 153 bsd_to_linux_statfs64(sb, <mp); 154 error = copyout(<mp, SCARG_P32(uap, sp), sizeof ltmp); 155 } 156 STATVFSBUF_PUT(sb); 157 158 return error; 159 } 160 161 extern const int linux_ptrace_request_map[]; 162 163 int 164 linux32_sys_ptrace(struct lwp *l, const struct linux32_sys_ptrace_args *uap, register_t *retval) 165 { 166 /* { 167 i386, m68k, powerpc: T=int 168 alpha, amd64: T=long 169 syscallarg(T) request; 170 syscallarg(T) pid; 171 syscallarg(T) addr; 172 syscallarg(T) data; 173 } */ 174 const int *ptr; 175 int request; 176 int error; 177 178 ptr = linux_ptrace_request_map; 179 request = SCARG(uap, request); 180 while (*ptr != -1) 181 if (*ptr++ == request) { 182 struct sys_ptrace_args pta; 183 184 SCARG(&pta, req) = *ptr; 185 SCARG(&pta, pid) = SCARG(uap, pid); 186 SCARG(&pta, addr) = NETBSD32IPTR64(SCARG(uap, addr)); 187 SCARG(&pta, data) = SCARG(uap, data); 188 189 /* 190 * Linux ptrace(PTRACE_CONT, pid, 0, 0) means actually 191 * to continue where the process left off previously. 192 * The same thing is achieved by addr == (void *) 1 193 * on NetBSD, so rewrite 'addr' appropriately. 194 */ 195 if (request == LINUX_PTRACE_CONT && SCARG(uap, addr)==0) 196 SCARG(&pta, addr) = (void *) 1; 197 198 error = sysent[SYS_ptrace].sy_call(l, &pta, retval); 199 if (error) 200 return error; 201 switch (request) { 202 case LINUX_PTRACE_PEEKTEXT: 203 case LINUX_PTRACE_PEEKDATA: 204 error = copyout (retval, 205 NETBSD32IPTR64(SCARG(uap, data)), 206 sizeof *retval); 207 *retval = SCARG(uap, data); 208 break; 209 default: 210 break; 211 } 212 return error; 213 } 214 else 215 ptr++; 216 217 return EIO; 218 } 219 220 int 221 linux32_sys_personality(struct lwp *l, const struct linux32_sys_personality_args *uap, register_t *retval) 222 { 223 /* { 224 syscallarg(netbsd32_u_long) per; 225 } */ 226 struct linux_sys_personality_args ua; 227 228 NETBSD32TOX_UAP(per, long); 229 return linux_sys_personality(l, &ua, retval); 230 } 231 232 int 233 linux32_sys_futex(struct lwp *l, 234 const struct linux32_sys_futex_args *uap, register_t *retval) 235 { 236 /* { 237 syscallarg(linux32_intp_t) uaddr; 238 syscallarg(int) op; 239 syscallarg(int) val; 240 syscallarg(linux32_timespecp_t) timeout; 241 syscallarg(linux32_intp_t) uaddr2; 242 syscallarg(int) val3; 243 } */ 244 struct linux_sys_futex_args ua; 245 struct linux32_timespec lts; 246 struct timespec ts = { 0, 0 }; 247 int error; 248 249 NETBSD32TOP_UAP(uaddr, int); 250 NETBSD32TO64_UAP(op); 251 NETBSD32TO64_UAP(val); 252 NETBSD32TOP_UAP(timeout, struct linux_timespec); 253 NETBSD32TOP_UAP(uaddr2, int); 254 NETBSD32TO64_UAP(val3); 255 if ((SCARG(uap, op) & ~LINUX_FUTEX_PRIVATE_FLAG) == LINUX_FUTEX_WAIT && 256 SCARG_P32(uap, timeout) != NULL) { 257 if ((error = copyin((void *)SCARG_P32(uap, timeout), 258 <s, sizeof(lts))) != 0) { 259 return error; 260 } 261 linux32_to_native_timespec(&ts, <s); 262 } 263 return linux_do_futex(l, &ua, retval, &ts); 264 } 265 266 int 267 linux32_sys_set_robust_list(struct lwp *l, 268 const struct linux32_sys_set_robust_list_args *uap, register_t *retval) 269 { 270 /* { 271 syscallarg(linux32_robust_list_headp_t) head; 272 syscallarg(linux32_size_t) len; 273 } */ 274 struct linux_sys_set_robust_list_args ua; 275 struct linux_emuldata *led; 276 277 if (SCARG(uap, len) != 12) 278 return EINVAL; 279 280 NETBSD32TOP_UAP(head, struct robust_list_head); 281 NETBSD32TOX64_UAP(len, size_t); 282 283 led = l->l_emuldata; 284 led->led_robust_head = SCARG(&ua, head); 285 *retval = 0; 286 return 0; 287 } 288 289 int 290 linux32_sys_get_robust_list(struct lwp *l, 291 const struct linux32_sys_get_robust_list_args *uap, register_t *retval) 292 { 293 /* { 294 syscallarg(linux32_robust_list_headpp_t) head; 295 syscallarg(linux32_sizep_t) len; 296 } */ 297 struct linux_sys_get_robust_list_args ua; 298 299 NETBSD32TOP_UAP(head, struct robust_list_head *); 300 NETBSD32TOP_UAP(len, size_t *); 301 return linux_sys_get_robust_list(l, &ua, retval); 302 } 303 304 int 305 linux32_sys_truncate64(struct lwp *l, const struct linux32_sys_truncate64_args *uap, register_t *retval) 306 { 307 /* { 308 syscallarg(netbsd32_charp) path; 309 syscallarg(off_t) length; 310 } */ 311 struct sys_truncate_args ua; 312 313 /* Linux doesn't have the 'pad' pseudo-parameter */ 314 NETBSD32TOP_UAP(path, const char *); 315 SCARG(&ua, PAD) = 0; 316 SCARG(&ua, length) = ((off_t)SCARG(uap, lenhi) << 32) + SCARG(uap, lenlo); 317 return sys_truncate(l, &ua, retval); 318 } 319 320 int 321 linux32_sys_ftruncate64(struct lwp *l, const struct linux32_sys_ftruncate64_args *uap, register_t *retval) 322 { 323 /* { 324 syscallarg(unsigned int) fd; 325 syscallarg(off_t) length; 326 } */ 327 struct sys_ftruncate_args ua; 328 329 /* Linux doesn't have the 'pad' pseudo-parameter */ 330 NETBSD32TO64_UAP(fd); 331 SCARG(&ua, PAD) = 0; 332 SCARG(&ua, length) = ((off_t)SCARG(uap, lenhi) << 32) + SCARG(uap, lenlo); 333 return sys_ftruncate(l, &ua, retval); 334 } 335 336 int 337 linux32_sys_setdomainname(struct lwp *l, const struct linux32_sys_setdomainname_args *uap, register_t *retval) 338 { 339 /* { 340 syscallarg(netbsd32_charp) domainname; 341 syscallarg(int) len; 342 } */ 343 struct linux_sys_setdomainname_args ua; 344 345 NETBSD32TOP_UAP(domainname, char); 346 NETBSD32TO64_UAP(len); 347 return linux_sys_setdomainname(l, &ua, retval); 348 } 349