linuxemu - fix typo
[dragonfly.git] / sys / emulation / linux / linux_file.c
CommitLineData
984263bc
MD
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 * $FreeBSD: src/sys/compat/linux/linux_file.c,v 1.41.2.6 2003/01/06 09:19:43 fjoe Exp $
8b953559 29 * $DragonFly: src/sys/emulation/linux/linux_file.c,v 1.39 2008/09/28 05:08:16 dillon Exp $
984263bc
MD
30 */
31
32#include "opt_compat.h"
33
34#include <sys/param.h>
35#include <sys/systm.h>
36#include <sys/conf.h>
37#include <sys/dirent.h>
38#include <sys/fcntl.h>
39#include <sys/file.h>
fad57d0e 40#include <sys/stat.h>
984263bc 41#include <sys/filedesc.h>
dda4b42b 42#include <sys/kern_syscall.h>
984263bc
MD
43#include <sys/lock.h>
44#include <sys/malloc.h>
45#include <sys/mount.h>
21739618 46#include <sys/nlookup.h>
984263bc
MD
47#include <sys/proc.h>
48#include <sys/sysproto.h>
49#include <sys/tty.h>
50#include <sys/vnode.h>
51
1f2de5d4
MD
52#include <vfs/ufs/quota.h>
53#include <vfs/ufs/ufsmount.h>
984263bc 54
dadab5e9
MD
55#include <sys/file2.h>
56
932f49b9
MD
57#include <arch_linux/linux.h>
58#include <arch_linux/linux_proto.h>
1f2de5d4 59#include "linux_util.h"
984263bc 60
984263bc 61int
753fd850 62sys_linux_creat(struct linux_creat_args *args)
984263bc 63{
fad57d0e 64 struct nlookupdata nd;
136178b3
DRJ
65 char *path;
66 int error;
984263bc 67
136178b3
DRJ
68 error = linux_copyin_path(args->path, &path, LINUX_PATH_CREATE);
69 if (error)
70 return (error);
984263bc
MD
71#ifdef DEBUG
72 if (ldebug(creat))
26be20a0 73 kprintf(ARGS(creat, "%s, %d"), path, args->mode);
984263bc 74#endif
fad57d0e
MD
75 error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
76 if (error == 0) {
77 error = kern_open(&nd, O_WRONLY | O_CREAT | O_TRUNC,
e54488bb 78 args->mode, &args->sysmsg_iresult);
fad57d0e 79 }
136178b3
DRJ
80 linux_free_path(&path);
81 return(error);
984263bc 82}
984263bc
MD
83
84int
753fd850 85sys_linux_open(struct linux_open_args *args)
984263bc 86{
136178b3
DRJ
87 struct thread *td = curthread;
88 struct proc *p = td->td_proc;
fad57d0e 89 struct nlookupdata nd;
136178b3
DRJ
90 char *path;
91 int error, flags;
dadab5e9 92
136178b3 93 KKASSERT(p);
984263bc 94
136178b3
DRJ
95 if (args->flags & LINUX_O_CREAT) {
96 error = linux_copyin_path(args->path, &path,
97 LINUX_PATH_CREATE);
98 } else {
99 error = linux_copyin_path(args->path, &path,
100 LINUX_PATH_EXISTS);
101 }
102 if (error)
103 return (error);
984263bc
MD
104
105#ifdef DEBUG
106 if (ldebug(open))
26be20a0 107 kprintf(ARGS(open, "%s, 0x%x, 0x%x"), path, args->flags,
136178b3 108 args->mode);
984263bc 109#endif
136178b3
DRJ
110 flags = 0;
111 if (args->flags & LINUX_O_RDONLY)
112 flags |= O_RDONLY;
113 if (args->flags & LINUX_O_WRONLY)
114 flags |= O_WRONLY;
115 if (args->flags & LINUX_O_RDWR)
116 flags |= O_RDWR;
117 if (args->flags & LINUX_O_NDELAY)
118 flags |= O_NONBLOCK;
119 if (args->flags & LINUX_O_APPEND)
120 flags |= O_APPEND;
121 if (args->flags & LINUX_O_SYNC)
122 flags |= O_FSYNC;
123 if (args->flags & LINUX_O_NONBLOCK)
124 flags |= O_NONBLOCK;
125 if (args->flags & LINUX_FASYNC)
126 flags |= O_ASYNC;
127 if (args->flags & LINUX_O_CREAT)
128 flags |= O_CREAT;
129 if (args->flags & LINUX_O_TRUNC)
130 flags |= O_TRUNC;
131 if (args->flags & LINUX_O_EXCL)
132 flags |= O_EXCL;
133 if (args->flags & LINUX_O_NOCTTY)
134 flags |= O_NOCTTY;
fad57d0e
MD
135 error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
136 if (error == 0) {
137 error = kern_open(&nd, flags,
e54488bb 138 args->mode, &args->sysmsg_iresult);
fad57d0e 139 }
136178b3
DRJ
140
141 if (error == 0 && !(flags & O_NOCTTY) &&
142 SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) {
228b401d 143 struct file *fp;
136178b3 144
e54488bb 145 fp = holdfp(p->p_fd, args->sysmsg_iresult, -1);
228b401d
MD
146 if (fp) {
147 if (fp->f_type == DTYPE_VNODE)
87baaf0c 148 fo_ioctl(fp, TIOCSCTTY, NULL, p->p_ucred, NULL);
228b401d
MD
149 fdrop(fp);
150 }
151 }
984263bc
MD
152#ifdef DEBUG
153 if (ldebug(open))
26be20a0 154 kprintf(LMSG("open returns error %d"), error);
984263bc 155#endif
136178b3
DRJ
156 linux_free_path(&path);
157 return error;
984263bc
MD
158}
159
160int
753fd850 161sys_linux_lseek(struct linux_lseek_args *args)
984263bc 162{
136178b3 163 int error;
984263bc
MD
164
165#ifdef DEBUG
166 if (ldebug(lseek))
26be20a0 167 kprintf(ARGS(lseek, "%d, %ld, %d"),
984263bc
MD
168 args->fdes, (long)args->off, args->whence);
169#endif
136178b3
DRJ
170 error = kern_lseek(args->fdes, args->off, args->whence,
171 &args->sysmsg_offset);
172
173 return error;
984263bc
MD
174}
175
984263bc 176int
753fd850 177sys_linux_llseek(struct linux_llseek_args *args)
984263bc 178{
984263bc 179 int error;
136178b3 180 off_t off, res;
984263bc
MD
181
182#ifdef DEBUG
183 if (ldebug(llseek))
26be20a0 184 kprintf(ARGS(llseek, "%d, %d:%d, %d"),
984263bc
MD
185 args->fd, args->ohigh, args->olow, args->whence);
186#endif
187 off = (args->olow) | (((off_t) args->ohigh) << 32);
188
136178b3 189 error = kern_lseek(args->fd, off, args->whence, &res);
984263bc 190
136178b3
DRJ
191 if (error == 0)
192 error = copyout(&res, args->res, sizeof(res));
193 return (error);
984263bc 194}
984263bc 195
984263bc 196int
753fd850 197sys_linux_readdir(struct linux_readdir_args *args)
984263bc
MD
198{
199 struct linux_getdents_args lda;
90b9818c 200 int error;
984263bc
MD
201
202 lda.fd = args->fd;
203 lda.dent = args->dent;
8b953559 204 lda.count = -1;
e54488bb 205 lda.sysmsg_iresult = 0;
753fd850 206 error = sys_linux_getdents(&lda);
e54488bb 207 args->sysmsg_iresult = lda.sysmsg_iresult;
90b9818c 208 return(error);
984263bc 209}
984263bc
MD
210
211/*
212 * Note that linux_getdents(2) and linux_getdents64(2) have the same
213 * arguments. They only differ in the definition of struct dirent they
214 * operate on. We use this to common the code, with the exception of
215 * accessing struct dirent. Note that linux_readdir(2) is implemented
216 * by means of linux_getdents(2). In this case we never operate on
217 * struct dirent64 and thus don't need to handle it...
218 */
219
220struct l_dirent {
221 l_long d_ino;
222 l_off_t d_off;
223 l_ushort d_reclen;
224 char d_name[LINUX_NAME_MAX + 1];
225};
226
227struct l_dirent64 {
228 uint64_t d_ino;
229 int64_t d_off;
230 l_ushort d_reclen;
231 u_char d_type;
232 char d_name[LINUX_NAME_MAX + 1];
233};
234
235#define LINUX_RECLEN(de,namlen) \
236 ALIGN((((char *)&(de)->d_name - (char *)de) + (namlen) + 1))
237
238#define LINUX_DIRBLKSIZ 512
239
240static int
41c20dac 241getdents_common(struct linux_getdents64_args *args, int is64bit)
984263bc 242{
dadab5e9
MD
243 struct thread *td = curthread;
244 struct proc *p = td->td_proc;
41c20dac 245 struct dirent *bdp;
984263bc
MD
246 struct vnode *vp;
247 caddr_t inp, buf; /* BSD-format */
e54488bb
MD
248 int reclen; /* BSD-format */
249 size_t len;
984263bc 250 caddr_t outp; /* Linux-format */
e54488bb
MD
251 int linuxreclen = 0; /* Linux-format */
252 size_t resid;
984263bc
MD
253 struct file *fp;
254 struct uio auio;
255 struct iovec aiov;
256 struct vattr va;
257 off_t off;
258 struct l_dirent linux_dirent;
259 struct l_dirent64 linux_dirent64;
e54488bb
MD
260 int error, eofflag, justone;
261 size_t buflen, nbytes;
6676af76 262 off_t *cookies = NULL, *cookiep;
984263bc
MD
263 int ncookies;
264
dadab5e9
MD
265 KKASSERT(p);
266
5b287bba 267 if ((error = holdvnode(p->p_fd, args->fd, &fp)) != 0)
984263bc
MD
268 return (error);
269
5b287bba
MD
270 if ((fp->f_flag & FREAD) == 0) {
271 error = EBADF;
272 goto done;
273 }
984263bc
MD
274
275 vp = (struct vnode *) fp->f_data;
5b287bba
MD
276 if (vp->v_type != VDIR) {
277 error = EINVAL;
278 goto done;
279 }
984263bc 280
5b287bba
MD
281 if ((error = VOP_GETATTR(vp, &va)) != 0)
282 goto done;
984263bc
MD
283
284 nbytes = args->count;
e54488bb 285 if (nbytes == (size_t)-1) {
984263bc 286 /* readdir(2) case. Always struct dirent. */
5b287bba
MD
287 if (is64bit) {
288 error = EINVAL;
289 goto done;
290 }
984263bc
MD
291 nbytes = sizeof(linux_dirent);
292 justone = 1;
5b287bba 293 } else {
984263bc 294 justone = 0;
5b287bba 295 }
e54488bb 296 if ((size_t)nbytes < 0)
8b953559 297 nbytes = 0;
984263bc
MD
298
299 off = fp->f_offset;
300
301 buflen = max(LINUX_DIRBLKSIZ, nbytes);
302 buflen = min(buflen, MAXBSIZE);
efda3bd0 303 buf = kmalloc(buflen, M_TEMP, M_WAITOK);
984263bc
MD
304
305again:
306 aiov.iov_base = buf;
307 aiov.iov_len = buflen;
308 auio.uio_iov = &aiov;
309 auio.uio_iovcnt = 1;
310 auio.uio_rw = UIO_READ;
311 auio.uio_segflg = UIO_SYSSPACE;
dadab5e9 312 auio.uio_td = td;
984263bc
MD
313 auio.uio_resid = buflen;
314 auio.uio_offset = off;
315
316 if (cookies) {
efda3bd0 317 kfree(cookies, M_TEMP);
984263bc
MD
318 cookies = NULL;
319 }
320
8b953559
MD
321 eofflag = 0;
322 ncookies = 0;
984263bc
MD
323 if ((error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies,
324 &cookies)))
325 goto out;
326
327 inp = buf;
328 outp = (caddr_t)args->dirent;
329 resid = nbytes;
74521803 330 if (auio.uio_resid >= buflen)
984263bc 331 goto eof;
e54488bb 332 len = buflen - auio.uio_resid;
984263bc
MD
333 cookiep = cookies;
334
335 if (cookies) {
336 /*
337 * When using cookies, the vfs has the option of reading from
338 * a different offset than that supplied (UFS truncates the
339 * offset to a block boundary to make sure that it never reads
340 * partway through a directory entry, even if the directory
341 * has been compacted).
342 */
8b953559 343 while (len > 0 && ncookies > 0 && *cookiep < off) {
984263bc 344 bdp = (struct dirent *) inp;
01f31ab3
JS
345 len -= _DIRENT_DIRSIZ(bdp);
346 inp += _DIRENT_DIRSIZ(bdp);
984263bc
MD
347 cookiep++;
348 ncookies--;
349 }
350 }
351
352 while (len > 0) {
353 if (cookiep && ncookies == 0)
354 break;
355 bdp = (struct dirent *) inp;
01f31ab3 356 reclen = _DIRENT_DIRSIZ(bdp);
984263bc
MD
357 if (reclen & 3) {
358 error = EFAULT;
359 goto out;
360 }
361
01f31ab3 362 if (bdp->d_ino == 0) {
984263bc
MD
363 inp += reclen;
364 if (cookiep) {
365 off = *cookiep++;
8b953559 366 ++off;
984263bc 367 ncookies--;
8b953559 368 } else {
984263bc 369 off += reclen;
8b953559 370 }
984263bc
MD
371 len -= reclen;
372 continue;
373 }
374
375 linuxreclen = (is64bit)
376 ? LINUX_RECLEN(&linux_dirent64, bdp->d_namlen)
377 : LINUX_RECLEN(&linux_dirent, bdp->d_namlen);
378
379 if (reclen > len || resid < linuxreclen) {
380 outp++;
381 break;
382 }
383
8b953559
MD
384 bzero(&linux_dirent, sizeof(linux_dirent));
385 bzero(&linux_dirent64, sizeof(linux_dirent64));
984263bc
MD
386 if (justone) {
387 /* readdir(2) case. */
8b953559 388 linux_dirent.d_ino = (l_long)INO64TO32(bdp->d_ino);
984263bc
MD
389 linux_dirent.d_off = (l_off_t)linuxreclen;
390 linux_dirent.d_reclen = (l_ushort)bdp->d_namlen;
391 strcpy(linux_dirent.d_name, bdp->d_name);
392 error = copyout(&linux_dirent, outp, linuxreclen);
393 } else {
394 if (is64bit) {
01f31ab3 395 linux_dirent64.d_ino = bdp->d_ino;
984263bc
MD
396 linux_dirent64.d_off = (cookiep)
397 ? (l_off_t)*cookiep
398 : (l_off_t)(off + reclen);
399 linux_dirent64.d_reclen =
400 (l_ushort)linuxreclen;
401 linux_dirent64.d_type = bdp->d_type;
402 strcpy(linux_dirent64.d_name, bdp->d_name);
403 error = copyout(&linux_dirent64, outp,
404 linuxreclen);
405 } else {
8b953559 406 linux_dirent.d_ino = INO64TO32(bdp->d_ino);
984263bc
MD
407 linux_dirent.d_off = (cookiep)
408 ? (l_off_t)*cookiep
409 : (l_off_t)(off + reclen);
410 linux_dirent.d_reclen = (l_ushort)linuxreclen;
411 strcpy(linux_dirent.d_name, bdp->d_name);
412 error = copyout(&linux_dirent, outp,
413 linuxreclen);
414 }
415 }
416 if (error)
417 goto out;
418
419 inp += reclen;
420 if (cookiep) {
421 off = *cookiep++;
8b953559 422 ++off;
984263bc 423 ncookies--;
8b953559 424 } else {
984263bc 425 off += reclen;
8b953559 426 }
984263bc
MD
427
428 outp += linuxreclen;
429 resid -= linuxreclen;
430 len -= reclen;
431 if (justone)
432 break;
433 }
434
b1c5843a 435 if (outp == (caddr_t)args->dirent && eofflag == 0)
984263bc
MD
436 goto again;
437
438 fp->f_offset = off;
439 if (justone)
440 nbytes = resid + linuxreclen;
441
442eof:
e54488bb 443 args->sysmsg_iresult = (int)(nbytes - resid);
984263bc
MD
444
445out:
446 if (cookies)
efda3bd0 447 kfree(cookies, M_TEMP);
984263bc 448
efda3bd0 449 kfree(buf, M_TEMP);
5b287bba
MD
450done:
451 fdrop(fp);
984263bc
MD
452 return (error);
453}
454
455int
753fd850 456sys_linux_getdents(struct linux_getdents_args *args)
984263bc 457{
984263bc
MD
458#ifdef DEBUG
459 if (ldebug(getdents))
26be20a0 460 kprintf(ARGS(getdents, "%d, *, %d"), args->fd, args->count);
984263bc 461#endif
41c20dac 462 return (getdents_common((struct linux_getdents64_args*)args, 0));
984263bc
MD
463}
464
465int
753fd850 466sys_linux_getdents64(struct linux_getdents64_args *args)
984263bc 467{
984263bc
MD
468#ifdef DEBUG
469 if (ldebug(getdents64))
26be20a0 470 kprintf(ARGS(getdents64, "%d, *, %d"), args->fd, args->count);
984263bc 471#endif
41c20dac 472 return (getdents_common(args, 1));
984263bc
MD
473}
474
475/*
476 * These exist mainly for hooks for doing /compat/linux translation.
477 */
478
479int
753fd850 480sys_linux_access(struct linux_access_args *args)
984263bc 481{
fad57d0e 482 struct nlookupdata nd;
136178b3 483 char *path;
90b9818c 484 int error;
984263bc 485
136178b3
DRJ
486 error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
487 if (error)
488 return (error);
984263bc
MD
489#ifdef DEBUG
490 if (ldebug(access))
26be20a0 491 kprintf(ARGS(access, "%s, %d"), path, args->flags);
984263bc 492#endif
fad57d0e
MD
493 error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
494 if (error == 0)
18cf460b 495 error = kern_access(&nd, args->flags, 0);
fad57d0e 496 nlookup_done(&nd);
136178b3 497 linux_free_path(&path);
90b9818c 498 return(error);
984263bc
MD
499}
500
501int
753fd850 502sys_linux_unlink(struct linux_unlink_args *args)
984263bc 503{
fad57d0e 504 struct nlookupdata nd;
136178b3 505 char *path;
90b9818c 506 int error;
984263bc 507
136178b3
DRJ
508 error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
509 if (error)
510 return (error);
984263bc
MD
511#ifdef DEBUG
512 if (ldebug(unlink))
26be20a0 513 kprintf(ARGS(unlink, "%s"), path);
984263bc 514#endif
fad57d0e
MD
515 error = nlookup_init(&nd, path, UIO_SYSSPACE, 0);
516 if (error == 0)
517 error = kern_unlink(&nd);
518 nlookup_done(&nd);
136178b3 519 linux_free_path(&path);
90b9818c 520 return(error);
984263bc
MD
521}
522
523int
753fd850 524sys_linux_chdir(struct linux_chdir_args *args)
984263bc 525{
21739618 526 struct nlookupdata nd;
136178b3 527 char *path;
90b9818c 528 int error;
984263bc 529
136178b3
DRJ
530 error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
531 if (error)
532 return (error);
984263bc
MD
533#ifdef DEBUG
534 if (ldebug(chdir))
26be20a0 535 kprintf(ARGS(chdir, "%s"), path);
984263bc 536#endif
21739618
MD
537 error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
538 if (error == 0) {
539 error = kern_chdir(&nd);
540 nlookup_done(&nd);
541 }
136178b3 542 linux_free_path(&path);
90b9818c 543 return(error);
984263bc
MD
544}
545
546int
753fd850 547sys_linux_chmod(struct linux_chmod_args *args)
984263bc 548{
fad57d0e 549 struct nlookupdata nd;
136178b3 550 char *path;
90b9818c 551 int error;
984263bc 552
136178b3
DRJ
553 error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
554 if (error)
555 return (error);
984263bc
MD
556#ifdef DEBUG
557 if (ldebug(chmod))
26be20a0 558 kprintf(ARGS(chmod, "%s, %d"), path, args->mode);
984263bc 559#endif
fad57d0e
MD
560 error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
561 if (error == 0)
562 error = kern_chmod(&nd, args->mode);
563 nlookup_done(&nd);
136178b3 564 linux_free_path(&path);
90b9818c 565 return(error);
984263bc
MD
566}
567
568int
753fd850 569sys_linux_mkdir(struct linux_mkdir_args *args)
984263bc 570{
fad57d0e 571 struct nlookupdata nd;
136178b3 572 char *path;
90b9818c 573 int error;
984263bc 574
136178b3
DRJ
575 error = linux_copyin_path(args->path, &path, LINUX_PATH_CREATE);
576 if (error)
577 return (error);
984263bc
MD
578#ifdef DEBUG
579 if (ldebug(mkdir))
26be20a0 580 kprintf(ARGS(mkdir, "%s, %d"), path, args->mode);
984263bc 581#endif
fad57d0e
MD
582 error = nlookup_init(&nd, path, UIO_SYSSPACE, 0);
583 if (error == 0)
584 error = kern_mkdir(&nd, args->mode);
585 nlookup_done(&nd);
136178b3
DRJ
586
587 linux_free_path(&path);
90b9818c 588 return(error);
984263bc
MD
589}
590
591int
753fd850 592sys_linux_rmdir(struct linux_rmdir_args *args)
984263bc 593{
fad57d0e 594 struct nlookupdata nd;
136178b3 595 char *path;
90b9818c 596 int error;
984263bc 597
136178b3
DRJ
598 error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
599 if (error)
600 return (error);
984263bc
MD
601#ifdef DEBUG
602 if (ldebug(rmdir))
26be20a0 603 kprintf(ARGS(rmdir, "%s"), path);
984263bc 604#endif
fad57d0e
MD
605 error = nlookup_init(&nd, path, UIO_SYSSPACE, 0);
606 if (error == 0)
607 error = kern_rmdir(&nd);
608 nlookup_done(&nd);
136178b3 609 linux_free_path(&path);
90b9818c 610 return(error);
984263bc
MD
611}
612
613int
753fd850 614sys_linux_rename(struct linux_rename_args *args)
984263bc 615{
fad57d0e 616 struct nlookupdata fromnd, tond;
136178b3 617 char *from, *to;
90b9818c 618 int error;
984263bc 619
136178b3
DRJ
620 error = linux_copyin_path(args->from, &from, LINUX_PATH_EXISTS);
621 if (error)
622 return (error);
623 error = linux_copyin_path(args->to, &to, LINUX_PATH_CREATE);
624 if (error) {
625 linux_free_path(&from);
626 return (error);
627 }
984263bc
MD
628#ifdef DEBUG
629 if (ldebug(rename))
26be20a0 630 kprintf(ARGS(rename, "%s, %s"), from, to);
984263bc 631#endif
fad57d0e
MD
632 error = nlookup_init(&fromnd, from, UIO_SYSSPACE, 0);
633 if (error == 0) {
634 error = nlookup_init(&tond, to, UIO_SYSSPACE, 0);
635 if (error == 0)
636 error = kern_rename(&fromnd, &tond);
637 nlookup_done(&tond);
638 }
639 nlookup_done(&fromnd);
136178b3
DRJ
640 linux_free_path(&from);
641 linux_free_path(&to);
90b9818c 642 return(error);
984263bc
MD
643}
644
645int
753fd850 646sys_linux_symlink(struct linux_symlink_args *args)
984263bc 647{
136178b3 648 struct thread *td = curthread;
fad57d0e 649 struct nlookupdata nd;
136178b3 650 char *path, *link;
90b9818c 651 int error;
fad57d0e 652 int mode;
984263bc 653
136178b3
DRJ
654 error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
655 if (error)
656 return (error);
657 error = linux_copyin_path(args->to, &link, LINUX_PATH_CREATE);
658 if (error) {
659 linux_free_path(&path);
660 return (error);
661 }
984263bc
MD
662#ifdef DEBUG
663 if (ldebug(symlink))
26be20a0 664 kprintf(ARGS(symlink, "%s, %s"), path, link);
984263bc 665#endif
fad57d0e
MD
666 error = nlookup_init(&nd, link, UIO_SYSSPACE, 0);
667 if (error == 0) {
668 mode = ACCESSPERMS & ~td->td_proc->p_fd->fd_cmask;
669 error = kern_symlink(&nd, path, mode);
670 }
671 nlookup_done(&nd);
136178b3
DRJ
672 linux_free_path(&path);
673 linux_free_path(&link);
90b9818c 674 return(error);
984263bc
MD
675}
676
677int
753fd850 678sys_linux_readlink(struct linux_readlink_args *args)
984263bc 679{
fad57d0e 680 struct nlookupdata nd;
136178b3 681 char *path;
90b9818c 682 int error;
984263bc 683
136178b3
DRJ
684 error = linux_copyin_path(args->name, &path, LINUX_PATH_EXISTS);
685 if (error)
686 return (error);
984263bc
MD
687#ifdef DEBUG
688 if (ldebug(readlink))
26be20a0 689 kprintf(ARGS(readlink, "%s, %p, %d"), path, (void *)args->buf,
136178b3 690 args->count);
984263bc 691#endif
fad57d0e
MD
692 error = nlookup_init(&nd, path, UIO_SYSSPACE, 0);
693 if (error == 0) {
694 error = kern_readlink(&nd, args->buf, args->count,
e54488bb 695 &args->sysmsg_iresult);
fad57d0e
MD
696 }
697 nlookup_done(&nd);
136178b3 698 linux_free_path(&path);
90b9818c 699 return(error);
984263bc
MD
700}
701
702int
753fd850 703sys_linux_truncate(struct linux_truncate_args *args)
984263bc 704{
fad57d0e 705 struct nlookupdata nd;
136178b3 706 char *path;
90b9818c 707 int error;
984263bc 708
136178b3
DRJ
709 error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
710 if (error)
711 return (error);
984263bc
MD
712#ifdef DEBUG
713 if (ldebug(truncate))
26be20a0 714 kprintf(ARGS(truncate, "%s, %ld"), path,
984263bc
MD
715 (long)args->length);
716#endif
fad57d0e
MD
717 error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
718 if (error == 0)
719 error = kern_truncate(&nd, args->length);
720 nlookup_done(&nd);
136178b3 721 linux_free_path(&path);
90b9818c 722 return(error);
984263bc
MD
723}
724
725int
753fd850 726sys_linux_truncate64(struct linux_truncate64_args *args)
7a228b16 727{
fad57d0e 728 struct nlookupdata nd;
7a228b16
DRJ
729 char *path;
730 int error;
731
732 error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
733 if (error)
734 return (error);
735#ifdef DEBUG
736 if (ldebug(truncate64))
26be20a0 737 kprintf(ARGS(truncate64, "%s, %lld"), path,
7a228b16
DRJ
738 (off_t)args->length);
739#endif
fad57d0e
MD
740 error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
741 if (error == 0)
742 error = kern_truncate(&nd, args->length);
743 nlookup_done(&nd);
7a228b16
DRJ
744 linux_free_path(&path);
745 return error;
746}
747
748int
753fd850 749sys_linux_ftruncate(struct linux_ftruncate_args *args)
8f6f8622
DRJ
750{
751 int error;
752
753#ifdef DEBUG
754 if (ldebug(ftruncate))
26be20a0 755 kprintf(ARGS(ftruncate, "%d, %ld"), args->fd,
8f6f8622
DRJ
756 (long)args->length);
757#endif
758 error = kern_ftruncate(args->fd, args->length);
759
760 return error;
761}
762
763int
753fd850 764sys_linux_ftruncate64(struct linux_ftruncate64_args *args)
7a228b16
DRJ
765{
766 int error;
767
768#ifdef DEBUG
769 if (ldebug(ftruncate))
26be20a0 770 kprintf(ARGS(ftruncate64, "%d, %lld"), args->fd,
7a228b16
DRJ
771 (off_t)args->length);
772#endif
773 error = kern_ftruncate(args->fd, args->length);
774
775 return error;
776}
777
778int
753fd850 779sys_linux_link(struct linux_link_args *args)
984263bc 780{
fad57d0e 781 struct nlookupdata nd, linknd;
136178b3
DRJ
782 char *path, *link;
783 int error;
984263bc 784
136178b3
DRJ
785 error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
786 if (error)
787 return (error);
788 error = linux_copyin_path(args->to, &link, LINUX_PATH_CREATE);
789 if (error) {
790 linux_free_path(&path);
791 return (error);
792 }
984263bc
MD
793#ifdef DEBUG
794 if (ldebug(link))
26be20a0 795 kprintf(ARGS(link, "%s, %s"), path, link);
984263bc 796#endif
fad57d0e
MD
797 error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
798 if (error == 0) {
799 error = nlookup_init(&linknd, link, UIO_SYSSPACE, 0);
800 if (error == 0)
801 error = kern_link(&nd, &linknd);
802 nlookup_done(&linknd);
803 }
804 nlookup_done(&nd);
136178b3
DRJ
805 linux_free_path(&path);
806 linux_free_path(&link);
807 return(error);
984263bc
MD
808}
809
984263bc 810int
753fd850 811sys_linux_fdatasync(struct linux_fdatasync_args *uap)
984263bc
MD
812{
813 struct fsync_args bsd;
90b9818c 814 int error;
984263bc
MD
815
816 bsd.fd = uap->fd;
e54488bb 817 bsd.sysmsg_iresult = 0;
90b9818c 818
753fd850 819 error = sys_fsync(&bsd);
e54488bb 820 uap->sysmsg_iresult = bsd.sysmsg_iresult;
90b9818c 821 return(error);
984263bc 822}
984263bc
MD
823
824int
753fd850 825sys_linux_pread(struct linux_pread_args *uap)
984263bc 826{
ba023347
DRJ
827 struct thread *td = curthread;
828 struct uio auio;
829 struct iovec aiov;
90b9818c 830 int error;
984263bc 831
ba023347
DRJ
832 aiov.iov_base = uap->buf;
833 aiov.iov_len = uap->nbyte;
834 auio.uio_iov = &aiov;
835 auio.uio_iovcnt = 1;
836 auio.uio_offset = uap->offset;
837 auio.uio_resid = uap->nbyte;
838 auio.uio_rw = UIO_READ;
839 auio.uio_segflg = UIO_USERSPACE;
840 auio.uio_td = td;
841
e54488bb 842 if ((ssize_t)auio.uio_resid < 0) {
ef5c76d7 843 error = EINVAL;
e54488bb
MD
844 } else {
845 error = kern_preadv(uap->fd, &auio, O_FOFFSET,
846 &uap->sysmsg_szresult);
847 }
90b9818c 848 return(error);
984263bc
MD
849}
850
851int
753fd850 852sys_linux_pwrite(struct linux_pwrite_args *uap)
984263bc 853{
ba023347
DRJ
854 struct thread *td = curthread;
855 struct uio auio;
856 struct iovec aiov;
90b9818c 857 int error;
984263bc 858
ba023347
DRJ
859 aiov.iov_base = uap->buf;
860 aiov.iov_len = uap->nbyte;
861 auio.uio_iov = &aiov;
862 auio.uio_iovcnt = 1;
863 auio.uio_offset = uap->offset;
864 auio.uio_resid = uap->nbyte;
865 auio.uio_rw = UIO_WRITE;
866 auio.uio_segflg = UIO_USERSPACE;
867 auio.uio_td = td;
868
e54488bb 869 if ((ssize_t)auio.uio_resid < 0) {
ef5c76d7 870 error = EINVAL;
e54488bb
MD
871 } else {
872 error = kern_pwritev(uap->fd, &auio, O_FOFFSET,
873 &uap->sysmsg_szresult);
874 }
90b9818c 875 return(error);
984263bc
MD
876}
877
878int
753fd850 879sys_linux_oldumount(struct linux_oldumount_args *args)
984263bc
MD
880{
881 struct linux_umount_args args2;
90b9818c 882 int error;
984263bc
MD
883
884 args2.path = args->path;
885 args2.flags = 0;
e54488bb 886 args2.sysmsg_iresult = 0;
753fd850 887 error = sys_linux_umount(&args2);
e54488bb 888 args->sysmsg_iresult = args2.sysmsg_iresult;
90b9818c 889 return(error);
984263bc
MD
890}
891
892int
753fd850 893sys_linux_umount(struct linux_umount_args *args)
984263bc
MD
894{
895 struct unmount_args bsd;
90b9818c 896 int error;
984263bc
MD
897
898 bsd.path = args->path;
899 bsd.flags = args->flags; /* XXX correct? */
e54488bb 900 bsd.sysmsg_iresult = 0;
90b9818c 901
753fd850 902 error = sys_unmount(&bsd);
e54488bb 903 args->sysmsg_iresult = bsd.sysmsg_iresult;
90b9818c 904 return(error);
984263bc
MD
905}
906
907/*
908 * fcntl family of syscalls
909 */
910
911struct l_flock {
912 l_short l_type;
913 l_short l_whence;
914 l_off_t l_start;
915 l_off_t l_len;
916 l_pid_t l_pid;
917};
918
919static void
920linux_to_bsd_flock(struct l_flock *linux_flock, struct flock *bsd_flock)
921{
922 switch (linux_flock->l_type) {
923 case LINUX_F_RDLCK:
924 bsd_flock->l_type = F_RDLCK;
925 break;
926 case LINUX_F_WRLCK:
927 bsd_flock->l_type = F_WRLCK;
928 break;
929 case LINUX_F_UNLCK:
930 bsd_flock->l_type = F_UNLCK;
931 break;
932 default:
933 bsd_flock->l_type = -1;
934 break;
935 }
936 bsd_flock->l_whence = linux_flock->l_whence;
937 bsd_flock->l_start = (off_t)linux_flock->l_start;
938 bsd_flock->l_len = (off_t)linux_flock->l_len;
939 bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
940}
941
942static void
943bsd_to_linux_flock(struct flock *bsd_flock, struct l_flock *linux_flock)
944{
945 switch (bsd_flock->l_type) {
946 case F_RDLCK:
947 linux_flock->l_type = LINUX_F_RDLCK;
948 break;
949 case F_WRLCK:
950 linux_flock->l_type = LINUX_F_WRLCK;
951 break;
952 case F_UNLCK:
953 linux_flock->l_type = LINUX_F_UNLCK;
954 break;
955 }
956 linux_flock->l_whence = bsd_flock->l_whence;
957 linux_flock->l_start = (l_off_t)bsd_flock->l_start;
958 linux_flock->l_len = (l_off_t)bsd_flock->l_len;
959 linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
960}
961
962#if defined(__i386__)
963struct l_flock64 {
964 l_short l_type;
965 l_short l_whence;
966 l_loff_t l_start;
967 l_loff_t l_len;
968 l_pid_t l_pid;
969};
970
971static void
972linux_to_bsd_flock64(struct l_flock64 *linux_flock, struct flock *bsd_flock)
973{
974 switch (linux_flock->l_type) {
975 case LINUX_F_RDLCK:
976 bsd_flock->l_type = F_RDLCK;
977 break;
978 case LINUX_F_WRLCK:
979 bsd_flock->l_type = F_WRLCK;
980 break;
981 case LINUX_F_UNLCK:
982 bsd_flock->l_type = F_UNLCK;
983 break;
984 default:
985 bsd_flock->l_type = -1;
986 break;
987 }
988 bsd_flock->l_whence = linux_flock->l_whence;
989 bsd_flock->l_start = (off_t)linux_flock->l_start;
990 bsd_flock->l_len = (off_t)linux_flock->l_len;
991 bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
992}
993
994static void
995bsd_to_linux_flock64(struct flock *bsd_flock, struct l_flock64 *linux_flock)
996{
997 switch (bsd_flock->l_type) {
998 case F_RDLCK:
999 linux_flock->l_type = LINUX_F_RDLCK;
1000 break;
1001 case F_WRLCK:
1002 linux_flock->l_type = LINUX_F_WRLCK;
1003 break;
1004 case F_UNLCK:
1005 linux_flock->l_type = LINUX_F_UNLCK;
1006 break;
1007 }
1008 linux_flock->l_whence = bsd_flock->l_whence;
1009 linux_flock->l_start = (l_loff_t)bsd_flock->l_start;
1010 linux_flock->l_len = (l_loff_t)bsd_flock->l_len;
1011 linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
1012}
1013#endif /* __i386__ */
1014
984263bc 1015static int
dda4b42b 1016linux_fcntl_common(struct linux_fcntl64_args *args)
984263bc 1017{
41c20dac 1018 struct proc *p = curproc;
984263bc 1019 struct l_flock linux_flock;
984263bc 1020 struct file *fp;
dda4b42b
DRJ
1021 union fcntl_dat dat;
1022 int error, cmd;
984263bc
MD
1023
1024 switch (args->cmd) {
1025 case LINUX_F_DUPFD:
dda4b42b
DRJ
1026 cmd = F_DUPFD;
1027 dat.fc_fd = args->arg;
90b9818c 1028 break;
984263bc 1029 case LINUX_F_GETFD:
dda4b42b 1030 cmd = F_GETFD;
90b9818c 1031 break;
984263bc 1032 case LINUX_F_SETFD:
dda4b42b
DRJ
1033 cmd = F_SETFD;
1034 dat.fc_cloexec = args->arg;
90b9818c 1035 break;
984263bc 1036 case LINUX_F_GETFL:
dda4b42b
DRJ
1037 cmd = F_GETFL;
1038 break;
984263bc 1039 case LINUX_F_SETFL:
dda4b42b
DRJ
1040 cmd = F_SETFL;
1041 dat.fc_flags = 0;
984263bc 1042 if (args->arg & LINUX_O_NDELAY)
dda4b42b 1043 dat.fc_flags |= O_NONBLOCK;
984263bc 1044 if (args->arg & LINUX_O_APPEND)
dda4b42b 1045 dat.fc_flags |= O_APPEND;
984263bc 1046 if (args->arg & LINUX_O_SYNC)
dda4b42b 1047 dat.fc_flags |= O_FSYNC;
984263bc 1048 if (args->arg & LINUX_FASYNC)
dda4b42b 1049 dat.fc_flags |= O_ASYNC;
90b9818c 1050 break;
984263bc 1051 case LINUX_F_GETLK:
984263bc 1052 case LINUX_F_SETLK:
984263bc 1053 case LINUX_F_SETLKW:
dda4b42b 1054 cmd = F_GETLK;
984263bc
MD
1055 error = copyin((caddr_t)args->arg, &linux_flock,
1056 sizeof(linux_flock));
1057 if (error)
1058 return (error);
dda4b42b 1059 linux_to_bsd_flock(&linux_flock, &dat.fc_flock);
90b9818c 1060 break;
984263bc 1061 case LINUX_F_GETOWN:
dda4b42b 1062 cmd = F_GETOWN;
90b9818c 1063 break;
984263bc
MD
1064 case LINUX_F_SETOWN:
1065 /*
1066 * XXX some Linux applications depend on F_SETOWN having no
1067 * significant effect for pipes (SIGIO is not delivered for
1068 * pipes under Linux-2.2.35 at least).
1069 */
228b401d
MD
1070 fp = holdfp(p->p_fd, args->fd, -1);
1071 if (fp == NULL)
984263bc 1072 return (EBADF);
228b401d
MD
1073 if (fp->f_type == DTYPE_PIPE) {
1074 fdrop(fp);
984263bc 1075 return (EINVAL);
228b401d
MD
1076 }
1077 fdrop(fp);
dda4b42b
DRJ
1078 cmd = F_SETOWN;
1079 dat.fc_owner = args->arg;
90b9818c
MD
1080 break;
1081 default:
1082 return (EINVAL);
984263bc 1083 }
dda4b42b 1084
87de5057 1085 error = kern_fcntl(args->fd, cmd, &dat, p->p_ucred);
dda4b42b
DRJ
1086
1087 if (error == 0) {
1088 switch (args->cmd) {
1089 case LINUX_F_DUPFD:
e54488bb 1090 args->sysmsg_iresult = dat.fc_fd;
dda4b42b
DRJ
1091 break;
1092 case LINUX_F_GETFD:
e54488bb 1093 args->sysmsg_iresult = dat.fc_cloexec;
dda4b42b
DRJ
1094 break;
1095 case LINUX_F_SETFD:
1096 break;
1097 case LINUX_F_GETFL:
e54488bb 1098 args->sysmsg_iresult = 0;
dda4b42b 1099 if (dat.fc_flags & O_RDONLY)
e54488bb 1100 args->sysmsg_iresult |= LINUX_O_RDONLY;
dda4b42b 1101 if (dat.fc_flags & O_WRONLY)
e54488bb 1102 args->sysmsg_iresult |= LINUX_O_WRONLY;
dda4b42b 1103 if (dat.fc_flags & O_RDWR)
e54488bb 1104 args->sysmsg_iresult |= LINUX_O_RDWR;
dda4b42b 1105 if (dat.fc_flags & O_NDELAY)
e54488bb 1106 args->sysmsg_iresult |= LINUX_O_NONBLOCK;
dda4b42b 1107 if (dat.fc_flags & O_APPEND)
e54488bb 1108 args->sysmsg_iresult |= LINUX_O_APPEND;
dda4b42b 1109 if (dat.fc_flags & O_FSYNC)
e54488bb 1110 args->sysmsg_iresult |= LINUX_O_SYNC;
dda4b42b 1111 if (dat.fc_flags & O_ASYNC)
e54488bb 1112 args->sysmsg_iresult |= LINUX_FASYNC;
dda4b42b
DRJ
1113 break;
1114 case LINUX_F_GETLK:
1115 bsd_to_linux_flock(&dat.fc_flock, &linux_flock);
1116 error = copyout(&linux_flock, (caddr_t)args->arg,
1117 sizeof(linux_flock));
1118 break;
1119 case LINUX_F_SETLK:
1120 case LINUX_F_SETLKW:
1121 break;
1122 case LINUX_F_GETOWN:
e54488bb 1123 args->sysmsg_iresult = dat.fc_owner;
dda4b42b
DRJ
1124 break;
1125 case LINUX_F_SETOWN:
1126 break;
1127 }
1128 }
1129
90b9818c 1130 return(error);
984263bc
MD
1131}
1132
1133int
753fd850 1134sys_linux_fcntl(struct linux_fcntl_args *args)
984263bc
MD
1135{
1136 struct linux_fcntl64_args args64;
90b9818c 1137 int error;
984263bc
MD
1138
1139#ifdef DEBUG
1140 if (ldebug(fcntl))
26be20a0 1141 kprintf(ARGS(fcntl, "%d, %08x, *"), args->fd, args->cmd);
984263bc
MD
1142#endif
1143
1144 args64.fd = args->fd;
1145 args64.cmd = args->cmd;
1146 args64.arg = args->arg;
e54488bb 1147 args64.sysmsg_iresult = 0;
dda4b42b 1148 error = linux_fcntl_common(&args64);
e54488bb 1149 args->sysmsg_iresult = args64.sysmsg_iresult;
90b9818c 1150 return(error);
984263bc
MD
1151}
1152
1153#if defined(__i386__)
1154int
753fd850 1155sys_linux_fcntl64(struct linux_fcntl64_args *args)
984263bc 1156{
984263bc 1157 struct l_flock64 linux_flock;
dda4b42b
DRJ
1158 union fcntl_dat dat;
1159 int error, cmd = 0;
984263bc
MD
1160
1161#ifdef DEBUG
1162 if (ldebug(fcntl64))
26be20a0 1163 kprintf(ARGS(fcntl64, "%d, %08x, *"), args->fd, args->cmd);
984263bc 1164#endif
dda4b42b
DRJ
1165 if (args->cmd == LINUX_F_GETLK64 || args->cmd == LINUX_F_SETLK64 ||
1166 args->cmd == LINUX_F_SETLKW64) {
1167 switch (args->cmd) {
1168 case LINUX_F_GETLK64:
1169 cmd = F_GETLK;
1170 break;
1171 case LINUX_F_SETLK64:
1172 cmd = F_SETLK;
1173 break;
1174 case LINUX_F_SETLKW64:
1175 cmd = F_SETLKW;
1176 break;
1177 }
984263bc 1178
984263bc
MD
1179 error = copyin((caddr_t)args->arg, &linux_flock,
1180 sizeof(linux_flock));
1181 if (error)
1182 return (error);
dda4b42b 1183 linux_to_bsd_flock64(&linux_flock, &dat.fc_flock);
984263bc 1184
87de5057 1185 error = kern_fcntl(args->fd, cmd, &dat, curproc->p_ucred);
dda4b42b
DRJ
1186
1187 if (error == 0 && args->cmd == LINUX_F_GETLK64) {
1188 bsd_to_linux_flock64(&dat.fc_flock, &linux_flock);
1189 error = copyout(&linux_flock, (caddr_t)args->arg,
1190 sizeof(linux_flock));
1191 }
1192 } else {
1193 error = linux_fcntl_common(args);
984263bc
MD
1194 }
1195
dda4b42b 1196 return (error);
984263bc
MD
1197}
1198#endif /* __i386__ */
1199
1200int
753fd850 1201sys_linux_chown(struct linux_chown_args *args)
984263bc 1202{
fad57d0e 1203 struct nlookupdata nd;
136178b3 1204 char *path;
90b9818c 1205 int error;
984263bc 1206
136178b3
DRJ
1207 error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
1208 if (error)
1209 return (error);
984263bc
MD
1210#ifdef DEBUG
1211 if (ldebug(chown))
26be20a0 1212 kprintf(ARGS(chown, "%s, %d, %d"), path, args->uid, args->gid);
984263bc 1213#endif
fad57d0e
MD
1214 error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
1215 if (error == 0)
1216 error = kern_chown(&nd, args->uid, args->gid);
1217 nlookup_done(&nd);
136178b3 1218 linux_free_path(&path);
90b9818c 1219 return(error);
984263bc
MD
1220}
1221
1222int
753fd850 1223sys_linux_lchown(struct linux_lchown_args *args)
984263bc 1224{
fad57d0e 1225 struct nlookupdata nd;
136178b3 1226 char *path;
90b9818c 1227 int error;
984263bc 1228
136178b3
DRJ
1229 error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
1230 if (error)
1231 return (error);
984263bc
MD
1232#ifdef DEBUG
1233 if (ldebug(lchown))
26be20a0 1234 kprintf(ARGS(lchown, "%s, %d, %d"), path, args->uid, args->gid);
984263bc 1235#endif
fad57d0e
MD
1236 error = nlookup_init(&nd, path, UIO_SYSSPACE, 0);
1237 if (error == 0)
1238 error = kern_chown(&nd, args->uid, args->gid);
1239 nlookup_done(&nd);
136178b3 1240 linux_free_path(&path);
90b9818c 1241 return(error);
984263bc 1242}
90b9818c 1243