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: releng/6.2/sys/i386/ibcs2/ibcs2_misc.c 147821 2005-07-07 19:29:42Z jhb $");
51
52 /*
53 * IBCS2 compatibility module.
54 *
55 * IBCS2 system calls that are implemented differently in BSD are
56 * handled here.
57 */
58 #include "opt_mac.h"
59
60 #include <sys/param.h>
61 #include <sys/systm.h>
62 #include <sys/dirent.h>
63 #include <sys/fcntl.h>
64 #include <sys/filedesc.h>
65 #include <sys/imgact.h>
66 #include <sys/kernel.h>
67 #include <sys/lock.h>
68 #include <sys/mac.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/reboot.h>
73 #include <sys/resourcevar.h>
74 #include <sys/stat.h>
75 #include <sys/sysctl.h>
76 #include <sys/syscallsubr.h>
77 #include <sys/sysproto.h>
78 #include <sys/time.h>
79 #include <sys/times.h>
80 #include <sys/vnode.h>
81 #include <sys/wait.h>
82
83 #include <machine/cpu.h>
84
85 #include <i386/ibcs2/ibcs2_dirent.h>
86 #include <i386/ibcs2/ibcs2_signal.h>
87 #include <i386/ibcs2/ibcs2_proto.h>
88 #include <i386/ibcs2/ibcs2_unistd.h>
89 #include <i386/ibcs2/ibcs2_util.h>
90 #include <i386/ibcs2/ibcs2_utime.h>
91 #include <i386/ibcs2/ibcs2_xenix.h>
92
93 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 exec_free_args(&eargs);
211 return (error);
212 }
213
214 int
215 ibcs2_execve(td, uap)
216 struct thread *td;
217 struct ibcs2_execve_args *uap;
218 {
219 struct image_args eargs;
220 char *path;
221 int error;
222
223 CHECKALTEXIST(td, uap->path, &path);
224
225 error = exec_copyin_args(&eargs, path, UIO_SYSSPACE, uap->argp,
226 uap->envp);
227 free(path, M_TEMP);
228 if (error == 0)
229 error = kern_execve(td, &eargs, NULL);
230 exec_free_args(&eargs);
231 return (error);
232 }
233
234 int
235 ibcs2_umount(td, uap)
236 struct thread *td;
237 struct ibcs2_umount_args *uap;
238 {
239 struct unmount_args um;
240
241 um.path = uap->name;
242 um.flags = 0;
243 return unmount(td, &um);
244 }
245
246 int
247 ibcs2_mount(td, uap)
248 struct thread *td;
249 struct ibcs2_mount_args *uap;
250 {
251 #ifdef notyet
252 int oflags = uap->flags, nflags, error;
253 char fsname[MFSNAMELEN];
254
255 if (oflags & (IBCS2_MS_NOSUB | IBCS2_MS_SYS5))
256 return (EINVAL);
257 if ((oflags & IBCS2_MS_NEWTYPE) == 0)
258 return (EINVAL);
259 nflags = 0;
260 if (oflags & IBCS2_MS_RDONLY)
261 nflags |= MNT_RDONLY;
262 if (oflags & IBCS2_MS_NOSUID)
263 nflags |= MNT_NOSUID;
264 if (oflags & IBCS2_MS_REMOUNT)
265 nflags |= MNT_UPDATE;
266 uap->flags = nflags;
267
268 if (error = copyinstr((caddr_t)uap->type, fsname, sizeof fsname,
269 (u_int *)0))
270 return (error);
271
272 if (strcmp(fsname, "4.2") == 0) {
273 uap->type = (caddr_t)STACK_ALLOC();
274 if (error = copyout("ufs", uap->type, sizeof("ufs")))
275 return (error);
276 } else if (strcmp(fsname, "nfs") == 0) {
277 struct ibcs2_nfs_args sna;
278 struct sockaddr_in sain;
279 struct nfs_args na;
280 struct sockaddr sa;
281
282 if (error = copyin(uap->data, &sna, sizeof sna))
283 return (error);
284 if (error = copyin(sna.addr, &sain, sizeof sain))
285 return (error);
286 bcopy(&sain, &sa, sizeof sa);
287 sa.sa_len = sizeof(sain);
288 uap->data = (caddr_t)STACK_ALLOC();
289 na.addr = (struct sockaddr *)((int)uap->data + sizeof na);
290 na.sotype = SOCK_DGRAM;
291 na.proto = IPPROTO_UDP;
292 na.fh = (nfsv2fh_t *)sna.fh;
293 na.flags = sna.flags;
294 na.wsize = sna.wsize;
295 na.rsize = sna.rsize;
296 na.timeo = sna.timeo;
297 na.retrans = sna.retrans;
298 na.hostname = sna.hostname;
299
300 if (error = copyout(&sa, na.addr, sizeof sa))
301 return (error);
302 if (error = copyout(&na, uap->data, sizeof na))
303 return (error);
304 }
305 return (mount(td, uap));
306 #else
307 return EINVAL;
308 #endif
309 }
310
311 /*
312 * Read iBCS2-style directory entries. We suck them into kernel space so
313 * that they can be massaged before being copied out to user code. Like
314 * SunOS, we squish out `empty' entries.
315 *
316 * This is quite ugly, but what do you expect from compatibility code?
317 */
318
319 int
320 ibcs2_getdents(td, uap)
321 struct thread *td;
322 register struct ibcs2_getdents_args *uap;
323 {
324 register struct vnode *vp;
325 register caddr_t inp, buf; /* BSD-format */
326 register int len, reclen; /* BSD-format */
327 register caddr_t outp; /* iBCS2-format */
328 register int resid; /* iBCS2-format */
329 struct file *fp;
330 struct uio auio;
331 struct iovec aiov;
332 struct ibcs2_dirent idb;
333 off_t off; /* true file offset */
334 int buflen, error, eofflag;
335 u_long *cookies = NULL, *cookiep;
336 int ncookies;
337 #define BSD_DIRENT(cp) ((struct dirent *)(cp))
338 #define IBCS2_RECLEN(reclen) (reclen + sizeof(u_short))
339
340 if ((error = getvnode(td->td_proc->p_fd, uap->fd, &fp)) != 0)
341 return (error);
342 if ((fp->f_flag & FREAD) == 0) {
343 fdrop(fp, td);
344 return (EBADF);
345 }
346 vp = fp->f_vnode;
347 if (vp->v_type != VDIR) { /* XXX vnode readdir op should do this */
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_EXCLUSIVE | LK_RETRY, td);
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_check_vnode_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, td);
464 fdrop(fp, td);
465 if (cookies)
466 free(cookies, M_TEMP);
467 free(buf, M_TEMP);
468 return (error);
469 }
470
471 int
472 ibcs2_read(td, uap)
473 struct thread *td;
474 struct ibcs2_read_args *uap;
475 {
476 register struct vnode *vp;
477 register caddr_t inp, buf; /* BSD-format */
478 register int len, reclen; /* BSD-format */
479 register caddr_t outp; /* iBCS2-format */
480 register int resid; /* iBCS2-format */
481 struct file *fp;
482 struct uio auio;
483 struct iovec aiov;
484 struct ibcs2_direct {
485 ibcs2_ino_t ino;
486 char name[14];
487 } idb;
488 off_t off; /* true file offset */
489 int buflen, error, eofflag, size;
490 u_long *cookies = NULL, *cookiep;
491 int ncookies;
492
493 if ((error = getvnode(td->td_proc->p_fd, uap->fd, &fp)) != 0) {
494 if (error == EINVAL)
495 return read(td, (struct read_args *)uap);
496 else
497 return error;
498 }
499 if ((fp->f_flag & FREAD) == 0) {
500 fdrop(fp, td);
501 return (EBADF);
502 }
503 vp = fp->f_vnode;
504 if (vp->v_type != VDIR) {
505 fdrop(fp, td);
506 return read(td, (struct read_args *)uap);
507 }
508
509 off = fp->f_offset;
510
511 DPRINTF(("ibcs2_read: read directory\n"));
512
513 buflen = max(DIRBLKSIZ, uap->nbytes);
514 buflen = min(buflen, MAXBSIZE);
515 buf = malloc(buflen, M_TEMP, M_WAITOK);
516 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
517 again:
518 aiov.iov_base = buf;
519 aiov.iov_len = buflen;
520 auio.uio_iov = &aiov;
521 auio.uio_iovcnt = 1;
522 auio.uio_rw = UIO_READ;
523 auio.uio_segflg = UIO_SYSSPACE;
524 auio.uio_td = td;
525 auio.uio_resid = buflen;
526 auio.uio_offset = off;
527
528 if (cookies) {
529 free(cookies, M_TEMP);
530 cookies = NULL;
531 }
532
533 #ifdef MAC
534 error = mac_check_vnode_readdir(td->td_ucred, vp);
535 if (error)
536 goto out;
537 #endif
538
539 /*
540 * First we read into the malloc'ed buffer, then
541 * we massage it into user space, one record at a time.
542 */
543 if ((error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies, &cookies)) != 0) {
544 DPRINTF(("VOP_READDIR failed: %d\n", error));
545 goto out;
546 }
547 inp = buf;
548 outp = uap->buf;
549 resid = uap->nbytes;
550 if ((len = buflen - auio.uio_resid) <= 0)
551 goto eof;
552
553 cookiep = cookies;
554
555 if (cookies) {
556 /*
557 * When using cookies, the vfs has the option of reading from
558 * a different offset than that supplied (UFS truncates the
559 * offset to a block boundary to make sure that it never reads
560 * partway through a directory entry, even if the directory
561 * has been compacted).
562 */
563 while (len > 0 && ncookies > 0 && *cookiep <= off) {
564 len -= BSD_DIRENT(inp)->d_reclen;
565 inp += BSD_DIRENT(inp)->d_reclen;
566 cookiep++;
567 ncookies--;
568 }
569 }
570
571 for (; len > 0 && resid > 0; len -= reclen) {
572 if (cookiep && ncookies == 0)
573 break;
574 reclen = BSD_DIRENT(inp)->d_reclen;
575 if (reclen & 3) {
576 printf("ibcs2_read: reclen=%d\n", reclen);
577 error = EFAULT;
578 goto out;
579 }
580 if (BSD_DIRENT(inp)->d_fileno == 0) {
581 inp += reclen; /* it is a hole; squish it out */
582 if (cookiep) {
583 off = *cookiep++;
584 ncookies--;
585 } else
586 off += reclen;
587 continue;
588 }
589 if (reclen > len || resid < sizeof(struct ibcs2_direct)) {
590 /* entry too big for buffer, so just stop */
591 outp++;
592 break;
593 }
594 /*
595 * Massage in place to make an iBCS2-shaped dirent (otherwise
596 * we have to worry about touching user memory outside of
597 * the copyout() call).
598 *
599 * TODO: if length(filename) > 14, then break filename into
600 * multiple entries and set inode = 0xffff except last
601 */
602 idb.ino = (BSD_DIRENT(inp)->d_fileno > 0xfffe) ? 0xfffe :
603 BSD_DIRENT(inp)->d_fileno;
604 (void)copystr(BSD_DIRENT(inp)->d_name, idb.name, 14, &size);
605 bzero(idb.name + size, 14 - size);
606 if ((error = copyout(&idb, outp, sizeof(struct ibcs2_direct))) != 0)
607 goto out;
608 /* advance past this real entry */
609 if (cookiep) {
610 off = *cookiep++;
611 ncookies--;
612 } else
613 off += reclen;
614 inp += reclen;
615 /* advance output past iBCS2-shaped entry */
616 outp += sizeof(struct ibcs2_direct);
617 resid -= sizeof(struct ibcs2_direct);
618 }
619 /* if we squished out the whole block, try again */
620 if (outp == uap->buf)
621 goto again;
622 fp->f_offset = off; /* update the vnode offset */
623 eof:
624 td->td_retval[0] = uap->nbytes - resid;
625 out:
626 VOP_UNLOCK(vp, 0, td);
627 fdrop(fp, td);
628 if (cookies)
629 free(cookies, M_TEMP);
630 free(buf, M_TEMP);
631 return (error);
632 }
633
634 int
635 ibcs2_mknod(td, uap)
636 struct thread *td;
637 struct ibcs2_mknod_args *uap;
638 {
639 char *path;
640 int error;
641
642 CHECKALTCREAT(td, uap->path, &path);
643 if (S_ISFIFO(uap->mode))
644 error = kern_mkfifo(td, path, UIO_SYSSPACE, uap->mode);
645 else
646 error = kern_mknod(td, path, UIO_SYSSPACE, uap->mode, uap->dev);
647 free(path, M_TEMP);
648 return (error);
649 }
650
651 int
652 ibcs2_getgroups(td, uap)
653 struct thread *td;
654 struct ibcs2_getgroups_args *uap;
655 {
656 int error, i;
657 ibcs2_gid_t *iset = NULL;
658 struct getgroups_args sa;
659 gid_t *gp;
660 caddr_t sg = stackgap_init();
661
662 if (uap->gidsetsize < 0)
663 return (EINVAL);
664 if (uap->gidsetsize > NGROUPS_MAX)
665 uap->gidsetsize = NGROUPS_MAX;
666 sa.gidsetsize = uap->gidsetsize;
667 if (uap->gidsetsize) {
668 sa.gidset = stackgap_alloc(&sg, NGROUPS_MAX *
669 sizeof(gid_t *));
670 iset = stackgap_alloc(&sg, uap->gidsetsize *
671 sizeof(ibcs2_gid_t));
672 }
673 if ((error = getgroups(td, &sa)) != 0)
674 return error;
675 if (uap->gidsetsize == 0)
676 return 0;
677
678 for (i = 0, gp = sa.gidset; i < td->td_retval[0]; i++)
679 iset[i] = (ibcs2_gid_t)*gp++;
680 if (td->td_retval[0] && (error = copyout((caddr_t)iset,
681 (caddr_t)uap->gidset,
682 sizeof(ibcs2_gid_t) * td->td_retval[0])))
683 return error;
684 return 0;
685 }
686
687 int
688 ibcs2_setgroups(td, uap)
689 struct thread *td;
690 struct ibcs2_setgroups_args *uap;
691 {
692 int error, i;
693 ibcs2_gid_t *iset;
694 struct setgroups_args sa;
695 gid_t *gp;
696 caddr_t sg = stackgap_init();
697
698 if (uap->gidsetsize < 0 || uap->gidsetsize > NGROUPS_MAX)
699 return (EINVAL);
700 sa.gidsetsize = uap->gidsetsize;
701 sa.gidset = stackgap_alloc(&sg, sa.gidsetsize *
702 sizeof(gid_t *));
703 iset = stackgap_alloc(&sg, sa.gidsetsize *
704 sizeof(ibcs2_gid_t *));
705 if (sa.gidsetsize) {
706 if ((error = copyin((caddr_t)uap->gidset, (caddr_t)iset,
707 sizeof(ibcs2_gid_t *) *
708 uap->gidsetsize)) != 0)
709 return error;
710 }
711 for (i = 0, gp = sa.gidset; i < sa.gidsetsize; i++)
712 *gp++ = (gid_t)iset[i];
713 return setgroups(td, &sa);
714 }
715
716 int
717 ibcs2_setuid(td, uap)
718 struct thread *td;
719 struct ibcs2_setuid_args *uap;
720 {
721 struct setuid_args sa;
722
723 sa.uid = (uid_t)uap->uid;
724 return setuid(td, &sa);
725 }
726
727 int
728 ibcs2_setgid(td, uap)
729 struct thread *td;
730 struct ibcs2_setgid_args *uap;
731 {
732 struct setgid_args sa;
733
734 sa.gid = (gid_t)uap->gid;
735 return setgid(td, &sa);
736 }
737
738 int
739 ibcs2_time(td, uap)
740 struct thread *td;
741 struct ibcs2_time_args *uap;
742 {
743 struct timeval tv;
744
745 microtime(&tv);
746 td->td_retval[0] = tv.tv_sec;
747 if (uap->tp)
748 return copyout((caddr_t)&tv.tv_sec, (caddr_t)uap->tp,
749 sizeof(ibcs2_time_t));
750 else
751 return 0;
752 }
753
754 int
755 ibcs2_pathconf(td, uap)
756 struct thread *td;
757 struct ibcs2_pathconf_args *uap;
758 {
759 char *path;
760 int error;
761
762 CHECKALTEXIST(td, uap->path, &path);
763 uap->name++; /* iBCS2 _PC_* defines are offset by one */
764 error = kern_pathconf(td, path, UIO_SYSSPACE, uap->name);
765 free(path, M_TEMP);
766 return (error);
767 }
768
769 int
770 ibcs2_fpathconf(td, uap)
771 struct thread *td;
772 struct ibcs2_fpathconf_args *uap;
773 {
774 uap->name++; /* iBCS2 _PC_* defines are offset by one */
775 return fpathconf(td, (struct fpathconf_args *)uap);
776 }
777
778 int
779 ibcs2_sysconf(td, uap)
780 struct thread *td;
781 struct ibcs2_sysconf_args *uap;
782 {
783 int mib[2], value, len, error;
784 struct proc *p;
785
786 p = td->td_proc;
787 switch(uap->name) {
788 case IBCS2_SC_ARG_MAX:
789 mib[1] = KERN_ARGMAX;
790 break;
791
792 case IBCS2_SC_CHILD_MAX:
793 PROC_LOCK(p);
794 td->td_retval[0] = lim_cur(td->td_proc, RLIMIT_NPROC);
795 PROC_UNLOCK(p);
796 return 0;
797
798 case IBCS2_SC_CLK_TCK:
799 td->td_retval[0] = hz;
800 return 0;
801
802 case IBCS2_SC_NGROUPS_MAX:
803 mib[1] = KERN_NGROUPS;
804 break;
805
806 case IBCS2_SC_OPEN_MAX:
807 PROC_LOCK(p);
808 td->td_retval[0] = lim_cur(td->td_proc, RLIMIT_NOFILE);
809 PROC_UNLOCK(p);
810 return 0;
811
812 case IBCS2_SC_JOB_CONTROL:
813 mib[1] = KERN_JOB_CONTROL;
814 break;
815
816 case IBCS2_SC_SAVED_IDS:
817 mib[1] = KERN_SAVED_IDS;
818 break;
819
820 case IBCS2_SC_VERSION:
821 mib[1] = KERN_POSIX1;
822 break;
823
824 case IBCS2_SC_PASS_MAX:
825 td->td_retval[0] = 128; /* XXX - should we create PASS_MAX ? */
826 return 0;
827
828 case IBCS2_SC_XOPEN_VERSION:
829 td->td_retval[0] = 2; /* XXX: What should that be? */
830 return 0;
831
832 default:
833 return EINVAL;
834 }
835
836 mib[0] = CTL_KERN;
837 len = sizeof(value);
838 error = kernel_sysctl(td, mib, 2, &value, &len, NULL, 0, NULL, 0);
839 if (error)
840 return error;
841 td->td_retval[0] = value;
842 return 0;
843 }
844
845 int
846 ibcs2_alarm(td, uap)
847 struct thread *td;
848 struct ibcs2_alarm_args *uap;
849 {
850 struct itimerval itv, oitv;
851 int error;
852
853 timevalclear(&itv.it_interval);
854 itv.it_value.tv_sec = uap->sec;
855 itv.it_value.tv_usec = 0;
856 error = kern_setitimer(td, ITIMER_REAL, &itv, &oitv);
857 if (error)
858 return (error);
859 if (oitv.it_value.tv_usec != 0)
860 oitv.it_value.tv_sec++;
861 td->td_retval[0] = oitv.it_value.tv_sec;
862 return (0);
863 }
864
865 int
866 ibcs2_times(td, uap)
867 struct thread *td;
868 struct ibcs2_times_args *uap;
869 {
870 struct rusage ru;
871 struct timeval t;
872 struct tms tms;
873 int error;
874
875 #define CONVTCK(r) (r.tv_sec * hz + r.tv_usec / (1000000 / hz))
876
877 error = kern_getrusage(td, RUSAGE_SELF, &ru);
878 if (error)
879 return (error);
880 tms.tms_utime = CONVTCK(ru.ru_utime);
881 tms.tms_stime = CONVTCK(ru.ru_stime);
882
883 error = kern_getrusage(td, RUSAGE_CHILDREN, &ru);
884 if (error)
885 return (error);
886 tms.tms_cutime = CONVTCK(ru.ru_utime);
887 tms.tms_cstime = CONVTCK(ru.ru_stime);
888
889 microtime(&t);
890 td->td_retval[0] = CONVTCK(t);
891
892 return (copyout(&tms, uap->tp, sizeof(struct tms)));
893 }
894
895 int
896 ibcs2_stime(td, uap)
897 struct thread *td;
898 struct ibcs2_stime_args *uap;
899 {
900 struct timeval tv;
901 long secs;
902 int error;
903
904 error = copyin(uap->timep, &secs, sizeof(long));
905 if (error)
906 return (error);
907 tv.tv_sec = secs;
908 tv.tv_usec = 0;
909 error = kern_settimeofday(td, &tv, NULL);
910 if (error)
911 error = EPERM;
912 return (error);
913 }
914
915 int
916 ibcs2_utime(td, uap)
917 struct thread *td;
918 struct ibcs2_utime_args *uap;
919 {
920 struct ibcs2_utimbuf ubuf;
921 struct timeval tbuf[2], *tp;
922 char *path;
923 int error;
924
925 if (uap->buf) {
926 error = copyin(uap->buf, &ubuf, sizeof(ubuf));
927 if (error)
928 return (error);
929 tbuf[0].tv_sec = ubuf.actime;
930 tbuf[0].tv_usec = 0;
931 tbuf[1].tv_sec = ubuf.modtime;
932 tbuf[1].tv_usec = 0;
933 tp = tbuf;
934 } else
935 tp = NULL;
936
937 CHECKALTEXIST(td, uap->path, &path);
938 error = kern_utimes(td, path, UIO_SYSSPACE, tp, UIO_SYSSPACE);
939 free(path, M_TEMP);
940 return (error);
941 }
942
943 int
944 ibcs2_nice(td, uap)
945 struct thread *td;
946 struct ibcs2_nice_args *uap;
947 {
948 int error;
949 struct setpriority_args sa;
950
951 sa.which = PRIO_PROCESS;
952 sa.who = 0;
953 sa.prio = td->td_proc->p_nice + uap->incr;
954 if ((error = setpriority(td, &sa)) != 0)
955 return EPERM;
956 td->td_retval[0] = td->td_proc->p_nice;
957 return 0;
958 }
959
960 /*
961 * iBCS2 getpgrp, setpgrp, setsid, and setpgid
962 */
963
964 int
965 ibcs2_pgrpsys(td, uap)
966 struct thread *td;
967 struct ibcs2_pgrpsys_args *uap;
968 {
969 struct proc *p = td->td_proc;
970 switch (uap->type) {
971 case 0: /* getpgrp */
972 PROC_LOCK(p);
973 td->td_retval[0] = p->p_pgrp->pg_id;
974 PROC_UNLOCK(p);
975 return 0;
976
977 case 1: /* setpgrp */
978 {
979 struct setpgid_args sa;
980
981 sa.pid = 0;
982 sa.pgid = 0;
983 setpgid(td, &sa);
984 PROC_LOCK(p);
985 td->td_retval[0] = p->p_pgrp->pg_id;
986 PROC_UNLOCK(p);
987 return 0;
988 }
989
990 case 2: /* setpgid */
991 {
992 struct setpgid_args sa;
993
994 sa.pid = uap->pid;
995 sa.pgid = uap->pgid;
996 return setpgid(td, &sa);
997 }
998
999 case 3: /* setsid */
1000 return setsid(td, NULL);
1001
1002 default:
1003 return EINVAL;
1004 }
1005 }
1006
1007 /*
1008 * XXX - need to check for nested calls
1009 */
1010
1011 int
1012 ibcs2_plock(td, uap)
1013 struct thread *td;
1014 struct ibcs2_plock_args *uap;
1015 {
1016 int error;
1017 #define IBCS2_UNLOCK 0
1018 #define IBCS2_PROCLOCK 1
1019 #define IBCS2_TEXTLOCK 2
1020 #define IBCS2_DATALOCK 4
1021
1022
1023 if ((error = suser(td)) != 0)
1024 return EPERM;
1025 switch(uap->cmd) {
1026 case IBCS2_UNLOCK:
1027 case IBCS2_PROCLOCK:
1028 case IBCS2_TEXTLOCK:
1029 case IBCS2_DATALOCK:
1030 return 0; /* XXX - TODO */
1031 }
1032 return EINVAL;
1033 }
1034
1035 int
1036 ibcs2_uadmin(td, uap)
1037 struct thread *td;
1038 struct ibcs2_uadmin_args *uap;
1039 {
1040 #define SCO_A_REBOOT 1
1041 #define SCO_A_SHUTDOWN 2
1042 #define SCO_A_REMOUNT 4
1043 #define SCO_A_CLOCK 8
1044 #define SCO_A_SETCONFIG 128
1045 #define SCO_A_GETDEV 130
1046
1047 #define SCO_AD_HALT 0
1048 #define SCO_AD_BOOT 1
1049 #define SCO_AD_IBOOT 2
1050 #define SCO_AD_PWRDOWN 3
1051 #define SCO_AD_PWRNAP 4
1052
1053 #define SCO_AD_PANICBOOT 1
1054
1055 #define SCO_AD_GETBMAJ 0
1056 #define SCO_AD_GETCMAJ 1
1057
1058 if (suser(td))
1059 return EPERM;
1060
1061 switch(uap->cmd) {
1062 case SCO_A_REBOOT:
1063 case SCO_A_SHUTDOWN:
1064 switch(uap->func) {
1065 struct reboot_args r;
1066 case SCO_AD_HALT:
1067 case SCO_AD_PWRDOWN:
1068 case SCO_AD_PWRNAP:
1069 r.opt = RB_HALT;
1070 reboot(td, &r);
1071 case SCO_AD_BOOT:
1072 case SCO_AD_IBOOT:
1073 r.opt = RB_AUTOBOOT;
1074 reboot(td, &r);
1075 }
1076 return EINVAL;
1077 case SCO_A_REMOUNT:
1078 case SCO_A_CLOCK:
1079 case SCO_A_SETCONFIG:
1080 return 0;
1081 case SCO_A_GETDEV:
1082 return EINVAL; /* XXX - TODO */
1083 }
1084 return EINVAL;
1085 }
1086
1087 int
1088 ibcs2_sysfs(td, uap)
1089 struct thread *td;
1090 struct ibcs2_sysfs_args *uap;
1091 {
1092 #define IBCS2_GETFSIND 1
1093 #define IBCS2_GETFSTYP 2
1094 #define IBCS2_GETNFSTYP 3
1095
1096 switch(uap->cmd) {
1097 case IBCS2_GETFSIND:
1098 case IBCS2_GETFSTYP:
1099 case IBCS2_GETNFSTYP:
1100 break;
1101 }
1102 return EINVAL; /* XXX - TODO */
1103 }
1104
1105 int
1106 ibcs2_unlink(td, uap)
1107 struct thread *td;
1108 struct ibcs2_unlink_args *uap;
1109 {
1110 char *path;
1111 int error;
1112
1113 CHECKALTEXIST(td, uap->path, &path);
1114 error = kern_unlink(td, path, UIO_SYSSPACE);
1115 free(path, M_TEMP);
1116 return (error);
1117 }
1118
1119 int
1120 ibcs2_chdir(td, uap)
1121 struct thread *td;
1122 struct ibcs2_chdir_args *uap;
1123 {
1124 char *path;
1125 int error;
1126
1127 CHECKALTEXIST(td, uap->path, &path);
1128 error = kern_chdir(td, path, UIO_SYSSPACE);
1129 free(path, M_TEMP);
1130 return (error);
1131 }
1132
1133 int
1134 ibcs2_chmod(td, uap)
1135 struct thread *td;
1136 struct ibcs2_chmod_args *uap;
1137 {
1138 char *path;
1139 int error;
1140
1141 CHECKALTEXIST(td, uap->path, &path);
1142 error = kern_chmod(td, path, UIO_SYSSPACE, uap->mode);
1143 free(path, M_TEMP);
1144 return (error);
1145 }
1146
1147 int
1148 ibcs2_chown(td, uap)
1149 struct thread *td;
1150 struct ibcs2_chown_args *uap;
1151 {
1152 char *path;
1153 int error;
1154
1155 CHECKALTEXIST(td, uap->path, &path);
1156 error = kern_chown(td, path, UIO_SYSSPACE, uap->uid, uap->gid);
1157 free(path, M_TEMP);
1158 return (error);
1159 }
1160
1161 int
1162 ibcs2_rmdir(td, uap)
1163 struct thread *td;
1164 struct ibcs2_rmdir_args *uap;
1165 {
1166 char *path;
1167 int error;
1168
1169 CHECKALTEXIST(td, uap->path, &path);
1170 error = kern_rmdir(td, path, UIO_SYSSPACE);
1171 free(path, M_TEMP);
1172 return (error);
1173 }
1174
1175 int
1176 ibcs2_mkdir(td, uap)
1177 struct thread *td;
1178 struct ibcs2_mkdir_args *uap;
1179 {
1180 char *path;
1181 int error;
1182
1183 CHECKALTEXIST(td, uap->path, &path);
1184 error = kern_mkdir(td, path, UIO_SYSSPACE, uap->mode);
1185 free(path, M_TEMP);
1186 return (error);
1187 }
1188
1189 int
1190 ibcs2_symlink(td, uap)
1191 struct thread *td;
1192 struct ibcs2_symlink_args *uap;
1193 {
1194 char *path, *link;
1195 int error;
1196
1197 CHECKALTEXIST(td, uap->path, &path);
1198
1199 /*
1200 * Have to expand CHECKALTCREAT() so that 'path' can be freed on
1201 * errors.
1202 */
1203 error = ibcs2_emul_find(td, uap->link, UIO_USERSPACE, &link, 1);
1204 if (link == NULL) {
1205 free(path, M_TEMP);
1206 return (error);
1207 }
1208 error = kern_symlink(td, path, link, UIO_SYSSPACE);
1209 free(path, M_TEMP);
1210 free(link, M_TEMP);
1211 return (error);
1212 }
1213
1214 int
1215 ibcs2_rename(td, uap)
1216 struct thread *td;
1217 struct ibcs2_rename_args *uap;
1218 {
1219 char *from, *to;
1220 int error;
1221
1222 CHECKALTEXIST(td, uap->from, &from);
1223
1224 /*
1225 * Have to expand CHECKALTCREAT() so that 'from' can be freed on
1226 * errors.
1227 */
1228 error = ibcs2_emul_find(td, uap->to, UIO_USERSPACE, &to, 1);
1229 if (link == NULL) {
1230 free(from, M_TEMP);
1231 return (error);
1232 }
1233 error = kern_rename(td, from, to, UIO_SYSSPACE);
1234 free(from, M_TEMP);
1235 free(to, M_TEMP);
1236 return (error);
1237 }
1238
1239 int
1240 ibcs2_readlink(td, uap)
1241 struct thread *td;
1242 struct ibcs2_readlink_args *uap;
1243 {
1244 char *path;
1245 int error;
1246
1247 CHECKALTEXIST(td, uap->path, &path);
1248 error = kern_readlink(td, path, UIO_SYSSPACE, uap->buf, UIO_USERSPACE,
1249 uap->count);
1250 free(path, M_TEMP);
1251 return (error);
1252 }
Cache object: 98fea7447fac6f2d1aaf782f5c5011eb
|