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