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