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