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