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