1 /* $NetBSD: linux_file.c,v 1.1 1995/02/28 23:24:53 fvdl Exp $ */ 2 3 /* 4 * Copyright (c) 1995 Frank van der Linden 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed for the NetBSD Project 18 * by Frank van der Linden 19 * 4. The name of the author may not be used to endorse or promote products 20 * derived from this software without specific prior written permission 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/namei.h> 37 #include <sys/proc.h> 38 #include <sys/file.h> 39 #include <sys/stat.h> 40 #include <sys/filedesc.h> 41 #include <sys/ioctl.h> 42 #include <sys/kernel.h> 43 #include <sys/mount.h> 44 #include <sys/malloc.h> 45 46 #include <sys/syscallargs.h> 47 48 #include <compat/linux/linux_types.h> 49 #include <compat/linux/linux_syscallargs.h> 50 #include <compat/linux/linux_fcntl.h> 51 #include <compat/linux/linux_util.h> 52 53 /* 54 * Some file-related calls are handled here. The usual flag conversion 55 * an structure conversion is done, and alternate emul path searching. 56 */ 57 58 /* 59 * The next two functions convert between the Linux and NetBSD values 60 * of the flags used in open(2) and fcntl(2). 61 */ 62 static int 63 linux_to_bsd_ioflags(int lflags) 64 { 65 int res = 0; 66 67 res |= cvtto_bsd_mask(lflags, LINUX_O_WRONLY, O_WRONLY); 68 res |= cvtto_bsd_mask(lflags, LINUX_O_RDONLY, O_RDONLY); 69 res |= cvtto_bsd_mask(lflags, LINUX_O_RDWR, O_RDWR); 70 res |= cvtto_bsd_mask(lflags, LINUX_O_CREAT, O_CREAT); 71 res |= cvtto_bsd_mask(lflags, LINUX_O_EXCL, O_EXCL); 72 res |= cvtto_bsd_mask(lflags, LINUX_O_NOCTTY, O_NOCTTY); 73 res |= cvtto_bsd_mask(lflags, LINUX_O_TRUNC, O_TRUNC); 74 res |= cvtto_bsd_mask(lflags, LINUX_O_NDELAY, O_NDELAY); 75 res |= cvtto_bsd_mask(lflags, LINUX_O_SYNC, O_FSYNC); 76 res |= cvtto_bsd_mask(lflags, LINUX_FASYNC, O_ASYNC); 77 res |= cvtto_bsd_mask(lflags, LINUX_O_APPEND, O_APPEND); 78 79 return res; 80 } 81 82 static int 83 bsd_to_linux_ioflags(int bflags) 84 { 85 int res = 0; 86 87 res |= cvtto_linux_mask(bflags, O_WRONLY, LINUX_O_WRONLY); 88 res |= cvtto_linux_mask(bflags, O_RDONLY, LINUX_O_RDONLY); 89 res |= cvtto_linux_mask(bflags, O_RDWR, LINUX_O_RDWR); 90 res |= cvtto_linux_mask(bflags, O_CREAT, LINUX_O_CREAT); 91 res |= cvtto_linux_mask(bflags, O_EXCL, LINUX_O_EXCL); 92 res |= cvtto_linux_mask(bflags, O_NOCTTY, LINUX_O_NOCTTY); 93 res |= cvtto_linux_mask(bflags, O_TRUNC, LINUX_O_TRUNC); 94 res |= cvtto_linux_mask(bflags, O_NDELAY, LINUX_O_NDELAY); 95 res |= cvtto_linux_mask(bflags, O_FSYNC, LINUX_O_SYNC); 96 res |= cvtto_linux_mask(bflags, O_ASYNC, LINUX_FASYNC); 97 res |= cvtto_linux_mask(bflags, O_APPEND, LINUX_O_APPEND); 98 99 return res; 100 } 101 102 /* 103 * creat(2) is an obsolete function, but it's present as a Linux 104 * system call, so let's deal with it. 105 * 106 * Just call open(2) with the TRUNC, CREAT and WRONLY flags. 107 */ 108 int 109 linux_creat(p, uap, retval) 110 struct proc *p; 111 struct linux_creat_args /* { 112 syscallarg(char *) path; 113 syscallarg(int) mode; 114 } */ *uap; 115 register_t *retval; 116 { 117 struct open_args oa; 118 caddr_t sg; 119 120 sg = stackgap_init(); 121 CHECK_ALT(p, &sg, SCARG(uap, path)); 122 123 SCARG(&oa, path) = SCARG(uap, path); 124 SCARG(&oa, flags) = O_CREAT | O_TRUNC | O_WRONLY; 125 SCARG(&oa, mode) = SCARG(uap, mode); 126 return open(p, &oa, retval); 127 } 128 129 /* 130 * open(2). Take care of the different flag values, and let the 131 * NetBSD syscall do the real work. See if this operation 132 * gives the current process a controlling terminal. 133 * (XXX is this necessary?) 134 */ 135 int 136 linux_open(p, uap, retval) 137 struct proc *p; 138 struct linux_open_args /* { 139 syscallarg(char *) path; 140 syscallarg(int) flags; 141 syscallarg(int) mode; 142 } */ *uap; 143 register_t *retval; 144 { 145 int error, fl; 146 struct open_args boa; 147 caddr_t sg; 148 149 sg = stackgap_init(); 150 151 CHECK_ALT(p, &sg, SCARG(uap, path)); 152 153 fl = linux_to_bsd_ioflags(SCARG(uap, flags)); 154 155 SCARG(&boa, path) = SCARG(uap, path); 156 SCARG(&boa, flags) = fl; 157 SCARG(&boa, mode) = SCARG(uap, mode); 158 if ((error = open(p, &boa, retval))) 159 return error; 160 161 /* 162 * this bit from sunos_misc.c (and svr4_fcntl.c). 163 * If we are a session leader, and we don't have a controlling 164 * terminal yet, and the O_NOCTTY flag is not set, try to make 165 * this the controlling terminal. 166 */ 167 if (!(fl & O_NOCTTY) && SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) { 168 struct filedesc *fdp = p->p_fd; 169 struct file *fp = fdp->fd_ofiles[*retval]; 170 171 /* ignore any error, just give it a try */ 172 if (fp->f_type == DTYPE_VNODE) 173 (fp->f_ops->fo_ioctl) (fp, TIOCSCTTY, (caddr_t) 0, p); 174 } 175 return 0; 176 } 177 178 /* 179 * The next two functions take care of converting the flock 180 * structure back and forth between Linux and NetBSD format. 181 * The only difference in the structures is the order of 182 * the fields, and the 'whence' value. 183 */ 184 static void 185 bsd_to_linux_flock(bfp, lfp) 186 struct flock *bfp; 187 struct linux_flock *lfp; 188 { 189 lfp->l_start = bfp->l_start; 190 lfp->l_len = bfp->l_len; 191 lfp->l_pid = bfp->l_pid; 192 lfp->l_type = bfp->l_type; 193 switch (bfp->l_whence) { 194 case F_RDLCK: 195 lfp->l_whence = LINUX_F_RDLCK; 196 break; 197 case F_UNLCK: 198 lfp->l_whence = LINUX_F_UNLCK; 199 break; 200 case F_WRLCK: 201 lfp->l_whence = LINUX_F_WRLCK; 202 break; 203 } 204 } 205 206 static void 207 linux_to_bsd_flock(lfp, bfp) 208 struct linux_flock *lfp; 209 struct flock *bfp; 210 { 211 bfp->l_start = lfp->l_start; 212 bfp->l_len = lfp->l_len; 213 bfp->l_pid = lfp->l_pid; 214 bfp->l_type = lfp->l_type; 215 switch (lfp->l_whence) { 216 case LINUX_F_RDLCK: 217 bfp->l_whence = F_RDLCK; 218 break; 219 case LINUX_F_UNLCK: 220 bfp->l_whence = F_UNLCK; 221 break; 222 case LINUX_F_WRLCK: 223 bfp->l_whence = F_WRLCK; 224 break; 225 } 226 } 227 228 /* 229 * Most actions in the fcntl() call are straightforward; simply 230 * pass control to the NetBSD system call. A few commands need 231 * conversions after the actual system call has done its work, 232 * because the flag values and lock structure are different. 233 */ 234 int 235 linux_fcntl(p, uap, retval) 236 struct proc *p; 237 struct linux_fcntl_args /* { 238 syscallarg(int) fd; 239 syscallarg(int) cmd; 240 syscallarg(void *) arg; 241 } */ *uap; 242 register_t *retval; 243 { 244 int fd, cmd, error, *tval,val; 245 caddr_t arg, sg; 246 struct linux_flock lfl; 247 struct flock *bfp, bfl; 248 struct fcntl_args fca; 249 250 fd = SCARG(uap, fd); 251 cmd = SCARG(uap, cmd); 252 arg = (caddr_t) SCARG(uap, arg); 253 254 switch (cmd) { 255 case LINUX_F_DUPFD: 256 cmd = F_DUPFD; 257 break; 258 case LINUX_F_GETFD: 259 cmd = F_GETFD; 260 break; 261 case LINUX_F_SETFD: 262 cmd = F_SETFD; 263 break; 264 case LINUX_F_GETFL: 265 SCARG(&fca, fd) = fd; 266 SCARG(&fca, cmd) = F_GETFL; 267 SCARG(&fca, arg) = arg; 268 if ((error = fcntl(p, &fca, retval))) 269 return error; 270 retval[0] = bsd_to_linux_ioflags(retval[0]); 271 return 0; 272 case LINUX_F_SETFL: 273 if ((error = copyin(SCARG(uap, arg), &val, sizeof (int)))) 274 return error; 275 val = linux_to_bsd_ioflags(val); 276 sg = stackgap_init(); 277 tval = (int *) stackgap_alloc(&sg, sizeof (int)); 278 if ((error = copyout(&val, tval, sizeof (int)))) 279 return error; 280 SCARG(&fca, fd) = fd; 281 SCARG(&fca, cmd) = F_SETFL; 282 SCARG(&fca, arg) = tval; 283 return fcntl(p, &fca, retval); 284 case LINUX_F_GETLK: 285 sg = stackgap_init(); 286 bfp = (struct flock *) stackgap_alloc(&sg, sizeof *bfp); 287 SCARG(&fca, fd) = fd; 288 SCARG(&fca, cmd) = F_GETLK; 289 SCARG(&fca, arg) = bfp; 290 if ((error = fcntl(p, &fca, retval))) 291 return error; 292 if ((error = copyin(bfp, &bfl, sizeof bfl))) 293 return error; 294 bsd_to_linux_flock(&bfl, &lfl); 295 return copyout(&lfl, arg, sizeof lfl); 296 break; 297 case LINUX_F_SETLK: 298 case LINUX_F_SETLKW: 299 cmd = (cmd == LINUX_F_SETLK ? F_SETLK : F_SETLKW); 300 if ((error = copyin(arg, &lfl, sizeof lfl))) 301 return error; 302 linux_to_bsd_flock(&lfl, &bfl); 303 sg = stackgap_init(); 304 bfp = (struct flock *) stackgap_alloc(&sg, sizeof *bfp); 305 if ((error = copyout(&bfl, bfp, sizeof bfl))) 306 return error; 307 SCARG(&fca, fd) = fd; 308 SCARG(&fca, cmd) = cmd; 309 SCARG(&fca, arg) = bfp; 310 return fcntl(p, &fca, retval); 311 break; 312 case LINUX_F_SETOWN: 313 cmd = F_SETOWN; 314 break; 315 case LINUX_F_GETOWN: 316 cmd = F_GETOWN; 317 break; 318 default: 319 return EOPNOTSUPP; 320 } 321 322 SCARG(&fca, fd) = fd; 323 SCARG(&fca, cmd) = cmd; 324 SCARG(&fca, arg) = arg; 325 return fcntl(p, uap, retval); 326 } 327 328 /* 329 * Convert a NetBSD stat structure to a Linux stat structure. 330 * Only the order of the fields and the padding in the structure 331 * is different. 332 */ 333 static void 334 bsd_to_linux_stat(bsp, lsp) 335 struct stat *bsp; 336 struct linux_stat *lsp; 337 { 338 lsp->lst_dev = bsp->st_dev; 339 lsp->lst_ino = bsp->st_ino; 340 lsp->lst_mode = bsp->st_mode; 341 lsp->lst_nlink = bsp->st_nlink; 342 lsp->lst_uid = bsp->st_uid; 343 lsp->lst_gid = bsp->st_gid; 344 lsp->lst_rdev = bsp->st_rdev; 345 lsp->lst_size = bsp->st_size; 346 lsp->lst_blksize = bsp->st_blksize; 347 lsp->lst_blocks = bsp->st_blocks; 348 lsp->lst_atime = bsp->st_atime; 349 lsp->lst_mtime = bsp->st_mtime; 350 lsp->lst_ctime = bsp->st_ctime; 351 } 352 353 /* 354 * The stat functions below are plain sailing. stat and lstat are handled 355 * by one function to avoid code duplication. 356 */ 357 int 358 linux_fstat(p, uap, retval) 359 struct proc *p; 360 struct linux_fstat_args /* { 361 syscallarg(int) fd; 362 syscallarg(linux_stat *) sp; 363 } */ *uap; 364 register_t *retval; 365 { 366 struct fstat_args fsa; 367 struct linux_stat tmplst; 368 struct stat *st,tmpst; 369 caddr_t sg; 370 int error; 371 372 sg = stackgap_init(); 373 374 st = stackgap_alloc(&sg, sizeof (struct stat)); 375 376 SCARG(&fsa, fd) = SCARG(uap, fd); 377 SCARG(&fsa, sb) = st; 378 379 if ((error = fstat(p, &fsa, retval))) 380 return error; 381 382 if ((error = copyin(st, &tmpst, sizeof tmpst))) 383 return error; 384 385 bsd_to_linux_stat(&tmpst, &tmplst); 386 387 if ((error = copyout(&tmplst, SCARG(uap, sp), sizeof tmplst))) 388 return error; 389 390 return 0; 391 } 392 393 static int 394 linux_stat1(p, uap, retval, dolstat) 395 struct proc *p; 396 struct linux_stat_args *uap; 397 register_t *retval; 398 int dolstat; 399 { 400 struct stat_args sa; 401 struct linux_stat tmplst; 402 struct stat *st, tmpst; 403 caddr_t sg; 404 int error; 405 406 sg = stackgap_init(); 407 408 CHECK_ALT(p, &sg, SCARG(uap, path)); 409 410 st = stackgap_alloc(&sg, sizeof (struct stat)); 411 SCARG(&sa, ub) = st; 412 SCARG(&sa, path) = SCARG(uap, path); 413 414 if ((error = (dolstat ? lstat(p, &sa, retval) : stat(p, &sa, retval)))) 415 return error; 416 417 if ((error = copyin(st, &tmpst, sizeof tmpst))) 418 return error; 419 420 bsd_to_linux_stat(&tmpst, &tmplst); 421 422 if ((error = copyout(&tmplst, SCARG(uap, sp), sizeof tmplst))) 423 return error; 424 425 return 0; 426 } 427 428 int 429 linux_stat(p, uap, retval) 430 struct proc *p; 431 struct linux_stat_args /* { 432 syscallarg(char *) path; 433 syscallarg(struct linux_stat *) sp; 434 } */ *uap; 435 register_t *retval; 436 { 437 return linux_stat1(p, uap, retval, 0); 438 } 439 440 int 441 linux_lstat(p, uap, retval) 442 struct proc *p; 443 struct linux_lstat_args /* { 444 syscallarg(char *) path; 445 syscallarg(struct linux_stat *) sp; 446 } */ *uap; 447 register_t *retval; 448 { 449 return linux_stat1(p, uap, retval, 1); 450 } 451 452 /* 453 * This one is only here because of the alternate path check. 454 */ 455 int 456 linux_access(p, uap, retval) 457 struct proc *p; 458 struct linux_access_args /* { 459 syscallarg(char *) path; 460 syscallarg(int) flags; 461 } */ *uap; 462 register_t *retval; 463 { 464 caddr_t sg = stackgap_init(); 465 466 CHECK_ALT(p, &sg, SCARG(uap, path)); 467 468 return access(p, uap, retval); 469 } 470