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