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