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.4 1995/11/22 07:43:45 bde Exp $ 29 */ 30 31 #include <sys/param.h> 32 #include <sys/systm.h> 33 #include <sys/sysproto.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 45 #include <ufs/ufs/dir.h> 46 47 #include <i386/linux/linux.h> 48 #include <i386/linux/sysproto.h> 49 50 struct linux_creat_args { 51 char *path; 52 int mode; 53 }; 54 55 int 56 linux_creat(struct proc *p, struct linux_creat_args *args, int *retval) 57 { 58 struct open_args /* { 59 char *path; 60 int flags; 61 int mode; 62 } */ bsd_open_args; 63 64 #ifdef DEBUG 65 printf("Linux-emul(%d): creat(%s, %d)\n", 66 p->p_pid, args->path, args->mode); 67 #endif 68 bsd_open_args.path = args->path; 69 bsd_open_args.mode = args->mode; 70 bsd_open_args.flags = O_WRONLY | O_CREAT | O_TRUNC; 71 return open(p, &bsd_open_args, retval); 72 } 73 74 struct linux_open_args { 75 char *path; 76 int flags; 77 int mode; 78 }; 79 80 int 81 linux_open(struct proc *p, struct linux_open_args *args, int *retval) 82 { 83 struct open_args /* { 84 char *path; 85 int flags; 86 int mode; 87 } */ bsd_open_args; 88 int error; 89 90 #ifdef DEBUG 91 printf("Linux-emul(%d): open(%s, 0x%x, 0x%x)\n", 92 p->p_pid, args->path, args->flags, args->mode); 93 #endif 94 bsd_open_args.flags = 0; 95 if (args->flags & LINUX_O_RDONLY) 96 bsd_open_args.flags |= O_RDONLY; 97 if (args->flags & LINUX_O_WRONLY) 98 bsd_open_args.flags |= O_WRONLY; 99 if (args->flags & LINUX_O_RDWR) 100 bsd_open_args.flags |= O_RDWR; 101 if (args->flags & LINUX_O_NDELAY) 102 bsd_open_args.flags |= O_NONBLOCK; 103 if (args->flags & LINUX_O_APPEND) 104 bsd_open_args.flags |= O_APPEND; 105 if (args->flags & LINUX_O_SYNC) 106 bsd_open_args.flags |= O_FSYNC; 107 if (args->flags & LINUX_O_NONBLOCK) 108 bsd_open_args.flags |= O_NONBLOCK; 109 if (args->flags & LINUX_FASYNC) 110 bsd_open_args.flags |= O_ASYNC; 111 if (args->flags & LINUX_O_CREAT) 112 bsd_open_args.flags |= O_CREAT; 113 if (args->flags & LINUX_O_TRUNC) 114 bsd_open_args.flags |= O_TRUNC; 115 if (args->flags & LINUX_O_EXCL) 116 bsd_open_args.flags |= O_EXCL; 117 if (args->flags & LINUX_O_NOCTTY) 118 bsd_open_args.flags |= O_NOCTTY; 119 bsd_open_args.path = args->path; 120 bsd_open_args.mode = args->mode; 121 122 error = open(p, &bsd_open_args, retval); 123 if (!error && !(bsd_open_args.flags & O_NOCTTY) && 124 SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) { 125 struct filedesc *fdp = p->p_fd; 126 struct file *fp = fdp->fd_ofiles[*retval]; 127 128 if (fp->f_type == DTYPE_VNODE) 129 (fp->f_ops->fo_ioctl)(fp, TIOCSCTTY, (caddr_t) 0, p); 130 } 131 return error; 132 } 133 134 struct linux_flock { 135 short l_type; 136 short l_whence; 137 linux_off_t l_start; 138 linux_off_t l_len; 139 linux_pid_t l_pid; 140 }; 141 142 static void 143 linux_to_bsd_flock(struct linux_flock *linux_flock, struct flock *bsd_flock) 144 { 145 switch (linux_flock->l_type) { 146 case LINUX_F_RDLCK: 147 bsd_flock->l_type = F_RDLCK; 148 break; 149 case LINUX_F_WRLCK: 150 bsd_flock->l_type = F_WRLCK; 151 break; 152 case LINUX_F_UNLCK: 153 bsd_flock->l_type = F_UNLCK; 154 break; 155 } 156 bsd_flock->l_whence = linux_flock->l_whence; 157 bsd_flock->l_start = (off_t)linux_flock->l_start; 158 bsd_flock->l_len = (off_t)linux_flock->l_len; 159 bsd_flock->l_pid = (pid_t)linux_flock->l_pid; 160 } 161 162 static void 163 bsd_to_linux_flock(struct flock *bsd_flock, struct linux_flock *linux_flock) 164 { 165 switch (bsd_flock->l_type) { 166 case F_RDLCK: 167 linux_flock->l_type = LINUX_F_RDLCK; 168 break; 169 case F_WRLCK: 170 linux_flock->l_type = LINUX_F_WRLCK; 171 break; 172 case F_UNLCK: 173 linux_flock->l_type = LINUX_F_UNLCK; 174 break; 175 } 176 linux_flock->l_whence = bsd_flock->l_whence; 177 linux_flock->l_start = (linux_off_t)bsd_flock->l_start; 178 linux_flock->l_len = (linux_off_t)bsd_flock->l_len; 179 linux_flock->l_pid = (linux_pid_t)bsd_flock->l_pid; 180 } 181 182 struct linux_fcntl_args { 183 int fd; 184 int cmd; 185 int arg; 186 }; 187 188 int 189 linux_fcntl(struct proc *p, struct linux_fcntl_args *args, int *retval) 190 { 191 int error, result; 192 struct fcntl_args /* { 193 int fd; 194 int cmd; 195 int arg; 196 } */ fcntl_args; 197 struct linux_flock linux_flock; 198 struct flock *bsd_flock = 199 (struct flock *)ua_alloc_init(sizeof(struct flock)); 200 201 #ifdef DEBUG 202 printf("Linux-emul(%d): fcntl(%d, %08x, *)\n", 203 p->p_pid, args->fd, args->cmd); 204 #endif 205 fcntl_args.fd = args->fd; 206 fcntl_args.arg = 0; 207 208 switch (args->cmd) { 209 case LINUX_F_DUPFD: 210 fcntl_args.cmd = F_DUPFD; 211 return fcntl(p, &fcntl_args, retval); 212 213 case LINUX_F_GETFD: 214 fcntl_args.cmd = F_GETFD; 215 return fcntl(p, &fcntl_args, retval); 216 217 case LINUX_F_SETFD: 218 fcntl_args.cmd = F_SETFD; 219 return fcntl(p, &fcntl_args, retval); 220 221 case LINUX_F_GETFL: 222 fcntl_args.cmd = F_GETFL; 223 error = fcntl(p, &fcntl_args, &result); 224 *retval = 0; 225 if (result & O_RDONLY) *retval |= LINUX_O_RDONLY; 226 if (result & O_WRONLY) *retval |= LINUX_O_WRONLY; 227 if (result & O_RDWR) *retval |= LINUX_O_RDWR; 228 if (result & O_NDELAY) *retval |= LINUX_O_NONBLOCK; 229 if (result & O_APPEND) *retval |= LINUX_O_APPEND; 230 if (result & O_FSYNC) *retval |= LINUX_O_SYNC; 231 return error; 232 233 case LINUX_F_SETFL: 234 if (args->arg & LINUX_O_NDELAY) fcntl_args.arg |= O_NONBLOCK; 235 if (args->arg & LINUX_O_APPEND) fcntl_args.arg |= O_APPEND; 236 if (args->arg & LINUX_O_SYNC) fcntl_args.arg |= O_FSYNC; 237 fcntl_args.cmd = F_SETFL; 238 return fcntl(p, &fcntl_args, retval); 239 240 case LINUX_F_GETLK: 241 if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock, 242 sizeof(struct linux_flock)))) 243 return error; 244 linux_to_bsd_flock(&linux_flock, bsd_flock); 245 fcntl_args.cmd = F_GETLK; 246 fcntl_args.arg = (int)bsd_flock; 247 if (error = fcntl(p, &fcntl_args, retval)) 248 return error; 249 bsd_to_linux_flock(bsd_flock, &linux_flock); 250 return copyout((caddr_t)&linux_flock, (caddr_t)args->arg, 251 sizeof(struct linux_flock)); 252 253 case LINUX_F_SETLK: 254 if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock, 255 sizeof(struct linux_flock)))) 256 return error; 257 linux_to_bsd_flock(&linux_flock, bsd_flock); 258 fcntl_args.cmd = F_SETLK; 259 fcntl_args.arg = (int)bsd_flock; 260 return fcntl(p, &fcntl_args, retval); 261 262 case LINUX_F_SETLKW: 263 if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock, 264 sizeof(struct linux_flock)))) 265 return error; 266 linux_to_bsd_flock(&linux_flock, bsd_flock); 267 fcntl_args.cmd = F_SETLKW; 268 fcntl_args.arg = (int)bsd_flock; 269 return fcntl(p, &fcntl_args, retval); 270 271 case LINUX_F_SETOWN: 272 fcntl_args.cmd = F_SETOWN; 273 return fcntl(p, &fcntl_args, retval); 274 275 case LINUX_F_GETOWN: 276 fcntl_args.cmd = F_GETOWN; 277 return fcntl(p, &fcntl_args, retval); 278 } 279 return EINVAL; 280 } 281 282 struct linux_lseek_args { 283 int fdes; 284 unsigned long off; 285 int whence; 286 }; 287 288 int 289 linux_lseek(struct proc *p, struct linux_lseek_args *args, int *retval) 290 { 291 292 struct lseek_args /* { 293 int fd; 294 int pad; 295 off_t offset; 296 int whence; 297 } */ tmp_args; 298 int error; 299 300 #ifdef DEBUG 301 printf("Linux-emul(%d): lseek(%d, %d, %d)\n", 302 p->p_pid, args->fdes, args->off, args->whence); 303 #endif 304 tmp_args.fd = args->fdes; 305 tmp_args.offset = (off_t)args->off; 306 tmp_args.whence = args->whence; 307 error = lseek(p, &tmp_args, retval); 308 return error; 309 } 310 311 struct 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 321 struct linux_readdir_args { 322 int fd; 323 struct linux_dirent *dent; 324 unsigned int count; 325 }; 326 327 int 328 linux_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 % DIRBLKSIZ; 374 buflen = max(DIRBLKSIZ, nbytes + blockoff); 375 buflen = min(buflen, MAXBSIZE); 376 buf = malloc(buflen, M_TEMP, M_WAITOK); 377 VOP_LOCK(vp); 378 again: 379 aiov.iov_base = buf; 380 aiov.iov_len = buflen; 381 auio.uio_iov = &aiov; 382 auio.uio_iovcnt = 1; 383 auio.uio_rw = UIO_READ; 384 auio.uio_segflg = UIO_SYSSPACE; 385 auio.uio_procp = p; 386 auio.uio_resid = buflen; 387 auio.uio_offset = off - (off_t)blockoff; 388 389 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, (int *) NULL, 390 (u_int **) NULL); 391 if (error) { 392 goto out; 393 } 394 395 inp = buf; 396 inp += blockoff; 397 outp = (caddr_t) args->dent; 398 resid = nbytes; 399 if ((len = buflen - auio.uio_resid - blockoff) == 0) { 400 goto eof; 401 } 402 403 while (len > 0) { 404 bdp = (struct dirent *) inp; 405 reclen = bdp->d_reclen; 406 if (reclen & 3) { 407 printf("linux_readdir: reclen=%d\n", reclen); 408 error = EFAULT; 409 goto out; 410 } 411 412 if (bdp->d_fileno == 0) { 413 inp += reclen; 414 off += reclen; 415 len -= reclen; 416 continue; 417 } 418 linuxreclen = LINUX_RECLEN(&linux_dirent, bdp->d_namlen); 419 if (reclen > len || resid < linuxreclen) { 420 outp++; 421 break; 422 } 423 linux_dirent.dino = (long) bdp->d_fileno; 424 linux_dirent.doff = (linux_off_t) linuxreclen; 425 linux_dirent.dreclen = (u_short) bdp->d_namlen; 426 strcpy(linux_dirent.dname, bdp->d_name); 427 if ((error = copyout((caddr_t)&linux_dirent, outp, linuxreclen))) { 428 goto out; 429 } 430 inp += reclen; 431 off += reclen; 432 outp += linuxreclen; 433 resid -= linuxreclen; 434 len -= reclen; 435 if (justone) 436 break; 437 } 438 439 if (outp == (caddr_t) args->dent) 440 goto again; 441 fp->f_offset = off; 442 443 if (justone) 444 nbytes = resid + linuxreclen; 445 446 eof: 447 *retval = nbytes - resid; 448 out: 449 VOP_UNLOCK(vp); 450 free(buf, M_TEMP); 451 return error; 452 } 453