]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/i386/ibcs2/ibcs2_misc.c
Merge llvm trunk r321414 to contrib/llvm.
[FreeBSD/FreeBSD.git] / sys / i386 / ibcs2 / ibcs2_misc.c
1 /*-
2  * SPDX-License-Identifier: BSD-4-Clause
3  *
4  * Copyright (c) 1995 Steven Wallace
5  * Copyright (c) 1994, 1995 Scott Bartram
6  * Copyright (c) 1992, 1993
7  *      The Regents of the University of California.  All rights reserved.
8  *
9  * This software was developed by the Computer Systems Engineering group
10  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
11  * contributed to Berkeley.
12  *
13  * All advertising materials mentioning features or use of this software
14  * must display the following acknowledgement:
15  *      This product includes software developed by the University of
16  *      California, Lawrence Berkeley Laboratory.
17  *
18  * Redistribution and use in source and binary forms, with or without
19  * modification, are permitted provided that the following conditions
20  * are met:
21  * 1. Redistributions of source code must retain the above copyright
22  *    notice, this list of conditions and the following disclaimer.
23  * 2. Redistributions in binary form must reproduce the above copyright
24  *    notice, this list of conditions and the following disclaimer in the
25  *    documentation and/or other materials provided with the distribution.
26  * 3. All advertising materials mentioning features or use of this software
27  *    must display the following acknowledgement:
28  *      This product includes software developed by the University of
29  *      California, Berkeley and its contributors.
30  * 4. Neither the name of the University nor the names of its contributors
31  *    may be used to endorse or promote products derived from this software
32  *    without specific prior written permission.
33  *
34  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
35  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
38  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
39  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
40  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
41  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
43  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44  * SUCH DAMAGE.
45  *
46  * from: Header: sun_misc.c,v 1.16 93/04/07 02:46:27 torek Exp 
47  *
48  *      @(#)sun_misc.c  8.1 (Berkeley) 6/18/93
49  */
50
51 #include <sys/cdefs.h>
52 __FBSDID("$FreeBSD$");
53
54 /*
55  * IBCS2 compatibility module.
56  *
57  * IBCS2 system calls that are implemented differently in BSD are
58  * handled here.
59  */
60 #include <sys/param.h>
61 #include <sys/systm.h>
62 #include <sys/capsicum.h>
63 #include <sys/dirent.h>
64 #include <sys/fcntl.h>
65 #include <sys/filedesc.h>
66 #include <sys/imgact.h>
67 #include <sys/kernel.h>
68 #include <sys/lock.h>
69 #include <sys/malloc.h>
70 #include <sys/file.h>                   /* Must come after sys/malloc.h */
71 #include <sys/mutex.h>
72 #include <sys/namei.h>
73 #include <sys/priv.h>
74 #include <sys/reboot.h>
75 #include <sys/resourcevar.h>
76 #include <sys/stat.h>
77 #include <sys/sysctl.h>
78 #include <sys/syscallsubr.h>
79 #include <sys/sysproto.h>
80 #include <sys/time.h>
81 #include <sys/times.h>
82 #include <sys/vnode.h>
83 #include <sys/wait.h>
84
85 #include <machine/cpu.h>
86
87 #include <i386/ibcs2/ibcs2_dirent.h>
88 #include <i386/ibcs2/ibcs2_signal.h>
89 #include <i386/ibcs2/ibcs2_proto.h>
90 #include <i386/ibcs2/ibcs2_unistd.h>
91 #include <i386/ibcs2/ibcs2_util.h>
92 #include <i386/ibcs2/ibcs2_utime.h>
93 #include <i386/ibcs2/ibcs2_xenix.h>
94
95 #include <security/mac/mac_framework.h>
96
97 int
98 ibcs2_ulimit(struct thread *td, struct ibcs2_ulimit_args *uap)
99 {
100         struct rlimit rl;
101         int error;
102 #define IBCS2_GETFSIZE          1
103 #define IBCS2_SETFSIZE          2
104 #define IBCS2_GETPSIZE          3
105 #define IBCS2_GETDTABLESIZE     4
106
107         switch (uap->cmd) {
108         case IBCS2_GETFSIZE:
109                 td->td_retval[0] = lim_cur(td, RLIMIT_FSIZE);
110                 if (td->td_retval[0] == -1)
111                         td->td_retval[0] = 0x7fffffff;
112                 return 0;
113         case IBCS2_SETFSIZE:
114                 rl.rlim_max = lim_max(td, RLIMIT_FSIZE);
115                 rl.rlim_cur = uap->newlimit;
116                 error = kern_setrlimit(td, RLIMIT_FSIZE, &rl);
117                 if (!error) {
118                         td->td_retval[0] = lim_cur(td, RLIMIT_FSIZE);
119                 } else {
120                         DPRINTF(("failed "));
121                 }
122                 return error;
123         case IBCS2_GETPSIZE:
124                 td->td_retval[0] = lim_cur(td, RLIMIT_RSS); /* XXX */
125                 return 0;
126         case IBCS2_GETDTABLESIZE:
127                 uap->cmd = IBCS2_SC_OPEN_MAX;
128                 return ibcs2_sysconf(td, (struct ibcs2_sysconf_args *)uap);
129         default:
130                 return ENOSYS;
131         }
132 }
133
134 #define IBCS2_WSTOPPED       0177
135 #define IBCS2_STOPCODE(sig)  ((sig) << 8 | IBCS2_WSTOPPED)
136 int
137 ibcs2_wait(struct thread *td, struct ibcs2_wait_args *uap)
138 {
139         int error, options, status;
140         int *statusp;
141         pid_t pid;
142         struct trapframe *tf = td->td_frame;
143         
144         if ((tf->tf_eflags & (PSL_Z|PSL_PF|PSL_N|PSL_V))
145             == (PSL_Z|PSL_PF|PSL_N|PSL_V)) {
146                 /* waitpid */
147                 pid = uap->a1;
148                 statusp = (int *)uap->a2;
149                 options = uap->a3;
150         } else {
151                 /* wait */
152                 pid = WAIT_ANY;
153                 statusp = (int *)uap->a1;
154                 options = 0;
155         }
156         error = kern_wait(td, pid, &status, options, NULL);
157         if (error)
158                 return error;
159         if (statusp) {
160                 /*
161                  * Convert status/signal result.
162                  */
163                 if (WIFSTOPPED(status)) {
164                         if (WSTOPSIG(status) <= 0 ||
165                             WSTOPSIG(status) > IBCS2_SIGTBLSZ)
166                                 return (EINVAL);
167                         status =
168                           IBCS2_STOPCODE(bsd_to_ibcs2_sig[_SIG_IDX(WSTOPSIG(status))]);
169                 } else if (WIFSIGNALED(status)) {
170                         if (WTERMSIG(status) <= 0 ||
171                             WTERMSIG(status) > IBCS2_SIGTBLSZ)
172                                 return (EINVAL);
173                         status = bsd_to_ibcs2_sig[_SIG_IDX(WTERMSIG(status))];
174                 }
175                 /* else exit status -- identical */
176
177                 /* record result/status */
178                 td->td_retval[1] = status;
179                 return copyout(&status, statusp, sizeof(status));
180         }
181
182         return 0;
183 }
184
185 int
186 ibcs2_execv(struct thread *td, struct ibcs2_execv_args *uap)
187 {
188         struct image_args eargs;
189         struct vmspace *oldvmspace;
190         char *path;
191         int error;
192
193         CHECKALTEXIST(td, uap->path, &path);
194
195         error = pre_execve(td, &oldvmspace);
196         if (error != 0) {
197                 free(path, M_TEMP);
198                 return (error);
199         }
200         error = exec_copyin_args(&eargs, path, UIO_SYSSPACE, uap->argp, NULL);
201         free(path, M_TEMP);
202         if (error == 0)
203                 error = kern_execve(td, &eargs, NULL);
204         post_execve(td, error, oldvmspace);
205         return (error);
206 }
207
208 int
209 ibcs2_execve(struct thread *td, struct ibcs2_execve_args *uap)
210 {
211         struct image_args eargs;
212         struct vmspace *oldvmspace;
213         char *path;
214         int error;
215
216         CHECKALTEXIST(td, uap->path, &path);
217
218         error = pre_execve(td, &oldvmspace);
219         if (error != 0) {
220                 free(path, M_TEMP);
221                 return (error);
222         }
223         error = exec_copyin_args(&eargs, path, UIO_SYSSPACE, uap->argp,
224             uap->envp);
225         free(path, M_TEMP);
226         if (error == 0)
227                 error = kern_execve(td, &eargs, NULL);
228         post_execve(td, error, oldvmspace);
229         return (error);
230 }
231
232 int
233 ibcs2_umount(struct thread *td, struct ibcs2_umount_args *uap)
234 {
235         struct unmount_args um;
236
237         um.path = uap->name;
238         um.flags = 0;
239         return sys_unmount(td, &um);
240 }
241
242 int
243 ibcs2_mount(struct thread *td, struct ibcs2_mount_args *uap)
244 {
245 #ifdef notyet
246         int oflags = uap->flags, nflags, error;
247         char fsname[MFSNAMELEN];
248
249         if (oflags & (IBCS2_MS_NOSUB | IBCS2_MS_SYS5))
250                 return (EINVAL);
251         if ((oflags & IBCS2_MS_NEWTYPE) == 0)
252                 return (EINVAL);
253         nflags = 0;
254         if (oflags & IBCS2_MS_RDONLY)
255                 nflags |= MNT_RDONLY;
256         if (oflags & IBCS2_MS_NOSUID)
257                 nflags |= MNT_NOSUID;
258         if (oflags & IBCS2_MS_REMOUNT)
259                 nflags |= MNT_UPDATE;
260         uap->flags = nflags;
261
262         if (error = copyinstr((caddr_t)uap->type, fsname, sizeof fsname,
263                               (u_int *)0))
264                 return (error);
265
266         if (strcmp(fsname, "4.2") == 0) {
267                 uap->type = (caddr_t)STACK_ALLOC();
268                 if (error = copyout("ufs", uap->type, sizeof("ufs")))
269                         return (error);
270         } else if (strcmp(fsname, "nfs") == 0) {
271                 struct ibcs2_nfs_args sna;
272                 struct sockaddr_in sain;
273                 struct nfs_args na;
274                 struct sockaddr sa;
275
276                 if (error = copyin(uap->data, &sna, sizeof sna))
277                         return (error);
278                 if (error = copyin(sna.addr, &sain, sizeof sain))
279                         return (error);
280                 bcopy(&sain, &sa, sizeof sa);
281                 sa.sa_len = sizeof(sain);
282                 uap->data = (caddr_t)STACK_ALLOC();
283                 na.addr = (struct sockaddr *)((int)uap->data + sizeof na);
284                 na.sotype = SOCK_DGRAM;
285                 na.proto = IPPROTO_UDP;
286                 na.fh = (nfsv2fh_t *)sna.fh;
287                 na.flags = sna.flags;
288                 na.wsize = sna.wsize;
289                 na.rsize = sna.rsize;
290                 na.timeo = sna.timeo;
291                 na.retrans = sna.retrans;
292                 na.hostname = sna.hostname;
293
294                 if (error = copyout(&sa, na.addr, sizeof sa))
295                         return (error);
296                 if (error = copyout(&na, uap->data, sizeof na))
297                         return (error);
298         }
299         return (mount(td, uap));
300 #else
301         return EINVAL;
302 #endif
303 }
304
305 /*
306  * Read iBCS2-style directory entries.  We suck them into kernel space so
307  * that they can be massaged before being copied out to user code.  Like
308  * SunOS, we squish out `empty' entries.
309  *
310  * This is quite ugly, but what do you expect from compatibility code?
311  */
312
313 int
314 ibcs2_getdents(struct thread *td, struct ibcs2_getdents_args *uap)
315 {
316         struct vnode *vp;
317         caddr_t inp, buf;               /* BSD-format */
318         int len, reclen;                /* BSD-format */
319         caddr_t outp;                   /* iBCS2-format */
320         int resid;                      /* iBCS2-format */
321         cap_rights_t rights;
322         struct file *fp;
323         struct uio auio;
324         struct iovec aiov;
325         struct ibcs2_dirent idb;
326         off_t off;                      /* true file offset */
327         int buflen, error, eofflag;
328         u_long *cookies = NULL, *cookiep;
329         int ncookies;
330 #define BSD_DIRENT(cp)          ((struct dirent *)(cp))
331 #define IBCS2_RECLEN(reclen)    (reclen + sizeof(u_short))
332
333         error = getvnode(td, uap->fd, cap_rights_init(&rights, CAP_READ), &fp);
334         if (error != 0)
335                 return (error);
336         if ((fp->f_flag & FREAD) == 0) {
337                 fdrop(fp, td);
338                 return (EBADF);
339         }
340         vp = fp->f_vnode;
341         if (vp->v_type != VDIR) {       /* XXX  vnode readdir op should do this */
342                 fdrop(fp, td);
343                 return (EINVAL);
344         }
345
346         off = fp->f_offset;
347 #define DIRBLKSIZ       512             /* XXX we used to use ufs's DIRBLKSIZ */
348         buflen = max(DIRBLKSIZ, uap->nbytes);
349         buflen = min(buflen, MAXBSIZE);
350         buf = malloc(buflen, M_TEMP, M_WAITOK);
351         vn_lock(vp, LK_SHARED | LK_RETRY);
352 again:
353         aiov.iov_base = buf;
354         aiov.iov_len = buflen;
355         auio.uio_iov = &aiov;
356         auio.uio_iovcnt = 1;
357         auio.uio_rw = UIO_READ;
358         auio.uio_segflg = UIO_SYSSPACE;
359         auio.uio_td = td;
360         auio.uio_resid = buflen;
361         auio.uio_offset = off;
362
363         if (cookies) {
364                 free(cookies, M_TEMP);
365                 cookies = NULL;
366         }
367
368 #ifdef MAC
369         error = mac_vnode_check_readdir(td->td_ucred, vp);
370         if (error)
371                 goto out;
372 #endif
373
374         /*
375          * First we read into the malloc'ed buffer, then
376          * we massage it into user space, one record at a time.
377          */
378         if ((error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies, &cookies)) != 0)
379                 goto out;
380         inp = buf;
381         outp = uap->buf;
382         resid = uap->nbytes;
383         if ((len = buflen - auio.uio_resid) <= 0)
384                 goto eof;
385
386         cookiep = cookies;
387
388         if (cookies) {
389                 /*
390                  * When using cookies, the vfs has the option of reading from
391                  * a different offset than that supplied (UFS truncates the
392                  * offset to a block boundary to make sure that it never reads
393                  * partway through a directory entry, even if the directory
394                  * has been compacted).
395                  */
396                 while (len > 0 && ncookies > 0 && *cookiep <= off) {
397                         len -= BSD_DIRENT(inp)->d_reclen;
398                         inp += BSD_DIRENT(inp)->d_reclen;
399                         cookiep++;
400                         ncookies--;
401                 }
402         }
403
404         for (; len > 0; len -= reclen) {
405                 if (cookiep && ncookies == 0)
406                         break;
407                 reclen = BSD_DIRENT(inp)->d_reclen;
408                 if (reclen & 3) {
409                         printf("ibcs2_getdents: reclen=%d\n", reclen);
410                         error = EFAULT;
411                         goto out;
412                 }
413                 if (BSD_DIRENT(inp)->d_fileno == 0) {
414                         inp += reclen;  /* it is a hole; squish it out */
415                         if (cookiep) {
416                                 off = *cookiep++;
417                                 ncookies--;
418                         } else
419                                 off += reclen;
420                         continue;
421                 }
422                 if (reclen > len || resid < IBCS2_RECLEN(reclen)) {
423                         /* entry too big for buffer, so just stop */
424                         outp++;
425                         break;
426                 }
427                 /*
428                  * Massage in place to make an iBCS2-shaped dirent (otherwise
429                  * we have to worry about touching user memory outside of
430                  * the copyout() call).
431                  */
432                 idb.d_ino = (ibcs2_ino_t)BSD_DIRENT(inp)->d_fileno;
433                 idb.d_off = (ibcs2_off_t)off;
434                 idb.d_reclen = (u_short)IBCS2_RECLEN(reclen);
435                 if ((error = copyout((caddr_t)&idb, outp, 10)) != 0 ||
436                     (error = copyout(BSD_DIRENT(inp)->d_name, outp + 10,
437                                      BSD_DIRENT(inp)->d_namlen + 1)) != 0)
438                         goto out;
439                 /* advance past this real entry */
440                 if (cookiep) {
441                         off = *cookiep++;
442                         ncookies--;
443                 } else
444                         off += reclen;
445                 inp += reclen;
446                 /* advance output past iBCS2-shaped entry */
447                 outp += IBCS2_RECLEN(reclen);
448                 resid -= IBCS2_RECLEN(reclen);
449         }
450         /* if we squished out the whole block, try again */
451         if (outp == uap->buf)
452                 goto again;
453         fp->f_offset = off;             /* update the vnode offset */
454 eof:
455         td->td_retval[0] = uap->nbytes - resid;
456 out:
457         VOP_UNLOCK(vp, 0);
458         fdrop(fp, td);
459         if (cookies)
460                 free(cookies, M_TEMP);
461         free(buf, M_TEMP);
462         return (error);
463 }
464
465 int
466 ibcs2_read(struct thread *td, struct ibcs2_read_args *uap)
467 {
468         struct vnode *vp;
469         caddr_t inp, buf;               /* BSD-format */
470         int len, reclen;                /* BSD-format */
471         caddr_t outp;                   /* iBCS2-format */
472         int resid;                      /* iBCS2-format */
473         cap_rights_t rights;
474         struct file *fp;
475         struct uio auio;
476         struct iovec aiov;
477         struct ibcs2_direct {
478                 ibcs2_ino_t ino;
479                 char name[14];
480         } idb;
481         off_t off;                      /* true file offset */
482         int buflen, error, eofflag, size;
483         u_long *cookies = NULL, *cookiep;
484         int ncookies;
485
486         error = getvnode(td, uap->fd, cap_rights_init(&rights, CAP_READ), &fp);
487         if (error != 0) {
488                 if (error == EINVAL)
489                         return sys_read(td, (struct read_args *)uap);
490                 else
491                         return error;
492         }
493         if ((fp->f_flag & FREAD) == 0) {
494                 fdrop(fp, td);
495                 return (EBADF);
496         }
497         vp = fp->f_vnode;
498         if (vp->v_type != VDIR) {
499                 fdrop(fp, td);
500                 return sys_read(td, (struct read_args *)uap);
501         }
502
503         off = fp->f_offset;
504
505         DPRINTF(("ibcs2_read: read directory\n"));
506
507         buflen = max(DIRBLKSIZ, uap->nbytes);
508         buflen = min(buflen, MAXBSIZE);
509         buf = malloc(buflen, M_TEMP, M_WAITOK);
510         vn_lock(vp, LK_SHARED | LK_RETRY);
511 again:
512         aiov.iov_base = buf;
513         aiov.iov_len = buflen;
514         auio.uio_iov = &aiov;
515         auio.uio_iovcnt = 1;
516         auio.uio_rw = UIO_READ;
517         auio.uio_segflg = UIO_SYSSPACE;
518         auio.uio_td = td;
519         auio.uio_resid = buflen;
520         auio.uio_offset = off;
521
522         if (cookies) {
523                 free(cookies, M_TEMP);
524                 cookies = NULL;
525         }
526
527 #ifdef MAC
528         error = mac_vnode_check_readdir(td->td_ucred, vp);
529         if (error)
530                 goto out;
531 #endif
532
533         /*
534          * First we read into the malloc'ed buffer, then
535          * we massage it into user space, one record at a time.
536          */
537         if ((error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies, &cookies)) != 0) {
538                 DPRINTF(("VOP_READDIR failed: %d\n", error));
539                 goto out;
540         }
541         inp = buf;
542         outp = uap->buf;
543         resid = uap->nbytes;
544         if ((len = buflen - auio.uio_resid) <= 0)
545                 goto eof;
546
547         cookiep = cookies;
548
549         if (cookies) {
550                 /*
551                  * When using cookies, the vfs has the option of reading from
552                  * a different offset than that supplied (UFS truncates the
553                  * offset to a block boundary to make sure that it never reads
554                  * partway through a directory entry, even if the directory
555                  * has been compacted).
556                  */
557                 while (len > 0 && ncookies > 0 && *cookiep <= off) {
558                         len -= BSD_DIRENT(inp)->d_reclen;
559                         inp += BSD_DIRENT(inp)->d_reclen;
560                         cookiep++;
561                         ncookies--;
562                 }
563         }
564
565         for (; len > 0 && resid > 0; len -= reclen) {
566                 if (cookiep && ncookies == 0)
567                         break;
568                 reclen = BSD_DIRENT(inp)->d_reclen;
569                 if (reclen & 3) {
570                         printf("ibcs2_read: reclen=%d\n", reclen);
571                         error = EFAULT;
572                         goto out;
573                 }
574                 if (BSD_DIRENT(inp)->d_fileno == 0) {
575                         inp += reclen;  /* it is a hole; squish it out */
576                         if (cookiep) {
577                                 off = *cookiep++;
578                                 ncookies--;
579                         } else
580                                 off += reclen;
581                         continue;
582                 }
583                 if (reclen > len || resid < sizeof(struct ibcs2_direct)) {
584                         /* entry too big for buffer, so just stop */
585                         outp++;
586                         break;
587                 }
588                 /*
589                  * Massage in place to make an iBCS2-shaped dirent (otherwise
590                  * we have to worry about touching user memory outside of
591                  * the copyout() call).
592                  *
593                  * TODO: if length(filename) > 14, then break filename into
594                  * multiple entries and set inode = 0xffff except last
595                  */
596                 idb.ino = (BSD_DIRENT(inp)->d_fileno > 0xfffe) ? 0xfffe :
597                         BSD_DIRENT(inp)->d_fileno;
598                 (void)copystr(BSD_DIRENT(inp)->d_name, idb.name, 14, &size);
599                 bzero(idb.name + size, 14 - size);
600                 if ((error = copyout(&idb, outp, sizeof(struct ibcs2_direct))) != 0)
601                         goto out;
602                 /* advance past this real entry */
603                 if (cookiep) {
604                         off = *cookiep++;
605                         ncookies--;
606                 } else
607                         off += reclen;
608                 inp += reclen;
609                 /* advance output past iBCS2-shaped entry */
610                 outp += sizeof(struct ibcs2_direct);
611                 resid -= sizeof(struct ibcs2_direct);
612         }
613         /* if we squished out the whole block, try again */
614         if (outp == uap->buf)
615                 goto again;
616         fp->f_offset = off;             /* update the vnode offset */
617 eof:
618         td->td_retval[0] = uap->nbytes - resid;
619 out:
620         VOP_UNLOCK(vp, 0);
621         fdrop(fp, td);
622         if (cookies)
623                 free(cookies, M_TEMP);
624         free(buf, M_TEMP);
625         return (error);
626 }
627
628 int
629 ibcs2_mknod(struct thread *td, struct ibcs2_mknod_args *uap)
630 {
631         char *path;
632         int error;
633
634         CHECKALTCREAT(td, uap->path, &path);
635         if (S_ISFIFO(uap->mode)) {
636                 error = kern_mkfifoat(td, AT_FDCWD, path,
637                     UIO_SYSSPACE, uap->mode);
638         } else {
639                 error = kern_mknodat(td, AT_FDCWD, path, UIO_SYSSPACE,
640                     uap->mode, uap->dev);
641         }
642         free(path, M_TEMP);
643         return (error);
644 }
645
646 int
647 ibcs2_getgroups(struct thread *td, struct ibcs2_getgroups_args *uap)
648 {
649         struct ucred *cred;
650         ibcs2_gid_t *iset;
651         u_int i, ngrp;
652         int error;
653
654         cred = td->td_ucred;
655         ngrp = cred->cr_ngroups;
656
657         if (uap->gidsetsize == 0) {
658                 error = 0;
659                 goto out;
660         }
661         if (uap->gidsetsize < ngrp)
662                 return (EINVAL);
663
664         iset = malloc(ngrp * sizeof(*iset), M_TEMP, M_WAITOK);
665         for (i = 0; i < ngrp; i++)
666                 iset[i] = (ibcs2_gid_t)cred->cr_groups[i];
667         error = copyout(iset, uap->gidset, ngrp * sizeof(ibcs2_gid_t));
668         free(iset, M_TEMP);
669 out:
670         td->td_retval[0] = ngrp;
671         return (error);
672 }
673
674 int
675 ibcs2_setgroups(struct thread *td, struct ibcs2_setgroups_args *uap)
676 {
677         ibcs2_gid_t *iset;
678         gid_t *gp;
679         int error, i;
680
681         if (uap->gidsetsize < 0 || uap->gidsetsize > ngroups_max + 1)
682                 return (EINVAL);
683         if (uap->gidsetsize && uap->gidset == NULL)
684                 return (EINVAL);
685         gp = malloc(uap->gidsetsize * sizeof(*gp), M_TEMP, M_WAITOK);
686         if (uap->gidsetsize) {
687                 iset = malloc(uap->gidsetsize * sizeof(*iset), M_TEMP, M_WAITOK);
688                 error = copyin(uap->gidset, iset, sizeof(ibcs2_gid_t) *
689                     uap->gidsetsize);
690                 if (error) {
691                         free(iset, M_TEMP);
692                         goto out;
693                 }
694                 for (i = 0; i < uap->gidsetsize; i++)
695                         gp[i] = (gid_t)iset[i];
696         }
697
698         error = kern_setgroups(td, uap->gidsetsize, gp);
699 out:
700         free(gp, M_TEMP);
701         return (error);
702 }
703
704 int
705 ibcs2_setuid(struct thread *td, struct ibcs2_setuid_args *uap)
706 {
707         struct setuid_args sa;
708
709         sa.uid = (uid_t)uap->uid;
710         return sys_setuid(td, &sa);
711 }
712
713 int
714 ibcs2_setgid(struct thread *td, struct ibcs2_setgid_args *uap)
715 {
716         struct setgid_args sa;
717
718         sa.gid = (gid_t)uap->gid;
719         return sys_setgid(td, &sa);
720 }
721
722 int
723 ibcs2_time(struct thread *td, struct ibcs2_time_args *uap)
724 {
725         struct timeval tv;
726
727         microtime(&tv);
728         td->td_retval[0] = tv.tv_sec;
729         if (uap->tp)
730                 return copyout((caddr_t)&tv.tv_sec, (caddr_t)uap->tp,
731                                sizeof(ibcs2_time_t));
732         else
733                 return 0;
734 }
735
736 int
737 ibcs2_pathconf(struct thread *td, struct ibcs2_pathconf_args *uap)
738 {
739         char *path;
740         int error;
741
742         CHECKALTEXIST(td, uap->path, &path);
743         uap->name++;    /* iBCS2 _PC_* defines are offset by one */
744         error = kern_pathconf(td, path, UIO_SYSSPACE, uap->name, FOLLOW);
745         free(path, M_TEMP);
746         return (error);
747 }
748
749 int
750 ibcs2_fpathconf(struct thread *td, struct ibcs2_fpathconf_args *uap)
751 {
752         uap->name++;    /* iBCS2 _PC_* defines are offset by one */
753         return sys_fpathconf(td, (struct fpathconf_args *)uap);
754 }
755
756 int
757 ibcs2_sysconf(struct thread *td, struct ibcs2_sysconf_args *uap)
758 {
759         int mib[2], value, len, error;
760
761         switch(uap->name) {
762         case IBCS2_SC_ARG_MAX:
763                 mib[1] = KERN_ARGMAX;
764                 break;
765
766         case IBCS2_SC_CHILD_MAX:
767                 td->td_retval[0] = lim_cur(td, RLIMIT_NPROC);
768                 return 0;
769
770         case IBCS2_SC_CLK_TCK:
771                 td->td_retval[0] = hz;
772                 return 0;
773
774         case IBCS2_SC_NGROUPS_MAX:
775                 mib[1] = KERN_NGROUPS;
776                 break;
777
778         case IBCS2_SC_OPEN_MAX:
779                 td->td_retval[0] = lim_cur(td, RLIMIT_NOFILE);
780                 return 0;
781                 
782         case IBCS2_SC_JOB_CONTROL:
783                 mib[1] = KERN_JOB_CONTROL;
784                 break;
785                 
786         case IBCS2_SC_SAVED_IDS:
787                 mib[1] = KERN_SAVED_IDS;
788                 break;
789                 
790         case IBCS2_SC_VERSION:
791                 mib[1] = KERN_POSIX1;
792                 break;
793                 
794         case IBCS2_SC_PASS_MAX:
795                 td->td_retval[0] = 128;         /* XXX - should we create PASS_MAX ? */
796                 return 0;
797
798         case IBCS2_SC_XOPEN_VERSION:
799                 td->td_retval[0] = 2;           /* XXX: What should that be? */
800                 return 0;
801                 
802         default:
803                 return EINVAL;
804         }
805
806         mib[0] = CTL_KERN;
807         len = sizeof(value);
808         error = kernel_sysctl(td, mib, 2, &value, &len, NULL, 0, NULL, 0);
809         if (error)
810                 return error;
811         td->td_retval[0] = value;
812         return 0;
813 }
814
815 int
816 ibcs2_alarm(struct thread *td, struct ibcs2_alarm_args *uap)
817 {
818         struct itimerval itv, oitv;
819         int error;
820
821         timevalclear(&itv.it_interval);
822         itv.it_value.tv_sec = uap->sec;
823         itv.it_value.tv_usec = 0;
824         error = kern_setitimer(td, ITIMER_REAL, &itv, &oitv);
825         if (error)
826                 return (error);
827         if (oitv.it_value.tv_usec != 0)
828                 oitv.it_value.tv_sec++;
829         td->td_retval[0] = oitv.it_value.tv_sec;
830         return (0);
831 }
832
833 int
834 ibcs2_times(struct thread *td, struct ibcs2_times_args *uap)
835 {
836         struct rusage ru;
837         struct timeval t;
838         struct tms tms;
839         int error;
840
841 #define CONVTCK(r)      (r.tv_sec * hz + r.tv_usec / (1000000 / hz))
842
843         error = kern_getrusage(td, RUSAGE_SELF, &ru);
844         if (error)
845                 return (error);
846         tms.tms_utime = CONVTCK(ru.ru_utime);
847         tms.tms_stime = CONVTCK(ru.ru_stime);
848
849         error = kern_getrusage(td, RUSAGE_CHILDREN, &ru);
850         if (error)
851                 return (error);
852         tms.tms_cutime = CONVTCK(ru.ru_utime);
853         tms.tms_cstime = CONVTCK(ru.ru_stime);
854
855         microtime(&t);
856         td->td_retval[0] = CONVTCK(t);
857         
858         return (copyout(&tms, uap->tp, sizeof(struct tms)));
859 }
860
861 int
862 ibcs2_stime(struct thread *td, struct ibcs2_stime_args *uap)
863 {
864         struct timeval tv;
865         long secs;
866         int error;
867
868         error = copyin(uap->timep, &secs, sizeof(long));
869         if (error)
870                 return (error);
871         tv.tv_sec = secs;
872         tv.tv_usec = 0;
873         error = kern_settimeofday(td, &tv, NULL);
874         if (error)
875                 error = EPERM;
876         return (error);
877 }
878
879 int
880 ibcs2_utime(struct thread *td, struct ibcs2_utime_args *uap)
881 {
882         struct ibcs2_utimbuf ubuf;
883         struct timeval tbuf[2], *tp;
884         char *path;
885         int error;
886
887         if (uap->buf) {
888                 error = copyin(uap->buf, &ubuf, sizeof(ubuf));
889                 if (error)
890                         return (error);
891                 tbuf[0].tv_sec = ubuf.actime;
892                 tbuf[0].tv_usec = 0;
893                 tbuf[1].tv_sec = ubuf.modtime;
894                 tbuf[1].tv_usec = 0;
895                 tp = tbuf;
896         } else
897                 tp = NULL;
898
899         CHECKALTEXIST(td, uap->path, &path);
900         error = kern_utimesat(td, AT_FDCWD, path, UIO_SYSSPACE,
901             tp, UIO_SYSSPACE);
902         free(path, M_TEMP);
903         return (error);
904 }
905
906 int
907 ibcs2_nice(struct thread *td, struct ibcs2_nice_args *uap)
908 {
909         int error;
910         struct setpriority_args sa;
911
912         sa.which = PRIO_PROCESS;
913         sa.who = 0;
914         sa.prio = td->td_proc->p_nice + uap->incr;
915         if ((error = sys_setpriority(td, &sa)) != 0)
916                 return EPERM;
917         td->td_retval[0] = td->td_proc->p_nice;
918         return 0;
919 }
920
921 /*
922  * iBCS2 getpgrp, setpgrp, setsid, and setpgid
923  */
924
925 int
926 ibcs2_pgrpsys(struct thread *td, struct ibcs2_pgrpsys_args *uap)
927 {
928         struct proc *p = td->td_proc;
929         switch (uap->type) {
930         case 0:                 /* getpgrp */
931                 PROC_LOCK(p);
932                 td->td_retval[0] = p->p_pgrp->pg_id;
933                 PROC_UNLOCK(p);
934                 return 0;
935
936         case 1:                 /* setpgrp */
937             {
938                 struct setpgid_args sa;
939
940                 sa.pid = 0;
941                 sa.pgid = 0;
942                 sys_setpgid(td, &sa);
943                 PROC_LOCK(p);
944                 td->td_retval[0] = p->p_pgrp->pg_id;
945                 PROC_UNLOCK(p);
946                 return 0;
947             }
948
949         case 2:                 /* setpgid */
950             {
951                 struct setpgid_args sa;
952
953                 sa.pid = uap->pid;
954                 sa.pgid = uap->pgid;
955                 return sys_setpgid(td, &sa);
956             }
957
958         case 3:                 /* setsid */
959                 return sys_setsid(td, NULL);
960
961         default:
962                 return EINVAL;
963         }
964 }
965
966 /*
967  * XXX - need to check for nested calls
968  */
969
970 int
971 ibcs2_plock(struct thread *td, struct ibcs2_plock_args *uap)
972 {
973         int error;
974 #define IBCS2_UNLOCK    0
975 #define IBCS2_PROCLOCK  1
976 #define IBCS2_TEXTLOCK  2
977 #define IBCS2_DATALOCK  4
978
979         
980         switch(uap->cmd) {
981         case IBCS2_UNLOCK:
982                 error = priv_check(td, PRIV_VM_MUNLOCK);
983                 if (error)
984                         return (error);
985                 /* XXX - TODO */
986                 return (0);
987
988         case IBCS2_PROCLOCK:
989         case IBCS2_TEXTLOCK:
990         case IBCS2_DATALOCK:
991                 error = priv_check(td, PRIV_VM_MLOCK);
992                 if (error)
993                         return (error);
994                 /* XXX - TODO */
995                 return 0;
996         }
997         return EINVAL;
998 }
999
1000 int
1001 ibcs2_uadmin(struct thread *td, struct ibcs2_uadmin_args *uap)
1002 {
1003 #define SCO_A_REBOOT        1
1004 #define SCO_A_SHUTDOWN      2
1005 #define SCO_A_REMOUNT       4
1006 #define SCO_A_CLOCK         8
1007 #define SCO_A_SETCONFIG     128
1008 #define SCO_A_GETDEV        130
1009
1010 #define SCO_AD_HALT         0
1011 #define SCO_AD_BOOT         1
1012 #define SCO_AD_IBOOT        2
1013 #define SCO_AD_PWRDOWN      3
1014 #define SCO_AD_PWRNAP       4
1015
1016 #define SCO_AD_PANICBOOT    1
1017
1018 #define SCO_AD_GETBMAJ      0
1019 #define SCO_AD_GETCMAJ      1
1020
1021         switch(uap->cmd) {
1022         case SCO_A_REBOOT:
1023         case SCO_A_SHUTDOWN:
1024                 switch(uap->func) {
1025                         struct reboot_args r;
1026                 case SCO_AD_HALT:
1027                 case SCO_AD_PWRDOWN:
1028                 case SCO_AD_PWRNAP:
1029                         r.opt = RB_HALT;
1030                         return (sys_reboot(td, &r));
1031                 case SCO_AD_BOOT:
1032                 case SCO_AD_IBOOT:
1033                         r.opt = RB_AUTOBOOT;
1034                         return (sys_reboot(td, &r));
1035                 }
1036                 return EINVAL;
1037         case SCO_A_REMOUNT:
1038         case SCO_A_CLOCK:
1039         case SCO_A_SETCONFIG:
1040                 return 0;
1041         case SCO_A_GETDEV:
1042                 return EINVAL;  /* XXX - TODO */
1043         }
1044         return EINVAL;
1045 }
1046
1047 int
1048 ibcs2_sysfs(struct thread *td, struct ibcs2_sysfs_args *uap)
1049 {
1050 #define IBCS2_GETFSIND        1
1051 #define IBCS2_GETFSTYP        2
1052 #define IBCS2_GETNFSTYP       3
1053
1054         switch(uap->cmd) {
1055         case IBCS2_GETFSIND:
1056         case IBCS2_GETFSTYP:
1057         case IBCS2_GETNFSTYP:
1058                 break;
1059         }
1060         return EINVAL;          /* XXX - TODO */
1061 }
1062
1063 int
1064 ibcs2_unlink(struct thread *td, struct ibcs2_unlink_args *uap)
1065 {
1066         char *path;
1067         int error;
1068
1069         CHECKALTEXIST(td, uap->path, &path);
1070         error = kern_unlinkat(td, AT_FDCWD, path, UIO_SYSSPACE, 0);
1071         free(path, M_TEMP);
1072         return (error);
1073 }
1074
1075 int
1076 ibcs2_chdir(struct thread *td, struct ibcs2_chdir_args *uap)
1077 {
1078         char *path;
1079         int error;
1080
1081         CHECKALTEXIST(td, uap->path, &path);
1082         error = kern_chdir(td, path, UIO_SYSSPACE);
1083         free(path, M_TEMP);
1084         return (error);
1085 }
1086
1087 int
1088 ibcs2_chmod(struct thread *td, struct ibcs2_chmod_args *uap)
1089 {
1090         char *path;
1091         int error;
1092
1093         CHECKALTEXIST(td, uap->path, &path);
1094         error = kern_fchmodat(td, AT_FDCWD, path, UIO_SYSSPACE, uap->mode, 0);
1095         free(path, M_TEMP);
1096         return (error);
1097 }
1098
1099 int
1100 ibcs2_chown(struct thread *td, struct ibcs2_chown_args *uap)
1101 {
1102         char *path;
1103         int error;
1104
1105         CHECKALTEXIST(td, uap->path, &path);
1106         error = kern_fchownat(td, AT_FDCWD, path, UIO_SYSSPACE, uap->uid,
1107             uap->gid, 0);
1108         free(path, M_TEMP);
1109         return (error);
1110 }
1111
1112 int
1113 ibcs2_rmdir(struct thread *td, struct ibcs2_rmdir_args *uap)
1114 {
1115         char *path;
1116         int error;
1117
1118         CHECKALTEXIST(td, uap->path, &path);
1119         error = kern_rmdirat(td, AT_FDCWD, path, UIO_SYSSPACE);
1120         free(path, M_TEMP);
1121         return (error);
1122 }
1123
1124 int
1125 ibcs2_mkdir(struct thread *td, struct ibcs2_mkdir_args *uap)
1126 {
1127         char *path;
1128         int error;
1129
1130         CHECKALTEXIST(td, uap->path, &path);
1131         error = kern_mkdirat(td, AT_FDCWD, path, UIO_SYSSPACE, uap->mode);
1132         free(path, M_TEMP);
1133         return (error);
1134 }
1135
1136 int
1137 ibcs2_symlink(struct thread *td, struct ibcs2_symlink_args *uap)
1138 {
1139         char *path, *link;
1140         int error;
1141
1142         CHECKALTEXIST(td, uap->path, &path);
1143
1144         /*
1145          * Have to expand CHECKALTCREAT() so that 'path' can be freed on
1146          * errors.
1147          */
1148         error = ibcs2_emul_find(td, uap->link, UIO_USERSPACE, &link, 1);
1149         if (link == NULL) {
1150                 free(path, M_TEMP);
1151                 return (error);
1152         }
1153         error = kern_symlinkat(td, path, AT_FDCWD, link, UIO_SYSSPACE);
1154         free(path, M_TEMP);
1155         free(link, M_TEMP);
1156         return (error);
1157 }
1158
1159 int
1160 ibcs2_rename(struct thread *td, struct ibcs2_rename_args *uap)
1161 {
1162         char *from, *to;
1163         int error;
1164
1165         CHECKALTEXIST(td, uap->from, &from);
1166
1167         /*
1168          * Have to expand CHECKALTCREAT() so that 'from' can be freed on
1169          * errors.
1170          */
1171         error = ibcs2_emul_find(td, uap->to, UIO_USERSPACE, &to, 1);
1172         if (to == NULL) {
1173                 free(from, M_TEMP);
1174                 return (error);
1175         }
1176         error = kern_renameat(td, AT_FDCWD, from, AT_FDCWD, to, UIO_SYSSPACE);
1177         free(from, M_TEMP);
1178         free(to, M_TEMP);
1179         return (error);
1180 }
1181
1182 int
1183 ibcs2_readlink(struct thread *td, struct ibcs2_readlink_args *uap)
1184 {
1185         char *path;
1186         int error;
1187
1188         CHECKALTEXIST(td, uap->path, &path);
1189         error = kern_readlinkat(td, AT_FDCWD, path, UIO_SYSSPACE,
1190             uap->buf, UIO_USERSPACE, uap->count);
1191         free(path, M_TEMP);
1192         return (error);
1193 }