]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/i386/ibcs2/ibcs2_misc.c
MFV r316918: 7990 libzfs: snapspec_cb() does not need to call zfs_strdup()
[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         error = getvnode(td, uap->fd, cap_rights_init(&rights, CAP_READ), &fp);
334         if (error != 0)
335                 return (error);
336         if ((fp->f_flag & FREAD) == 0) {
337                 fdrop(fp, td);
338                 return (EBADF);
339         }
340         vp = fp->f_vnode;
341         if (vp->v_type != VDIR) {       /* XXX  vnode readdir op should do this */
342                 fdrop(fp, td);
343                 return (EINVAL);
344         }
345
346         off = fp->f_offset;
347 #define DIRBLKSIZ       512             /* XXX we used to use ufs's DIRBLKSIZ */
348         buflen = max(DIRBLKSIZ, uap->nbytes);
349         buflen = min(buflen, MAXBSIZE);
350         buf = malloc(buflen, M_TEMP, M_WAITOK);
351         vn_lock(vp, LK_SHARED | LK_RETRY);
352 again:
353         aiov.iov_base = buf;
354         aiov.iov_len = buflen;
355         auio.uio_iov = &aiov;
356         auio.uio_iovcnt = 1;
357         auio.uio_rw = UIO_READ;
358         auio.uio_segflg = UIO_SYSSPACE;
359         auio.uio_td = td;
360         auio.uio_resid = buflen;
361         auio.uio_offset = off;
362
363         if (cookies) {
364                 free(cookies, M_TEMP);
365                 cookies = NULL;
366         }
367
368 #ifdef MAC
369         error = mac_vnode_check_readdir(td->td_ucred, vp);
370         if (error)
371                 goto out;
372 #endif
373
374         /*
375          * First we read into the malloc'ed buffer, then
376          * we massage it into user space, one record at a time.
377          */
378         if ((error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies, &cookies)) != 0)
379                 goto out;
380         inp = buf;
381         outp = uap->buf;
382         resid = uap->nbytes;
383         if ((len = buflen - auio.uio_resid) <= 0)
384                 goto eof;
385
386         cookiep = cookies;
387
388         if (cookies) {
389                 /*
390                  * When using cookies, the vfs has the option of reading from
391                  * a different offset than that supplied (UFS truncates the
392                  * offset to a block boundary to make sure that it never reads
393                  * partway through a directory entry, even if the directory
394                  * has been compacted).
395                  */
396                 while (len > 0 && ncookies > 0 && *cookiep <= off) {
397                         len -= BSD_DIRENT(inp)->d_reclen;
398                         inp += BSD_DIRENT(inp)->d_reclen;
399                         cookiep++;
400                         ncookies--;
401                 }
402         }
403
404         for (; len > 0; len -= reclen) {
405                 if (cookiep && ncookies == 0)
406                         break;
407                 reclen = BSD_DIRENT(inp)->d_reclen;
408                 if (reclen & 3) {
409                         printf("ibcs2_getdents: reclen=%d\n", reclen);
410                         error = EFAULT;
411                         goto out;
412                 }
413                 if (BSD_DIRENT(inp)->d_fileno == 0) {
414                         inp += reclen;  /* it is a hole; squish it out */
415                         if (cookiep) {
416                                 off = *cookiep++;
417                                 ncookies--;
418                         } else
419                                 off += reclen;
420                         continue;
421                 }
422                 if (reclen > len || resid < IBCS2_RECLEN(reclen)) {
423                         /* entry too big for buffer, so just stop */
424                         outp++;
425                         break;
426                 }
427                 /*
428                  * Massage in place to make an iBCS2-shaped dirent (otherwise
429                  * we have to worry about touching user memory outside of
430                  * the copyout() call).
431                  */
432                 idb.d_ino = (ibcs2_ino_t)BSD_DIRENT(inp)->d_fileno;
433                 idb.d_off = (ibcs2_off_t)off;
434                 idb.d_reclen = (u_short)IBCS2_RECLEN(reclen);
435                 if ((error = copyout((caddr_t)&idb, outp, 10)) != 0 ||
436                     (error = copyout(BSD_DIRENT(inp)->d_name, outp + 10,
437                                      BSD_DIRENT(inp)->d_namlen + 1)) != 0)
438                         goto out;
439                 /* advance past this real entry */
440                 if (cookiep) {
441                         off = *cookiep++;
442                         ncookies--;
443                 } else
444                         off += reclen;
445                 inp += reclen;
446                 /* advance output past iBCS2-shaped entry */
447                 outp += IBCS2_RECLEN(reclen);
448                 resid -= IBCS2_RECLEN(reclen);
449         }
450         /* if we squished out the whole block, try again */
451         if (outp == uap->buf)
452                 goto again;
453         fp->f_offset = off;             /* update the vnode offset */
454 eof:
455         td->td_retval[0] = uap->nbytes - resid;
456 out:
457         VOP_UNLOCK(vp, 0);
458         fdrop(fp, td);
459         if (cookies)
460                 free(cookies, M_TEMP);
461         free(buf, M_TEMP);
462         return (error);
463 }
464
465 int
466 ibcs2_read(struct thread *td, struct ibcs2_read_args *uap)
467 {
468         struct vnode *vp;
469         caddr_t inp, buf;               /* BSD-format */
470         int len, reclen;                /* BSD-format */
471         caddr_t outp;                   /* iBCS2-format */
472         int resid;                      /* iBCS2-format */
473         cap_rights_t rights;
474         struct file *fp;
475         struct uio auio;
476         struct iovec aiov;
477         struct ibcs2_direct {
478                 ibcs2_ino_t ino;
479                 char name[14];
480         } idb;
481         off_t off;                      /* true file offset */
482         int buflen, error, eofflag, size;
483         u_long *cookies = NULL, *cookiep;
484         int ncookies;
485
486         error = getvnode(td, uap->fd, cap_rights_init(&rights, CAP_READ), &fp);
487         if (error != 0) {
488                 if (error == EINVAL)
489                         return sys_read(td, (struct read_args *)uap);
490                 else
491                         return error;
492         }
493         if ((fp->f_flag & FREAD) == 0) {
494                 fdrop(fp, td);
495                 return (EBADF);
496         }
497         vp = fp->f_vnode;
498         if (vp->v_type != VDIR) {
499                 fdrop(fp, td);
500                 return sys_read(td, (struct read_args *)uap);
501         }
502
503         off = fp->f_offset;
504
505         DPRINTF(("ibcs2_read: read directory\n"));
506
507         buflen = max(DIRBLKSIZ, uap->nbytes);
508         buflen = min(buflen, MAXBSIZE);
509         buf = malloc(buflen, M_TEMP, M_WAITOK);
510         vn_lock(vp, LK_SHARED | LK_RETRY);
511 again:
512         aiov.iov_base = buf;
513         aiov.iov_len = buflen;
514         auio.uio_iov = &aiov;
515         auio.uio_iovcnt = 1;
516         auio.uio_rw = UIO_READ;
517         auio.uio_segflg = UIO_SYSSPACE;
518         auio.uio_td = td;
519         auio.uio_resid = buflen;
520         auio.uio_offset = off;
521
522         if (cookies) {
523                 free(cookies, M_TEMP);
524                 cookies = NULL;
525         }
526
527 #ifdef MAC
528         error = mac_vnode_check_readdir(td->td_ucred, vp);
529         if (error)
530                 goto out;
531 #endif
532
533         /*
534          * First we read into the malloc'ed buffer, then
535          * we massage it into user space, one record at a time.
536          */
537         if ((error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies, &cookies)) != 0) {
538                 DPRINTF(("VOP_READDIR failed: %d\n", error));
539                 goto out;
540         }
541         inp = buf;
542         outp = uap->buf;
543         resid = uap->nbytes;
544         if ((len = buflen - auio.uio_resid) <= 0)
545                 goto eof;
546
547         cookiep = cookies;
548
549         if (cookies) {
550                 /*
551                  * When using cookies, the vfs has the option of reading from
552                  * a different offset than that supplied (UFS truncates the
553                  * offset to a block boundary to make sure that it never reads
554                  * partway through a directory entry, even if the directory
555                  * has been compacted).
556                  */
557                 while (len > 0 && ncookies > 0 && *cookiep <= off) {
558                         len -= BSD_DIRENT(inp)->d_reclen;
559                         inp += BSD_DIRENT(inp)->d_reclen;
560                         cookiep++;
561                         ncookies--;
562                 }
563         }
564
565         for (; len > 0 && resid > 0; len -= reclen) {
566                 if (cookiep && ncookies == 0)
567                         break;
568                 reclen = BSD_DIRENT(inp)->d_reclen;
569                 if (reclen & 3) {
570                         printf("ibcs2_read: reclen=%d\n", reclen);
571                         error = EFAULT;
572                         goto out;
573                 }
574                 if (BSD_DIRENT(inp)->d_fileno == 0) {
575                         inp += reclen;  /* it is a hole; squish it out */
576                         if (cookiep) {
577                                 off = *cookiep++;
578                                 ncookies--;
579                         } else
580                                 off += reclen;
581                         continue;
582                 }
583                 if (reclen > len || resid < sizeof(struct ibcs2_direct)) {
584                         /* entry too big for buffer, so just stop */
585                         outp++;
586                         break;
587                 }
588                 /*
589                  * Massage in place to make an iBCS2-shaped dirent (otherwise
590                  * we have to worry about touching user memory outside of
591                  * the copyout() call).
592                  *
593                  * TODO: if length(filename) > 14, then break filename into
594                  * multiple entries and set inode = 0xffff except last
595                  */
596                 idb.ino = (BSD_DIRENT(inp)->d_fileno > 0xfffe) ? 0xfffe :
597                         BSD_DIRENT(inp)->d_fileno;
598                 (void)copystr(BSD_DIRENT(inp)->d_name, idb.name, 14, &size);
599                 bzero(idb.name + size, 14 - size);
600                 if ((error = copyout(&idb, outp, sizeof(struct ibcs2_direct))) != 0)
601                         goto out;
602                 /* advance past this real entry */
603                 if (cookiep) {
604                         off = *cookiep++;
605                         ncookies--;
606                 } else
607                         off += reclen;
608                 inp += reclen;
609                 /* advance output past iBCS2-shaped entry */
610                 outp += sizeof(struct ibcs2_direct);
611                 resid -= sizeof(struct ibcs2_direct);
612         }
613         /* if we squished out the whole block, try again */
614         if (outp == uap->buf)
615                 goto again;
616         fp->f_offset = off;             /* update the vnode offset */
617 eof:
618         td->td_retval[0] = uap->nbytes - resid;
619 out:
620         VOP_UNLOCK(vp, 0);
621         fdrop(fp, td);
622         if (cookies)
623                 free(cookies, M_TEMP);
624         free(buf, M_TEMP);
625         return (error);
626 }
627
628 int
629 ibcs2_mknod(struct thread *td, struct ibcs2_mknod_args *uap)
630 {
631         char *path;
632         int error;
633
634         CHECKALTCREAT(td, uap->path, &path);
635         if (S_ISFIFO(uap->mode)) {
636                 error = kern_mkfifoat(td, AT_FDCWD, path,
637                     UIO_SYSSPACE, uap->mode);
638         } else {
639                 error = kern_mknodat(td, AT_FDCWD, path, UIO_SYSSPACE,
640                     uap->mode, uap->dev);
641         }
642         free(path, M_TEMP);
643         return (error);
644 }
645
646 int
647 ibcs2_getgroups(struct thread *td, struct ibcs2_getgroups_args *uap)
648 {
649         struct ucred *cred;
650         ibcs2_gid_t *iset;
651         u_int i, ngrp;
652         int error;
653
654         cred = td->td_ucred;
655         ngrp = cred->cr_ngroups;
656
657         if (uap->gidsetsize == 0) {
658                 error = 0;
659                 goto out;
660         }
661         if (uap->gidsetsize < ngrp)
662                 return (EINVAL);
663
664         iset = malloc(ngrp * sizeof(*iset), M_TEMP, M_WAITOK);
665         for (i = 0; i < ngrp; i++)
666                 iset[i] = (ibcs2_gid_t)cred->cr_groups[i];
667         error = copyout(iset, uap->gidset, ngrp * sizeof(ibcs2_gid_t));
668         free(iset, M_TEMP);
669 out:
670         td->td_retval[0] = ngrp;
671         return (error);
672 }
673
674 int
675 ibcs2_setgroups(struct thread *td, struct ibcs2_setgroups_args *uap)
676 {
677         ibcs2_gid_t *iset;
678         gid_t *gp;
679         int error, i;
680
681         if (uap->gidsetsize < 0 || uap->gidsetsize > ngroups_max + 1)
682                 return (EINVAL);
683         if (uap->gidsetsize && uap->gidset == NULL)
684                 return (EINVAL);
685         gp = malloc(uap->gidsetsize * sizeof(*gp), M_TEMP, M_WAITOK);
686         if (uap->gidsetsize) {
687                 iset = malloc(uap->gidsetsize * sizeof(*iset), M_TEMP, M_WAITOK);
688                 error = copyin(uap->gidset, iset, sizeof(ibcs2_gid_t) *
689                     uap->gidsetsize);
690                 if (error) {
691                         free(iset, M_TEMP);
692                         goto out;
693                 }
694                 for (i = 0; i < uap->gidsetsize; i++)
695                         gp[i] = (gid_t)iset[i];
696         }
697
698         error = kern_setgroups(td, uap->gidsetsize, gp);
699 out:
700         free(gp, M_TEMP);
701         return (error);
702 }
703
704 int
705 ibcs2_setuid(struct thread *td, struct ibcs2_setuid_args *uap)
706 {
707         struct setuid_args sa;
708
709         sa.uid = (uid_t)uap->uid;
710         return sys_setuid(td, &sa);
711 }
712
713 int
714 ibcs2_setgid(struct thread *td, struct ibcs2_setgid_args *uap)
715 {
716         struct setgid_args sa;
717
718         sa.gid = (gid_t)uap->gid;
719         return sys_setgid(td, &sa);
720 }
721
722 int
723 ibcs2_time(struct thread *td, struct ibcs2_time_args *uap)
724 {
725         struct timeval tv;
726
727         microtime(&tv);
728         td->td_retval[0] = tv.tv_sec;
729         if (uap->tp)
730                 return copyout((caddr_t)&tv.tv_sec, (caddr_t)uap->tp,
731                                sizeof(ibcs2_time_t));
732         else
733                 return 0;
734 }
735
736 int
737 ibcs2_pathconf(struct thread *td, struct ibcs2_pathconf_args *uap)
738 {
739         char *path;
740         long value;
741         int error;
742
743         CHECKALTEXIST(td, uap->path, &path);
744         uap->name++;    /* iBCS2 _PC_* defines are offset by one */
745         error = kern_pathconf(td, path, UIO_SYSSPACE, uap->name, FOLLOW,
746             &value);
747         free(path, M_TEMP);
748         if (error == 0)
749                 td->td_retval[0] = value;
750         return (error);
751 }
752
753 int
754 ibcs2_fpathconf(struct thread *td, struct ibcs2_fpathconf_args *uap)
755 {
756         uap->name++;    /* iBCS2 _PC_* defines are offset by one */
757         return sys_fpathconf(td, (struct fpathconf_args *)uap);
758 }
759
760 int
761 ibcs2_sysconf(struct thread *td, struct ibcs2_sysconf_args *uap)
762 {
763         int mib[2], value, len, error;
764
765         switch(uap->name) {
766         case IBCS2_SC_ARG_MAX:
767                 mib[1] = KERN_ARGMAX;
768                 break;
769
770         case IBCS2_SC_CHILD_MAX:
771                 td->td_retval[0] = lim_cur(td, RLIMIT_NPROC);
772                 return 0;
773
774         case IBCS2_SC_CLK_TCK:
775                 td->td_retval[0] = hz;
776                 return 0;
777
778         case IBCS2_SC_NGROUPS_MAX:
779                 mib[1] = KERN_NGROUPS;
780                 break;
781
782         case IBCS2_SC_OPEN_MAX:
783                 td->td_retval[0] = lim_cur(td, RLIMIT_NOFILE);
784                 return 0;
785                 
786         case IBCS2_SC_JOB_CONTROL:
787                 mib[1] = KERN_JOB_CONTROL;
788                 break;
789                 
790         case IBCS2_SC_SAVED_IDS:
791                 mib[1] = KERN_SAVED_IDS;
792                 break;
793                 
794         case IBCS2_SC_VERSION:
795                 mib[1] = KERN_POSIX1;
796                 break;
797                 
798         case IBCS2_SC_PASS_MAX:
799                 td->td_retval[0] = 128;         /* XXX - should we create PASS_MAX ? */
800                 return 0;
801
802         case IBCS2_SC_XOPEN_VERSION:
803                 td->td_retval[0] = 2;           /* XXX: What should that be? */
804                 return 0;
805                 
806         default:
807                 return EINVAL;
808         }
809
810         mib[0] = CTL_KERN;
811         len = sizeof(value);
812         error = kernel_sysctl(td, mib, 2, &value, &len, NULL, 0, NULL, 0);
813         if (error)
814                 return error;
815         td->td_retval[0] = value;
816         return 0;
817 }
818
819 int
820 ibcs2_alarm(struct thread *td, struct ibcs2_alarm_args *uap)
821 {
822         struct itimerval itv, oitv;
823         int error;
824
825         timevalclear(&itv.it_interval);
826         itv.it_value.tv_sec = uap->sec;
827         itv.it_value.tv_usec = 0;
828         error = kern_setitimer(td, ITIMER_REAL, &itv, &oitv);
829         if (error)
830                 return (error);
831         if (oitv.it_value.tv_usec != 0)
832                 oitv.it_value.tv_sec++;
833         td->td_retval[0] = oitv.it_value.tv_sec;
834         return (0);
835 }
836
837 int
838 ibcs2_times(struct thread *td, struct ibcs2_times_args *uap)
839 {
840         struct rusage ru;
841         struct timeval t;
842         struct tms tms;
843         int error;
844
845 #define CONVTCK(r)      (r.tv_sec * hz + r.tv_usec / (1000000 / hz))
846
847         error = kern_getrusage(td, RUSAGE_SELF, &ru);
848         if (error)
849                 return (error);
850         tms.tms_utime = CONVTCK(ru.ru_utime);
851         tms.tms_stime = CONVTCK(ru.ru_stime);
852
853         error = kern_getrusage(td, RUSAGE_CHILDREN, &ru);
854         if (error)
855                 return (error);
856         tms.tms_cutime = CONVTCK(ru.ru_utime);
857         tms.tms_cstime = CONVTCK(ru.ru_stime);
858
859         microtime(&t);
860         td->td_retval[0] = CONVTCK(t);
861         
862         return (copyout(&tms, uap->tp, sizeof(struct tms)));
863 }
864
865 int
866 ibcs2_stime(struct thread *td, struct ibcs2_stime_args *uap)
867 {
868         struct timeval tv;
869         long secs;
870         int error;
871
872         error = copyin(uap->timep, &secs, sizeof(long));
873         if (error)
874                 return (error);
875         tv.tv_sec = secs;
876         tv.tv_usec = 0;
877         error = kern_settimeofday(td, &tv, NULL);
878         if (error)
879                 error = EPERM;
880         return (error);
881 }
882
883 int
884 ibcs2_utime(struct thread *td, struct ibcs2_utime_args *uap)
885 {
886         struct ibcs2_utimbuf ubuf;
887         struct timeval tbuf[2], *tp;
888         char *path;
889         int error;
890
891         if (uap->buf) {
892                 error = copyin(uap->buf, &ubuf, sizeof(ubuf));
893                 if (error)
894                         return (error);
895                 tbuf[0].tv_sec = ubuf.actime;
896                 tbuf[0].tv_usec = 0;
897                 tbuf[1].tv_sec = ubuf.modtime;
898                 tbuf[1].tv_usec = 0;
899                 tp = tbuf;
900         } else
901                 tp = NULL;
902
903         CHECKALTEXIST(td, uap->path, &path);
904         error = kern_utimesat(td, AT_FDCWD, path, UIO_SYSSPACE,
905             tp, UIO_SYSSPACE);
906         free(path, M_TEMP);
907         return (error);
908 }
909
910 int
911 ibcs2_nice(struct thread *td, struct ibcs2_nice_args *uap)
912 {
913         int error;
914         struct setpriority_args sa;
915
916         sa.which = PRIO_PROCESS;
917         sa.who = 0;
918         sa.prio = td->td_proc->p_nice + uap->incr;
919         if ((error = sys_setpriority(td, &sa)) != 0)
920                 return EPERM;
921         td->td_retval[0] = td->td_proc->p_nice;
922         return 0;
923 }
924
925 /*
926  * iBCS2 getpgrp, setpgrp, setsid, and setpgid
927  */
928
929 int
930 ibcs2_pgrpsys(struct thread *td, struct ibcs2_pgrpsys_args *uap)
931 {
932         struct proc *p = td->td_proc;
933         switch (uap->type) {
934         case 0:                 /* getpgrp */
935                 PROC_LOCK(p);
936                 td->td_retval[0] = p->p_pgrp->pg_id;
937                 PROC_UNLOCK(p);
938                 return 0;
939
940         case 1:                 /* setpgrp */
941             {
942                 struct setpgid_args sa;
943
944                 sa.pid = 0;
945                 sa.pgid = 0;
946                 sys_setpgid(td, &sa);
947                 PROC_LOCK(p);
948                 td->td_retval[0] = p->p_pgrp->pg_id;
949                 PROC_UNLOCK(p);
950                 return 0;
951             }
952
953         case 2:                 /* setpgid */
954             {
955                 struct setpgid_args sa;
956
957                 sa.pid = uap->pid;
958                 sa.pgid = uap->pgid;
959                 return sys_setpgid(td, &sa);
960             }
961
962         case 3:                 /* setsid */
963                 return sys_setsid(td, NULL);
964
965         default:
966                 return EINVAL;
967         }
968 }
969
970 /*
971  * XXX - need to check for nested calls
972  */
973
974 int
975 ibcs2_plock(struct thread *td, struct ibcs2_plock_args *uap)
976 {
977         int error;
978 #define IBCS2_UNLOCK    0
979 #define IBCS2_PROCLOCK  1
980 #define IBCS2_TEXTLOCK  2
981 #define IBCS2_DATALOCK  4
982
983         
984         switch(uap->cmd) {
985         case IBCS2_UNLOCK:
986                 error = priv_check(td, PRIV_VM_MUNLOCK);
987                 if (error)
988                         return (error);
989                 /* XXX - TODO */
990                 return (0);
991
992         case IBCS2_PROCLOCK:
993         case IBCS2_TEXTLOCK:
994         case IBCS2_DATALOCK:
995                 error = priv_check(td, PRIV_VM_MLOCK);
996                 if (error)
997                         return (error);
998                 /* XXX - TODO */
999                 return 0;
1000         }
1001         return EINVAL;
1002 }
1003
1004 int
1005 ibcs2_uadmin(struct thread *td, struct ibcs2_uadmin_args *uap)
1006 {
1007 #define SCO_A_REBOOT        1
1008 #define SCO_A_SHUTDOWN      2
1009 #define SCO_A_REMOUNT       4
1010 #define SCO_A_CLOCK         8
1011 #define SCO_A_SETCONFIG     128
1012 #define SCO_A_GETDEV        130
1013
1014 #define SCO_AD_HALT         0
1015 #define SCO_AD_BOOT         1
1016 #define SCO_AD_IBOOT        2
1017 #define SCO_AD_PWRDOWN      3
1018 #define SCO_AD_PWRNAP       4
1019
1020 #define SCO_AD_PANICBOOT    1
1021
1022 #define SCO_AD_GETBMAJ      0
1023 #define SCO_AD_GETCMAJ      1
1024
1025         switch(uap->cmd) {
1026         case SCO_A_REBOOT:
1027         case SCO_A_SHUTDOWN:
1028                 switch(uap->func) {
1029                         struct reboot_args r;
1030                 case SCO_AD_HALT:
1031                 case SCO_AD_PWRDOWN:
1032                 case SCO_AD_PWRNAP:
1033                         r.opt = RB_HALT;
1034                         return (sys_reboot(td, &r));
1035                 case SCO_AD_BOOT:
1036                 case SCO_AD_IBOOT:
1037                         r.opt = RB_AUTOBOOT;
1038                         return (sys_reboot(td, &r));
1039                 }
1040                 return EINVAL;
1041         case SCO_A_REMOUNT:
1042         case SCO_A_CLOCK:
1043         case SCO_A_SETCONFIG:
1044                 return 0;
1045         case SCO_A_GETDEV:
1046                 return EINVAL;  /* XXX - TODO */
1047         }
1048         return EINVAL;
1049 }
1050
1051 int
1052 ibcs2_sysfs(struct thread *td, struct ibcs2_sysfs_args *uap)
1053 {
1054 #define IBCS2_GETFSIND        1
1055 #define IBCS2_GETFSTYP        2
1056 #define IBCS2_GETNFSTYP       3
1057
1058         switch(uap->cmd) {
1059         case IBCS2_GETFSIND:
1060         case IBCS2_GETFSTYP:
1061         case IBCS2_GETNFSTYP:
1062                 break;
1063         }
1064         return EINVAL;          /* XXX - TODO */
1065 }
1066
1067 int
1068 ibcs2_unlink(struct thread *td, struct ibcs2_unlink_args *uap)
1069 {
1070         char *path;
1071         int error;
1072
1073         CHECKALTEXIST(td, uap->path, &path);
1074         error = kern_unlinkat(td, AT_FDCWD, path, UIO_SYSSPACE, 0);
1075         free(path, M_TEMP);
1076         return (error);
1077 }
1078
1079 int
1080 ibcs2_chdir(struct thread *td, struct ibcs2_chdir_args *uap)
1081 {
1082         char *path;
1083         int error;
1084
1085         CHECKALTEXIST(td, uap->path, &path);
1086         error = kern_chdir(td, path, UIO_SYSSPACE);
1087         free(path, M_TEMP);
1088         return (error);
1089 }
1090
1091 int
1092 ibcs2_chmod(struct thread *td, struct ibcs2_chmod_args *uap)
1093 {
1094         char *path;
1095         int error;
1096
1097         CHECKALTEXIST(td, uap->path, &path);
1098         error = kern_fchmodat(td, AT_FDCWD, path, UIO_SYSSPACE, uap->mode, 0);
1099         free(path, M_TEMP);
1100         return (error);
1101 }
1102
1103 int
1104 ibcs2_chown(struct thread *td, struct ibcs2_chown_args *uap)
1105 {
1106         char *path;
1107         int error;
1108
1109         CHECKALTEXIST(td, uap->path, &path);
1110         error = kern_fchownat(td, AT_FDCWD, path, UIO_SYSSPACE, uap->uid,
1111             uap->gid, 0);
1112         free(path, M_TEMP);
1113         return (error);
1114 }
1115
1116 int
1117 ibcs2_rmdir(struct thread *td, struct ibcs2_rmdir_args *uap)
1118 {
1119         char *path;
1120         int error;
1121
1122         CHECKALTEXIST(td, uap->path, &path);
1123         error = kern_rmdirat(td, AT_FDCWD, path, UIO_SYSSPACE);
1124         free(path, M_TEMP);
1125         return (error);
1126 }
1127
1128 int
1129 ibcs2_mkdir(struct thread *td, struct ibcs2_mkdir_args *uap)
1130 {
1131         char *path;
1132         int error;
1133
1134         CHECKALTEXIST(td, uap->path, &path);
1135         error = kern_mkdirat(td, AT_FDCWD, path, UIO_SYSSPACE, uap->mode);
1136         free(path, M_TEMP);
1137         return (error);
1138 }
1139
1140 int
1141 ibcs2_symlink(struct thread *td, struct ibcs2_symlink_args *uap)
1142 {
1143         char *path, *link;
1144         int error;
1145
1146         CHECKALTEXIST(td, uap->path, &path);
1147
1148         /*
1149          * Have to expand CHECKALTCREAT() so that 'path' can be freed on
1150          * errors.
1151          */
1152         error = ibcs2_emul_find(td, uap->link, UIO_USERSPACE, &link, 1);
1153         if (link == NULL) {
1154                 free(path, M_TEMP);
1155                 return (error);
1156         }
1157         error = kern_symlinkat(td, path, AT_FDCWD, link, UIO_SYSSPACE);
1158         free(path, M_TEMP);
1159         free(link, M_TEMP);
1160         return (error);
1161 }
1162
1163 int
1164 ibcs2_rename(struct thread *td, struct ibcs2_rename_args *uap)
1165 {
1166         char *from, *to;
1167         int error;
1168
1169         CHECKALTEXIST(td, uap->from, &from);
1170
1171         /*
1172          * Have to expand CHECKALTCREAT() so that 'from' can be freed on
1173          * errors.
1174          */
1175         error = ibcs2_emul_find(td, uap->to, UIO_USERSPACE, &to, 1);
1176         if (to == NULL) {
1177                 free(from, M_TEMP);
1178                 return (error);
1179         }
1180         error = kern_renameat(td, AT_FDCWD, from, AT_FDCWD, to, UIO_SYSSPACE);
1181         free(from, M_TEMP);
1182         free(to, M_TEMP);
1183         return (error);
1184 }
1185
1186 int
1187 ibcs2_readlink(struct thread *td, struct ibcs2_readlink_args *uap)
1188 {
1189         char *path;
1190         int error;
1191
1192         CHECKALTEXIST(td, uap->path, &path);
1193         error = kern_readlinkat(td, AT_FDCWD, path, UIO_SYSSPACE,
1194             uap->buf, UIO_USERSPACE, uap->count);
1195         free(path, M_TEMP);
1196         return (error);
1197 }