linux_file.c revision 10355
1/*- 2 * Copyright (c) 1994-1995 S�ren Schmidt 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer 10 * in this position and unchanged. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software withough specific prior written permission 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * $Id: linux_file.c,v 1.1 1995/06/25 17:32:34 sos Exp $ 29 */ 30 31#include <i386/linux/linux.h> 32#include <sys/param.h> 33#include <sys/systm.h> 34#include <sys/fcntl.h> 35#include <sys/file.h> 36#include <sys/filedesc.h> 37#include <sys/proc.h> 38#include <sys/ioctl.h> 39#include <sys/stat.h> 40#include <sys/vnode.h> 41#include <sys/malloc.h> 42#include <sys/exec.h> 43#include <sys/dirent.h> 44#include <vm/vm.h> 45#include <ufs/ufs/dir.h> 46 47 48struct linux_creat_args { 49 char *path; 50 int mode; 51}; 52 53int 54linux_creat(struct proc *p, struct linux_creat_args *args, int *retval) 55{ 56 struct { 57 char *path; 58 int flags; 59 int mode; 60 } bsd_open_args; 61 62#ifdef DEBUG 63 printf("Linux-emul(%d): creat(%s, %d)\n", 64 p->p_pid, args->path, args->mode); 65#endif 66 bsd_open_args.path = args->path; 67 bsd_open_args.mode = args->mode; 68 bsd_open_args.flags = O_WRONLY | O_CREAT | O_TRUNC; 69 return open(p, &bsd_open_args, retval); 70} 71 72struct linux_open_args { 73 char *path; 74 int flags; 75 int mode; 76}; 77 78int 79linux_open(struct proc *p, struct linux_open_args *args, int *retval) 80{ 81 struct { 82 char *path; 83 int flags; 84 int mode; 85 } bsd_open_args; 86 int error; 87 88#ifdef DEBUG 89 printf("Linux-emul(%d): open(%s, 0x%x, 0x%x)\n", 90 p->p_pid, args->path, args->flags, args->mode); 91#endif 92 bsd_open_args.flags = 0; 93 if (args->flags & LINUX_O_RDONLY) 94 bsd_open_args.flags |= O_RDONLY; 95 if (args->flags & LINUX_O_WRONLY) 96 bsd_open_args.flags |= O_WRONLY; 97 if (args->flags & LINUX_O_RDWR) 98 bsd_open_args.flags |= O_RDWR; 99 if (args->flags & LINUX_O_NDELAY) 100 bsd_open_args.flags |= O_NONBLOCK; 101 if (args->flags & LINUX_O_APPEND) 102 bsd_open_args.flags |= O_APPEND; 103 if (args->flags & LINUX_O_SYNC) 104 bsd_open_args.flags |= O_FSYNC; 105 if (args->flags & LINUX_O_NONBLOCK) 106 bsd_open_args.flags |= O_NONBLOCK; 107 if (args->flags & LINUX_FASYNC) 108 bsd_open_args.flags |= O_ASYNC; 109 if (args->flags & LINUX_O_CREAT) 110 bsd_open_args.flags |= O_CREAT; 111 if (args->flags & LINUX_O_TRUNC) 112 bsd_open_args.flags |= O_TRUNC; 113 if (args->flags & LINUX_O_EXCL) 114 bsd_open_args.flags |= O_EXCL; 115 if (args->flags & LINUX_O_NOCTTY) 116 bsd_open_args.flags |= O_NOCTTY; 117 bsd_open_args.path = args->path; 118 bsd_open_args.mode = args->mode; 119 120 error = open(p, &bsd_open_args, retval); 121 if (!error && !(bsd_open_args.flags & O_NOCTTY) && 122 SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) { 123 struct filedesc *fdp = p->p_fd; 124 struct file *fp = fdp->fd_ofiles[*retval]; 125 126 if (fp->f_type == DTYPE_VNODE) 127 (fp->f_ops->fo_ioctl)(fp, TIOCSCTTY, (caddr_t) 0, p); 128 } 129 return error; 130} 131 132struct linux_flock { 133 short l_type; 134 short l_whence; 135 linux_off_t l_start; 136 linux_off_t l_len; 137 linux_pid_t l_pid; 138}; 139 140static void 141linux_to_bsd_flock(struct linux_flock *linux_flock, struct flock *bsd_flock) 142{ 143 switch (linux_flock->l_type) { 144 case LINUX_F_RDLCK: 145 bsd_flock->l_type = F_RDLCK; 146 break; 147 case LINUX_F_WRLCK: 148 bsd_flock->l_type = F_WRLCK; 149 break; 150 case LINUX_F_UNLCK: 151 bsd_flock->l_type = F_UNLCK; 152 break; 153 } 154 bsd_flock->l_whence = linux_flock->l_whence; 155 bsd_flock->l_start = (off_t)linux_flock->l_start; 156 bsd_flock->l_len = (off_t)linux_flock->l_len; 157 bsd_flock->l_pid = (pid_t)linux_flock->l_pid; 158} 159 160static void 161bsd_to_linux_flock(struct flock *bsd_flock, struct linux_flock *linux_flock) 162{ 163 switch (bsd_flock->l_type) { 164 case F_RDLCK: 165 linux_flock->l_type = LINUX_F_RDLCK; 166 break; 167 case F_WRLCK: 168 linux_flock->l_type = LINUX_F_WRLCK; 169 break; 170 case F_UNLCK: 171 linux_flock->l_type = LINUX_F_UNLCK; 172 break; 173 } 174 linux_flock->l_whence = bsd_flock->l_whence; 175 linux_flock->l_start = (linux_off_t)bsd_flock->l_start; 176 linux_flock->l_len = (linux_off_t)bsd_flock->l_len; 177 linux_flock->l_pid = (linux_pid_t)bsd_flock->l_pid; 178} 179 180struct linux_fcntl_args { 181 int fd; 182 int cmd; 183 int arg; 184}; 185 186int 187linux_fcntl(struct proc *p, struct linux_fcntl_args *args, int *retval) 188{ 189 int error, result; 190 struct fcntl_args { 191 int fd; 192 int cmd; 193 int arg; 194 } fcntl_args; 195 struct linux_flock linux_flock; 196 struct flock *bsd_flock = 197 (struct flock *)ua_alloc_init(sizeof(struct flock)); 198 199#ifdef DEBUG 200 printf("Linux-emul(%d): fcntl(%d, %08x, *)\n", 201 p->p_pid, args->fd, args->cmd); 202#endif 203 fcntl_args.fd = args->fd; 204 fcntl_args.arg = 0; 205 206 switch (args->cmd) { 207 case LINUX_F_DUPFD: 208 fcntl_args.cmd = F_DUPFD; 209 return fcntl(p, &fcntl_args, retval); 210 211 case LINUX_F_GETFD: 212 fcntl_args.cmd = F_GETFD; 213 return fcntl(p, &fcntl_args, retval); 214 215 case LINUX_F_SETFD: 216 fcntl_args.cmd = F_SETFD; 217 return fcntl(p, &fcntl_args, retval); 218 219 case LINUX_F_GETFL: 220 fcntl_args.cmd = F_GETFL; 221 error = fcntl(p, &fcntl_args, &result); 222 *retval = 0; 223 if (result & O_RDONLY) *retval |= LINUX_O_RDONLY; 224 if (result & O_WRONLY) *retval |= LINUX_O_WRONLY; 225 if (result & O_RDWR) *retval |= LINUX_O_RDWR; 226 if (result & O_NDELAY) *retval |= LINUX_O_NONBLOCK; 227 if (result & O_APPEND) *retval |= LINUX_O_APPEND; 228 if (result & O_FSYNC) *retval |= LINUX_O_SYNC; 229 return error; 230 231 case LINUX_F_SETFL: 232 if (args->arg & LINUX_O_NDELAY) fcntl_args.arg |= O_NONBLOCK; 233 if (args->arg & LINUX_O_APPEND) fcntl_args.arg |= O_APPEND; 234 if (args->arg & LINUX_O_SYNC) fcntl_args.arg |= O_FSYNC; 235 fcntl_args.cmd = F_SETFL; 236 return fcntl(p, &fcntl_args, retval); 237 238 case LINUX_F_GETLK: 239 if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock, 240 sizeof(struct linux_flock)))) 241 return error; 242 linux_to_bsd_flock(&linux_flock, bsd_flock); 243 fcntl_args.cmd = F_GETLK; 244 fcntl_args.arg = (int)bsd_flock; 245 if (error = fcntl(p, &fcntl_args, retval)) 246 return error; 247 bsd_to_linux_flock(bsd_flock, &linux_flock); 248 return copyout((caddr_t)&linux_flock, (caddr_t)args->arg, 249 sizeof(struct linux_flock)); 250 251 case LINUX_F_SETLK: 252 if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock, 253 sizeof(struct linux_flock)))) 254 return error; 255 linux_to_bsd_flock(&linux_flock, bsd_flock); 256 fcntl_args.cmd = F_SETLK; 257 fcntl_args.arg = (int)bsd_flock; 258 return fcntl(p, &fcntl_args, retval); 259 260 case LINUX_F_SETLKW: 261 if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock, 262 sizeof(struct linux_flock)))) 263 return error; 264 linux_to_bsd_flock(&linux_flock, bsd_flock); 265 fcntl_args.cmd = F_SETLKW; 266 fcntl_args.arg = (int)bsd_flock; 267 return fcntl(p, &fcntl_args, retval); 268 269 case LINUX_F_SETOWN: 270 fcntl_args.cmd = F_SETOWN; 271 return fcntl(p, &fcntl_args, retval); 272 273 case LINUX_F_GETOWN: 274 fcntl_args.cmd = F_GETOWN; 275 return fcntl(p, &fcntl_args, retval); 276 } 277 return EINVAL; 278} 279 280struct linux_lseek_args { 281 int fdes; 282 unsigned long off; 283 int whence; 284}; 285 286int 287linux_lseek(struct proc *p, struct linux_lseek_args *args, int *retval) 288{ 289 290 struct lseek_args { 291 int fdes; 292 int pad; 293 off_t off; 294 int whence; 295 } tmp_args; 296 off_t tmp_retval; 297 int error; 298 299#ifdef DEBUG 300 printf("Linux-emul(%d): lseek(%d, %d, %d)\n", 301 p->p_pid, args->fdes, args->off, args->whence); 302#endif 303 tmp_args.fdes = args->fdes; 304 tmp_args.off = (off_t)args->off; 305 tmp_args.whence = args->whence; 306 error = lseek(p, &tmp_args, &tmp_retval); 307 *retval = (int)tmp_retval; 308 return error; 309} 310 311struct linux_dirent { 312 long dino; 313 linux_off_t doff; 314 unsigned short dreclen; 315 char dname[LINUX_NAME_MAX + 1]; 316}; 317 318#define LINUX_RECLEN(de,namlen) \ 319 ALIGN((((char *)&(de)->dname - (char *)de) + (namlen) + 1)) 320 321struct linux_readdir_args { 322 int fd; 323 struct linux_dirent *dent; 324 unsigned int count; 325}; 326 327int 328linux_readdir(struct proc *p, struct linux_readdir_args *args, int *retval) 329{ 330 register struct dirent *bdp; 331 struct vnode *vp; 332 caddr_t inp, buf; /* BSD-format */ 333 int len, reclen; /* BSD-format */ 334 caddr_t outp; /* Linux-format */ 335 int resid, linuxreclen=0; /* Linux-format */ 336 struct file *fp; 337 struct uio auio; 338 struct iovec aiov; 339 struct vattr va; 340 off_t off; 341 struct linux_dirent linux_dirent; 342 int buflen, error, eofflag, nbytes, justone, blockoff; 343 344#ifdef DEBUG 345 printf("Linux-emul(%d): readdir(%d, *, %d)\n", 346 p->p_pid, args->fd, args->count); 347#endif 348 if ((error = getvnode(p->p_fd, args->fd, &fp)) != 0) { 349 return (error); 350} 351 352 if ((fp->f_flag & FREAD) == 0) 353 return (EBADF); 354 355 vp = (struct vnode *) fp->f_data; 356 357 if (vp->v_type != VDIR) 358 return (EINVAL); 359 360 if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p))) { 361 return error; 362 } 363 364 nbytes = args->count; 365 if (nbytes == 1) { 366 nbytes = sizeof (struct linux_dirent); 367 justone = 1; 368 } 369 else 370 justone = 0; 371 372 off = fp->f_offset; 373 blockoff = off % va.va_blocksize; 374 buflen = max(va.va_blocksize, (nbytes + blockoff)); 375 buf = malloc(buflen, M_TEMP, M_WAITOK); 376 VOP_LOCK(vp); 377again: 378 aiov.iov_base = buf; 379 aiov.iov_len = buflen; 380 auio.uio_iov = &aiov; 381 auio.uio_iovcnt = 1; 382 auio.uio_rw = UIO_READ; 383 auio.uio_segflg = UIO_SYSSPACE; 384 auio.uio_procp = p; 385 auio.uio_resid = buflen; 386 auio.uio_offset = off - (off_t)blockoff; 387 388 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, (u_long *) 0, 0); 389 if (error) { 390 goto out; 391} 392 393 inp = buf; 394 inp += blockoff; 395 outp = (caddr_t) args->dent; 396 resid = nbytes; 397 if ((len = buflen - auio.uio_resid - blockoff) == 0) { 398 goto eof; 399 } 400 401 while (len > 0) { 402 bdp = (struct dirent *) inp; 403 reclen = bdp->d_reclen; 404 if (reclen & 3) { 405 printf("linux_readdir: reclen=%d\n", reclen); 406 error = EFAULT; 407 goto out; 408 } 409 410 off += reclen; 411 if (bdp->d_fileno == 0) { 412 inp += reclen; 413 len -= reclen; 414 continue; 415 } 416 linuxreclen = LINUX_RECLEN(&linux_dirent, bdp->d_namlen); 417 if (reclen > len || resid < linuxreclen) { 418 outp++; 419 break; 420 } 421 linux_dirent.dino = (long) bdp->d_fileno; 422 linux_dirent.doff = (linux_off_t) linuxreclen; 423 linux_dirent.dreclen = (u_short) bdp->d_namlen; 424 strcpy(linux_dirent.dname, bdp->d_name); 425 if ((error = copyout((caddr_t)&linux_dirent, outp, linuxreclen))) { 426 goto out; 427 } 428 inp += reclen; 429 outp += linuxreclen; 430 resid -= linuxreclen; 431 len -= reclen; 432 if (justone) 433 break; 434 } 435 436 if (outp == (caddr_t) args->dent) 437 goto again; 438 fp->f_offset = off; 439 440 if (justone) 441 nbytes = resid + linuxreclen; 442 443eof: 444 *retval = nbytes - resid; 445out: 446 VOP_UNLOCK(vp); 447 free(buf, M_TEMP); 448 return error; 449} 450