Commit | Line | Data |
---|---|---|
a8fd2d0d KM |
1 | /* |
2 | * Copyright (c) 1988 University of Utah. | |
3 | * Copyright (c) 1990 The Regents of the University of California. | |
4 | * All rights reserved. | |
5 | * | |
6 | * This code is derived from software contributed to Berkeley by | |
7 | * the Systems Programming Group of the University of Utah Computer | |
8 | * Science Department. | |
9 | * | |
10 | * %sccs.include.redist.c% | |
11 | * | |
22d09b27 | 12 | * from: Utah $Hdr: hpux_compat.c 1.3 90/09/17$ |
a8fd2d0d | 13 | * |
22d09b27 | 14 | * @(#)hpux_compat.c 7.10 (Berkeley) %G% |
a8fd2d0d KM |
15 | */ |
16 | ||
17 | /* | |
18 | * Various HPUX compatibility routines | |
19 | */ | |
20 | ||
21 | #ifdef HPUXCOMPAT | |
22 | ||
23 | #include "param.h" | |
24 | #include "systm.h" | |
196c0567 | 25 | #include "user.h" |
a8fd2d0d KM |
26 | #include "kernel.h" |
27 | #include "proc.h" | |
28 | #include "buf.h" | |
29 | #include "wait.h" | |
30 | #include "file.h" | |
31 | #include "vnode.h" | |
32 | #include "ioctl.h" | |
33 | #include "uio.h" | |
34 | #include "ptrace.h" | |
35 | #include "stat.h" | |
36 | #include "syslog.h" | |
37 | #include "malloc.h" | |
38 | #include "mount.h" | |
39 | #include "ipc.h" | |
40 | ||
41 | #include "machine/cpu.h" | |
42 | #include "machine/reg.h" | |
43 | #include "machine/psl.h" | |
44 | #include "machine/vmparam.h" | |
45 | #include "hpux.h" | |
46 | #include "hpux_termio.h" | |
47 | ||
48 | #ifdef DEBUG | |
49 | int unimpresponse = 0; | |
50 | #endif | |
51 | ||
a8fd2d0d KM |
52 | /* SYS5 style UTSNAME info */ |
53 | struct hpuxutsname protoutsname = { | |
54 | "4.4bsd", "", "2.0", "B", "9000/3?0", "" | |
55 | }; | |
56 | ||
57 | /* 6.0 and later style context */ | |
58 | #ifdef FPCOPROC | |
59 | char hpuxcontext[] = | |
60 | "standalone HP-MC68881 HP-MC68020 HP-MC68010 localroot default"; | |
61 | #else | |
62 | char hpuxcontext[] = | |
63 | "standalone HP-MC68020 HP-MC68010 localroot default"; | |
64 | #endif | |
65 | ||
66 | /* YP domainname */ | |
67 | char domainname[MAXHOSTNAMELEN] = "unknown"; | |
68 | int domainnamelen = 7; | |
69 | ||
70 | #define NERR 79 | |
71 | #define BERR 1000 | |
72 | ||
73 | /* indexed by BSD errno */ | |
74 | short bsdtohpuxerrnomap[NERR] = { | |
75 | /*00*/ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, | |
76 | /*10*/ 10, 45, 12, 13, 14, 15, 16, 17, 18, 19, | |
77 | /*20*/ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, | |
78 | /*30*/ 30, 31, 32, 33, 34, 246, 245, 244, 216, 217, | |
79 | /*40*/ 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, | |
80 | /*50*/ 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, | |
81 | /*60*/ 238, 239, 249, 248, 241, 242, 247,BERR,BERR,BERR, | |
82 | /*70*/ 70, 71,BERR,BERR,BERR,BERR,BERR, 46,BERR | |
83 | }; | |
84 | ||
d9bd2b96 MH |
85 | notimp(p, uap, retval, code, nargs) |
86 | struct proc *p; | |
87 | int *uap, *retval; | |
88 | int code, nargs; | |
a8fd2d0d | 89 | { |
d9bd2b96 | 90 | int error = 0; |
a8fd2d0d | 91 | #ifdef DEBUG |
d9bd2b96 | 92 | register int *argp = uap; |
a8fd2d0d KM |
93 | extern char *hpuxsyscallnames[]; |
94 | ||
95 | printf("HPUX %s(", hpuxsyscallnames[code]); | |
96 | if (nargs) | |
97 | while (nargs--) | |
98 | printf("%x%c", *argp++, nargs? ',' : ')'); | |
99 | else | |
100 | printf(")"); | |
101 | printf("\n"); | |
102 | switch (unimpresponse) { | |
103 | case 0: | |
d9bd2b96 | 104 | error = nosys(p, uap, retval); |
a8fd2d0d KM |
105 | break; |
106 | case 1: | |
d9bd2b96 | 107 | error = EINVAL; |
a8fd2d0d KM |
108 | break; |
109 | } | |
110 | #else | |
d9bd2b96 | 111 | error = nosys(p, uap, retval); |
a8fd2d0d | 112 | #endif |
d9bd2b96 | 113 | uprintf("HP-UX system call %d not implemented\n", code); |
196c0567 | 114 | return (error); |
a8fd2d0d KM |
115 | } |
116 | ||
117 | /* | |
118 | * HPUX versions of wait and wait3 actually pass the parameters | |
119 | * (status pointer, options, rusage) into the kernel rather than | |
fdf2ec5d KM |
120 | * handling it in the C library stub. We also need to map any |
121 | * termination signal from BSD to HPUX. | |
a8fd2d0d | 122 | */ |
d9bd2b96 MH |
123 | hpuxwait3(p, uap, retval) |
124 | struct proc *p; | |
125 | struct args { | |
a8fd2d0d KM |
126 | int *status; |
127 | int options; | |
128 | int rusage; | |
d9bd2b96 MH |
129 | } *uap; |
130 | int *retval; | |
131 | { | |
a8fd2d0d | 132 | /* rusage pointer must be zero */ |
d9bd2b96 | 133 | if (uap->rusage) |
196c0567 | 134 | return (EINVAL); |
a8fd2d0d KM |
135 | u.u_ar0[PS] = PSL_ALLCC; |
136 | u.u_ar0[R0] = uap->options; | |
137 | u.u_ar0[R1] = uap->rusage; | |
196c0567 | 138 | return (hpuxwait(p, uap, retval)); |
a8fd2d0d KM |
139 | } |
140 | ||
d9bd2b96 MH |
141 | hpuxwait(p, uap, retval) |
142 | struct proc *p; | |
143 | struct args { | |
a8fd2d0d | 144 | int *status; |
d9bd2b96 MH |
145 | } *uap; |
146 | int *retval; | |
147 | { | |
148 | int sig, *statp, error; | |
a8fd2d0d KM |
149 | |
150 | statp = uap->status; /* owait clobbers first arg */ | |
d9bd2b96 | 151 | error = owait(p, uap, retval); |
a8fd2d0d KM |
152 | /* |
153 | * HP-UX wait always returns EINTR when interrupted by a signal | |
154 | * (well, unless its emulating a BSD process, but we don't bother...) | |
155 | */ | |
d9bd2b96 MH |
156 | if (error == ERESTART) |
157 | error = EINTR; | |
158 | if (error) | |
196c0567 | 159 | return (error); |
d9bd2b96 | 160 | sig = retval[1] & 0xFF; |
fdf2ec5d | 161 | if (sig == WSTOPPED) { |
d9bd2b96 MH |
162 | sig = (retval[1] >> 8) & 0xFF; |
163 | retval[1] = (bsdtohpuxsig(sig) << 8) | WSTOPPED; | |
fdf2ec5d | 164 | } else if (sig) |
d9bd2b96 | 165 | retval[1] = (retval[1] & 0xFF00) | |
fdf2ec5d KM |
166 | bsdtohpuxsig(sig & 0x7F) | (sig & 0x80); |
167 | if (statp) | |
d9bd2b96 MH |
168 | if (suword((caddr_t)statp, retval[1])) |
169 | error = EFAULT; | |
196c0567 | 170 | return (error); |
fdf2ec5d KM |
171 | } |
172 | ||
d9bd2b96 MH |
173 | hpuxwaitpid(p, uap, retval) |
174 | struct proc *p; | |
175 | struct args { | |
fdf2ec5d KM |
176 | int pid; |
177 | int *status; | |
178 | int options; | |
179 | struct rusage *rusage; /* wait4 arg */ | |
d9bd2b96 MH |
180 | } *uap; |
181 | int *retval; | |
182 | { | |
183 | int sig, *statp, error; | |
fdf2ec5d KM |
184 | |
185 | uap->rusage = 0; | |
d9bd2b96 | 186 | error = wait4(p, uap, retval); |
fdf2ec5d KM |
187 | /* |
188 | * HP-UX wait always returns EINTR when interrupted by a signal | |
189 | * (well, unless its emulating a BSD process, but we don't bother...) | |
190 | */ | |
d9bd2b96 MH |
191 | if (error == ERESTART) |
192 | error = EINTR; | |
193 | if (error) | |
196c0567 | 194 | return (error); |
d9bd2b96 | 195 | sig = retval[1] & 0xFF; |
a8fd2d0d | 196 | if (sig == WSTOPPED) { |
d9bd2b96 MH |
197 | sig = (retval[1] >> 8) & 0xFF; |
198 | retval[1] = (bsdtohpuxsig(sig) << 8) | WSTOPPED; | |
a8fd2d0d | 199 | } else if (sig) |
d9bd2b96 | 200 | retval[1] = (retval[1] & 0xFF00) | |
a8fd2d0d KM |
201 | bsdtohpuxsig(sig & 0x7F) | (sig & 0x80); |
202 | if (statp) | |
d9bd2b96 MH |
203 | if (suword((caddr_t)statp, retval[1])) |
204 | error = EFAULT; | |
196c0567 | 205 | return (error); |
a8fd2d0d KM |
206 | } |
207 | ||
208 | /* | |
209 | * Must remap some bits in the mode mask. | |
210 | * O_CREAT, O_TRUNC, and O_EXCL must be remapped, | |
211 | * O_SYNCIO (0100000) is removed entirely. | |
212 | */ | |
43af3a95 MK |
213 | hpuxopen(p, uap, retval) |
214 | struct proc *p; | |
d9bd2b96 | 215 | register struct args { |
a8fd2d0d KM |
216 | char *fname; |
217 | int mode; | |
218 | int crtmode; | |
43af3a95 MK |
219 | } *uap; |
220 | int *retval; | |
221 | { | |
a8fd2d0d KM |
222 | int mode; |
223 | ||
224 | mode = uap->mode; | |
225 | uap->mode &= ~(HPUXFSYNCIO|HPUXFEXCL|HPUXFTRUNC|HPUXFCREAT); | |
226 | if (mode & HPUXFCREAT) { | |
227 | /* | |
228 | * simulate the pre-NFS behavior that opening a | |
229 | * file for READ+CREATE ignores the CREATE (unless | |
230 | * EXCL is set in which case we will return the | |
231 | * proper error). | |
232 | */ | |
233 | if ((mode & HPUXFEXCL) || ((mode-FOPEN) & FWRITE)) | |
234 | uap->mode |= FCREAT; | |
235 | } | |
236 | if (mode & HPUXFTRUNC) | |
237 | uap->mode |= FTRUNC; | |
238 | if (mode & HPUXFEXCL) | |
239 | uap->mode |= FEXCL; | |
196c0567 | 240 | return (open(p, uap, retval)); |
a8fd2d0d KM |
241 | } |
242 | ||
d9bd2b96 MH |
243 | hpuxfcntl(p, uap, retval) |
244 | struct proc *p; | |
245 | register struct args { | |
a8fd2d0d KM |
246 | int fdes; |
247 | int cmd; | |
248 | int arg; | |
d9bd2b96 MH |
249 | } *uap; |
250 | int *retval; | |
251 | { | |
252 | int mode, error; | |
a8fd2d0d KM |
253 | |
254 | switch (uap->cmd) { | |
255 | case F_SETFL: | |
256 | uap->arg &= ~(HPUXFSYNCIO|HPUXFREMOTE|FUSECACHE); | |
257 | break; | |
258 | case F_GETFL: | |
259 | case F_DUPFD: | |
260 | case F_GETFD: | |
261 | case F_SETFD: | |
262 | break; | |
263 | default: | |
196c0567 | 264 | return (EINVAL); |
a8fd2d0d | 265 | } |
d9bd2b96 MH |
266 | error = fcntl(p, uap, retval); |
267 | if (error == 0 && uap->arg == F_GETFL) { | |
268 | mode = *retval; | |
269 | *retval &= ~(FCREAT|FTRUNC|FEXCL|FUSECACHE); | |
a8fd2d0d | 270 | if (mode & FCREAT) |
d9bd2b96 | 271 | *retval |= HPUXFCREAT; |
a8fd2d0d | 272 | if (mode & FTRUNC) |
d9bd2b96 | 273 | *retval |= HPUXFTRUNC; |
a8fd2d0d | 274 | if (mode & FEXCL) |
d9bd2b96 | 275 | *retval |= HPUXFEXCL; |
a8fd2d0d | 276 | } |
196c0567 | 277 | return (error); |
a8fd2d0d KM |
278 | } |
279 | ||
280 | /* | |
281 | * Read and write should return a 0 count when an operation | |
282 | * on a VNODE would block, not an error. Sockets appear to | |
283 | * return EWOULDBLOCK (at least in 6.2). This is probably | |
284 | * not entirely correct, since the behavior is only defined | |
285 | * for pipes and tty type devices. | |
286 | */ | |
d9bd2b96 MH |
287 | hpuxread(p, uap, retval) |
288 | struct proc *p; | |
289 | struct args { | |
a8fd2d0d | 290 | int fd; |
d9bd2b96 MH |
291 | } *uap; |
292 | int *retval; | |
293 | { | |
294 | int error; | |
a8fd2d0d | 295 | |
d9bd2b96 MH |
296 | error = read(p, uap, retval); |
297 | if (error == EWOULDBLOCK && | |
a8fd2d0d | 298 | u.u_ofile[uap->fd]->f_type == DTYPE_VNODE) { |
d9bd2b96 MH |
299 | error = 0; |
300 | *retval = 0; | |
a8fd2d0d | 301 | } |
196c0567 | 302 | return (error); |
a8fd2d0d KM |
303 | } |
304 | ||
d9bd2b96 MH |
305 | hpuxwrite(p, uap, retval) |
306 | struct proc *p; | |
307 | struct args { | |
a8fd2d0d | 308 | int fd; |
d9bd2b96 MH |
309 | } *uap; |
310 | int *retval; | |
311 | { | |
312 | int error; | |
a8fd2d0d | 313 | |
d9bd2b96 MH |
314 | error = write(p, uap, retval); |
315 | if (error == EWOULDBLOCK && | |
a8fd2d0d | 316 | u.u_ofile[uap->fd]->f_type == DTYPE_VNODE) { |
d9bd2b96 MH |
317 | error = 0; |
318 | *retval = 0; | |
a8fd2d0d | 319 | } |
196c0567 | 320 | return (error); |
a8fd2d0d KM |
321 | } |
322 | ||
d9bd2b96 MH |
323 | hpuxreadv(p, uap, retval) |
324 | struct proc *p; | |
325 | struct args { | |
a8fd2d0d | 326 | int fd; |
d9bd2b96 MH |
327 | } *uap; |
328 | int *retval; | |
329 | { | |
330 | int error; | |
a8fd2d0d | 331 | |
d9bd2b96 MH |
332 | error = readv(p, uap, retval); |
333 | if (error == EWOULDBLOCK && | |
a8fd2d0d | 334 | u.u_ofile[uap->fd]->f_type == DTYPE_VNODE) { |
d9bd2b96 MH |
335 | error = 0; |
336 | *retval = 0; | |
a8fd2d0d | 337 | } |
196c0567 | 338 | return (error); |
a8fd2d0d KM |
339 | } |
340 | ||
d9bd2b96 MH |
341 | hpuxwritev(p, uap, retval) |
342 | struct proc *p; | |
343 | struct args { | |
a8fd2d0d | 344 | int fd; |
d9bd2b96 MH |
345 | } *uap; |
346 | int *retval; | |
347 | { | |
348 | int error; | |
a8fd2d0d | 349 | |
d9bd2b96 MH |
350 | error = writev(p, uap, retval); |
351 | if (error == EWOULDBLOCK && | |
a8fd2d0d | 352 | u.u_ofile[uap->fd]->f_type == DTYPE_VNODE) { |
d9bd2b96 MH |
353 | error = 0; |
354 | *retval = 0; | |
a8fd2d0d | 355 | } |
196c0567 | 356 | return (error); |
a8fd2d0d KM |
357 | } |
358 | ||
359 | /* | |
360 | * 4.3bsd dup allows dup2 to come in on the same syscall entry | |
361 | * and hence allows two arguments. HPUX dup has only one arg. | |
362 | */ | |
d9bd2b96 MH |
363 | hpuxdup(p, uap, retval) |
364 | struct proc *p; | |
365 | register struct args { | |
a8fd2d0d | 366 | int i; |
d9bd2b96 MH |
367 | } *uap; |
368 | int *retval; | |
369 | { | |
a8fd2d0d | 370 | struct file *fp; |
d9bd2b96 MH |
371 | int fd, error; |
372 | ||
373 | if ((unsigned)uap->i >= NOFILE || (fp = u.u_ofile[uap->i]) == NULL) | |
196c0567 | 374 | return (EBADF); |
d9bd2b96 | 375 | if (error = ufalloc(0, &fd)) |
196c0567 | 376 | return (error); |
d9bd2b96 MH |
377 | *retval = fd; |
378 | u.u_ofile[fd] = fp; | |
379 | u.u_pofile[fd] = u.u_pofile[uap->i] &~ UF_EXCLOSE; | |
43af3a95 | 380 | fp->f_count++; |
d9bd2b96 MH |
381 | if (fd > u.u_lastfile) |
382 | u.u_lastfile = fd; | |
196c0567 | 383 | return (0); |
a8fd2d0d KM |
384 | } |
385 | ||
22d09b27 | 386 | hpuxutssys(p, uap, retval) |
d9bd2b96 MH |
387 | struct proc *p; |
388 | register struct args { | |
a8fd2d0d KM |
389 | struct hpuxutsname *uts; |
390 | int dev; | |
391 | int request; | |
d9bd2b96 MH |
392 | } *uap; |
393 | int *retval; | |
394 | { | |
a8fd2d0d | 395 | register int i; |
d9bd2b96 | 396 | int error; |
a8fd2d0d KM |
397 | |
398 | switch (uap->request) { | |
399 | /* uname */ | |
400 | case 0: | |
401 | /* fill in machine type */ | |
402 | switch (machineid) { | |
403 | case HP_320: | |
404 | protoutsname.machine[6] = '2'; | |
405 | break; | |
406 | /* includes 318 and 319 */ | |
407 | case HP_330: | |
408 | protoutsname.machine[6] = '3'; | |
409 | break; | |
410 | case HP_340: | |
411 | protoutsname.machine[6] = '4'; | |
412 | break; | |
413 | case HP_350: | |
414 | protoutsname.machine[6] = '5'; | |
415 | break; | |
416 | case HP_360: | |
417 | protoutsname.machine[6] = '6'; | |
418 | break; | |
419 | case HP_370: | |
420 | protoutsname.machine[6] = '7'; | |
421 | break; | |
d9bd2b96 MH |
422 | /* includes 345 */ |
423 | case HP_375: | |
424 | protoutsname.machine[6] = '7'; | |
425 | protoutsname.machine[7] = '5'; | |
426 | break; | |
a8fd2d0d KM |
427 | } |
428 | /* copy hostname (sans domain) to nodename */ | |
429 | for (i = 0; i < 9 && hostname[i] != '.'; i++) | |
430 | protoutsname.nodename[i] = hostname[i]; | |
d9bd2b96 MH |
431 | error = copyout((caddr_t)&protoutsname, (caddr_t)uap->uts, |
432 | sizeof(struct hpuxutsname)); | |
a8fd2d0d | 433 | break; |
22d09b27 KM |
434 | |
435 | /* gethostname */ | |
436 | case 5: | |
437 | /* uap->dev is length */ | |
438 | if (uap->dev > hostnamelen + 1) | |
439 | uap->dev = hostnamelen + 1; | |
440 | error = copyout((caddr_t)hostname, (caddr_t)uap->uts, | |
441 | uap->dev); | |
442 | break; | |
443 | ||
444 | case 1: /* ?? */ | |
445 | case 2: /* ustat */ | |
446 | case 3: /* ?? */ | |
447 | case 4: /* sethostname */ | |
a8fd2d0d | 448 | default: |
d9bd2b96 | 449 | error = EINVAL; |
a8fd2d0d KM |
450 | break; |
451 | } | |
196c0567 | 452 | return (error); |
a8fd2d0d KM |
453 | } |
454 | ||
d9bd2b96 MH |
455 | hpuxstat(p, uap, retval) |
456 | struct proc *p; | |
457 | struct args { | |
a8fd2d0d KM |
458 | char *fname; |
459 | struct hpuxstat *hsb; | |
d9bd2b96 MH |
460 | } *uap; |
461 | int *retval; | |
462 | { | |
196c0567 | 463 | return (hpuxstat1(uap->fname, uap->hsb, FOLLOW)); |
a8fd2d0d KM |
464 | } |
465 | ||
d9bd2b96 MH |
466 | hpuxlstat(p, uap, retval) |
467 | struct proc *p; | |
468 | struct args { | |
a8fd2d0d | 469 | char *fname; |
d9bd2b96 MH |
470 | struct hpuxstat *hsb; |
471 | } *uap; | |
472 | int *retval; | |
473 | { | |
196c0567 | 474 | return (hpuxstat1(uap->fname, uap->hsb, NOFOLLOW)); |
a8fd2d0d KM |
475 | } |
476 | ||
d9bd2b96 MH |
477 | hpuxfstat(p, uap, retval) |
478 | struct proc *p; | |
479 | register struct args { | |
a8fd2d0d KM |
480 | int fdes; |
481 | struct hpuxstat *hsb; | |
d9bd2b96 MH |
482 | } *uap; |
483 | int *retval; | |
484 | { | |
485 | register struct file *fp; | |
a8fd2d0d | 486 | struct stat sb; |
d9bd2b96 | 487 | int error; |
a8fd2d0d KM |
488 | |
489 | if ((unsigned)uap->fdes >= NOFILE || | |
d9bd2b96 | 490 | (fp = u.u_ofile[uap->fdes]) == NULL) |
196c0567 | 491 | return (EBADF); |
d9bd2b96 | 492 | |
a8fd2d0d KM |
493 | switch (fp->f_type) { |
494 | ||
495 | case DTYPE_VNODE: | |
d9bd2b96 | 496 | error = vn_stat((struct vnode *)fp->f_data, &sb); |
a8fd2d0d KM |
497 | break; |
498 | ||
499 | case DTYPE_SOCKET: | |
d9bd2b96 | 500 | error = soo_stat((struct socket *)fp->f_data, &sb); |
a8fd2d0d KM |
501 | break; |
502 | ||
503 | default: | |
504 | panic("fstat"); | |
505 | /*NOTREACHED*/ | |
506 | } | |
507 | /* is this right for sockets?? */ | |
d9bd2b96 MH |
508 | if (error == 0) |
509 | error = bsdtohpuxstat(&sb, uap->hsb); | |
196c0567 | 510 | return (error); |
a8fd2d0d KM |
511 | } |
512 | ||
d9bd2b96 MH |
513 | hpuxulimit(p, uap, retval) |
514 | struct proc *p; | |
515 | register struct args { | |
a8fd2d0d KM |
516 | int cmd; |
517 | long newlimit; | |
d9bd2b96 | 518 | } *uap; |
3e6066b0 | 519 | off_t *retval; |
d9bd2b96 | 520 | { |
a8fd2d0d | 521 | struct rlimit *limp; |
d9bd2b96 | 522 | int error = 0; |
a8fd2d0d KM |
523 | |
524 | limp = &u.u_rlimit[RLIMIT_FSIZE]; | |
525 | switch (uap->cmd) { | |
526 | case 2: | |
527 | uap->newlimit *= 512; | |
528 | if (uap->newlimit > limp->rlim_max && | |
d9bd2b96 | 529 | (error = suser(u.u_cred, &u.u_acflag))) |
a8fd2d0d KM |
530 | break; |
531 | limp->rlim_cur = limp->rlim_max = uap->newlimit; | |
532 | /* else fall into... */ | |
533 | ||
534 | case 1: | |
22d09b27 | 535 | *retval = limp->rlim_max / 512; |
a8fd2d0d KM |
536 | break; |
537 | ||
538 | case 3: | |
539 | limp = &u.u_rlimit[RLIMIT_DATA]; | |
22d09b27 | 540 | *retval = ctob(u.u_tsize) + limp->rlim_max; |
a8fd2d0d KM |
541 | break; |
542 | ||
543 | default: | |
d9bd2b96 | 544 | error = EINVAL; |
a8fd2d0d KM |
545 | break; |
546 | } | |
196c0567 | 547 | return (error); |
a8fd2d0d KM |
548 | } |
549 | ||
550 | /* | |
551 | * Map "real time" priorities 0 (high) thru 127 (low) into nice | |
552 | * values -16 (high) thru -1 (low). | |
553 | */ | |
d9bd2b96 MH |
554 | hpuxrtprio(cp, uap, retval) |
555 | struct proc *cp; | |
556 | register struct args { | |
a8fd2d0d KM |
557 | int pid; |
558 | int prio; | |
d9bd2b96 MH |
559 | } *uap; |
560 | int *retval; | |
561 | { | |
a8fd2d0d | 562 | struct proc *p; |
d9bd2b96 | 563 | int nice, error; |
a8fd2d0d KM |
564 | |
565 | if (uap->prio < RTPRIO_MIN && uap->prio > RTPRIO_MAX && | |
d9bd2b96 | 566 | uap->prio != RTPRIO_NOCHG && uap->prio != RTPRIO_RTOFF) |
196c0567 | 567 | return (EINVAL); |
a8fd2d0d | 568 | if (uap->pid == 0) |
d9bd2b96 MH |
569 | p = cp; |
570 | else if ((p = pfind(uap->pid)) == 0) | |
196c0567 | 571 | return (ESRCH); |
a8fd2d0d KM |
572 | nice = p->p_nice; |
573 | if (nice < NZERO) | |
d9bd2b96 | 574 | *retval = (nice + 16) << 3; |
a8fd2d0d | 575 | else |
d9bd2b96 | 576 | *retval = RTPRIO_RTOFF; |
a8fd2d0d KM |
577 | switch (uap->prio) { |
578 | ||
579 | case RTPRIO_NOCHG: | |
196c0567 | 580 | return (0); |
a8fd2d0d KM |
581 | |
582 | case RTPRIO_RTOFF: | |
583 | if (nice >= NZERO) | |
196c0567 | 584 | return (0); |
a8fd2d0d KM |
585 | nice = NZERO; |
586 | break; | |
587 | ||
588 | default: | |
589 | nice = (uap->prio >> 3) - 16; | |
590 | break; | |
591 | } | |
d9bd2b96 MH |
592 | error = donice(cp, p, nice); |
593 | if (error == EACCES) | |
594 | error = EPERM; | |
196c0567 | 595 | return (error); |
a8fd2d0d KM |
596 | } |
597 | ||
d9bd2b96 MH |
598 | hpuxadvise(p, uap, retval) |
599 | struct proc *p; | |
600 | struct args { | |
a8fd2d0d | 601 | int arg; |
d9bd2b96 MH |
602 | } *uap; |
603 | int *retval; | |
604 | { | |
605 | int error = 0; | |
a8fd2d0d KM |
606 | |
607 | switch (uap->arg) { | |
608 | case 0: | |
609 | u.u_pcb.pcb_flags |= PCB_HPUXMMAP; | |
610 | break; | |
611 | case 1: | |
612 | ICIA(); | |
613 | break; | |
614 | case 2: | |
615 | DCIA(); | |
616 | break; | |
617 | default: | |
d9bd2b96 | 618 | error = EINVAL; |
a8fd2d0d KM |
619 | break; |
620 | } | |
196c0567 | 621 | return (error); |
a8fd2d0d KM |
622 | } |
623 | ||
d9bd2b96 MH |
624 | hpuxptrace(p, uap, retval) |
625 | struct proc *p; | |
626 | struct args { | |
a8fd2d0d KM |
627 | int req; |
628 | int pid; | |
629 | int *addr; | |
630 | int data; | |
d9bd2b96 MH |
631 | } *uap; |
632 | int *retval; | |
633 | { | |
634 | int error; | |
a8fd2d0d KM |
635 | |
636 | if (uap->req == PT_STEP || uap->req == PT_CONTINUE) { | |
637 | if (uap->data) { | |
638 | uap->data = hpuxtobsdsig(uap->data); | |
639 | if (uap->data == 0) | |
640 | uap->data = NSIG; | |
641 | } | |
642 | } | |
d9bd2b96 | 643 | error = ptrace(p, uap, retval); |
196c0567 | 644 | return (error); |
a8fd2d0d KM |
645 | } |
646 | ||
d9bd2b96 MH |
647 | hpuxgetdomainname(p, uap, retval) |
648 | struct proc *p; | |
649 | register struct args { | |
a8fd2d0d KM |
650 | char *domainname; |
651 | u_int len; | |
d9bd2b96 MH |
652 | } *uap; |
653 | int *retval; | |
654 | { | |
a8fd2d0d KM |
655 | if (uap->len > domainnamelen + 1) |
656 | uap->len = domainnamelen + 1; | |
196c0567 | 657 | return (copyout(domainname, uap->domainname, uap->len)); |
a8fd2d0d KM |
658 | } |
659 | ||
d9bd2b96 MH |
660 | hpuxsetdomainname(p, uap, retval) |
661 | struct proc *p; | |
662 | register struct args { | |
a8fd2d0d KM |
663 | char *domainname; |
664 | u_int len; | |
d9bd2b96 MH |
665 | } *uap; |
666 | int *retval; | |
667 | { | |
668 | int error; | |
a8fd2d0d | 669 | |
d9bd2b96 | 670 | if (error = suser(u.u_cred, &u.u_acflag)) |
196c0567 | 671 | return (error); |
d9bd2b96 | 672 | if (uap->len > sizeof (domainname) - 1) |
196c0567 | 673 | return (EINVAL); |
a8fd2d0d | 674 | domainnamelen = uap->len; |
d9bd2b96 | 675 | error = copyin(uap->domainname, domainname, uap->len); |
a8fd2d0d | 676 | domainname[domainnamelen] = 0; |
196c0567 | 677 | return (error); |
a8fd2d0d KM |
678 | } |
679 | ||
680 | #ifdef SYSVSHM | |
d9bd2b96 MH |
681 | hpuxshmat(p, uap, retval) |
682 | struct proc *p; | |
683 | int *uap, *retval; | |
a8fd2d0d | 684 | { |
196c0567 | 685 | return (shmat(p, uap, retval)); |
a8fd2d0d KM |
686 | } |
687 | ||
d9bd2b96 MH |
688 | hpuxshmctl(p, uap, retval) |
689 | struct proc *p; | |
690 | int *uap, *retval; | |
a8fd2d0d | 691 | { |
196c0567 | 692 | return (shmctl(p, uap, retval)); |
a8fd2d0d KM |
693 | } |
694 | ||
d9bd2b96 MH |
695 | hpuxshmdt(p, uap, retval) |
696 | struct proc *p; | |
697 | int *uap, *retval; | |
a8fd2d0d | 698 | { |
196c0567 | 699 | return (shmdt(p, uap, retval)); |
a8fd2d0d KM |
700 | } |
701 | ||
d9bd2b96 MH |
702 | hpuxshmget(p, uap, retval) |
703 | struct proc *p; | |
704 | int *uap, *retval; | |
a8fd2d0d | 705 | { |
196c0567 | 706 | return (shmget(p, uap, retval)); |
a8fd2d0d KM |
707 | } |
708 | #endif | |
709 | ||
710 | /* | |
711 | * Fake semaphore routines, just don't return an error. | |
712 | * Should be adequate for starbase to run. | |
713 | */ | |
d9bd2b96 MH |
714 | hpuxsemctl(p, uap, retval) |
715 | struct proc *p; | |
716 | struct args { | |
a8fd2d0d KM |
717 | int semid; |
718 | u_int semnum; | |
719 | int cmd; | |
720 | int arg; | |
d9bd2b96 MH |
721 | } *uap; |
722 | int *retval; | |
723 | { | |
a8fd2d0d | 724 | /* XXX: should do something here */ |
196c0567 | 725 | return (0); |
a8fd2d0d KM |
726 | } |
727 | ||
d9bd2b96 MH |
728 | hpuxsemget(p, uap, retval) |
729 | struct proc *p; | |
730 | struct args { | |
a8fd2d0d KM |
731 | key_t key; |
732 | int nsems; | |
733 | int semflg; | |
d9bd2b96 MH |
734 | } *uap; |
735 | int *retval; | |
736 | { | |
a8fd2d0d | 737 | /* XXX: should do something here */ |
196c0567 | 738 | return (0); |
a8fd2d0d KM |
739 | } |
740 | ||
d9bd2b96 MH |
741 | hpuxsemop(p, uap, retval) |
742 | struct proc *p; | |
743 | struct args { | |
a8fd2d0d KM |
744 | int semid; |
745 | struct sembuf *sops; | |
746 | u_int nsops; | |
d9bd2b96 MH |
747 | } *uap; |
748 | int *retval; | |
749 | { | |
a8fd2d0d | 750 | /* XXX: should do something here */ |
196c0567 | 751 | return (0); |
a8fd2d0d KM |
752 | } |
753 | ||
754 | /* convert from BSD to HPUX errno */ | |
755 | bsdtohpuxerrno(err) | |
756 | int err; | |
757 | { | |
758 | if (err < 0 || err >= NERR) | |
759 | return(BERR); | |
760 | return((int)bsdtohpuxerrnomap[err]); | |
761 | } | |
762 | ||
763 | hpuxstat1(fname, hsb, follow) | |
764 | char *fname; | |
765 | struct hpuxstat *hsb; | |
766 | int follow; | |
767 | { | |
768 | register struct nameidata *ndp = &u.u_nd; | |
769 | struct stat sb; | |
770 | int error; | |
771 | ||
772 | ndp->ni_nameiop = LOOKUP | LOCKLEAF | follow; | |
773 | ndp->ni_segflg = UIO_USERSPACE; | |
774 | ndp->ni_dirp = fname; | |
775 | if (error = namei(ndp)) | |
776 | return (error); | |
777 | error = vn_stat(ndp->ni_vp, &sb); | |
778 | vput(ndp->ni_vp); | |
779 | if (error == 0) | |
780 | error = bsdtohpuxstat(&sb, hsb); | |
781 | return (error); | |
782 | } | |
783 | ||
784 | #include "grf.h" | |
785 | ||
786 | bsdtohpuxstat(sb, hsb) | |
787 | struct stat *sb; | |
788 | struct hpuxstat *hsb; | |
789 | { | |
790 | struct hpuxstat ds; | |
791 | ||
792 | bzero((caddr_t)&ds, sizeof(ds)); | |
793 | ds.hst_dev = sb->st_dev; | |
794 | ds.hst_ino = (u_long)sb->st_ino; | |
795 | ds.hst_mode = sb->st_mode; | |
796 | ds.hst_nlink = sb->st_nlink; | |
797 | ds.hst_uid = (u_short)sb->st_uid; | |
798 | ds.hst_gid = (u_short)sb->st_gid; | |
799 | #if NGRF > 0 | |
800 | /* XXX: I don't want to talk about it... */ | |
801 | if ((sb->st_mode & S_IFMT) == S_IFCHR && major(sb->st_rdev) == 10) | |
802 | ds.hst_rdev = grfdevno(sb->st_rdev); | |
803 | else | |
804 | #endif | |
805 | ds.hst_rdev = bsdtohpuxdev(sb->st_rdev); | |
806 | ds.hst_size = sb->st_size; | |
807 | ds.hst_atime = sb->st_atime; | |
808 | ds.hst_mtime = sb->st_mtime; | |
809 | ds.hst_ctime = sb->st_ctime; | |
810 | ds.hst_blksize = sb->st_blksize; | |
811 | ds.hst_blocks = sb->st_blocks; | |
812 | return(copyout((caddr_t)&ds, (caddr_t)hsb, sizeof(ds))); | |
813 | } | |
814 | ||
815 | hpuxtobsdioctl(com) | |
816 | int com; | |
817 | { | |
818 | switch (com) { | |
819 | case HPUXTIOCSLTC: | |
820 | com = TIOCSLTC; break; | |
821 | case HPUXTIOCGLTC: | |
822 | com = TIOCGLTC; break; | |
823 | case HPUXTIOCSPGRP: | |
824 | com = TIOCSPGRP; break; | |
825 | case HPUXTIOCGPGRP: | |
826 | com = TIOCGPGRP; break; | |
827 | case HPUXTIOCLBIS: | |
828 | com = TIOCLBIS; break; | |
829 | case HPUXTIOCLBIC: | |
830 | com = TIOCLBIC; break; | |
831 | case HPUXTIOCLSET: | |
832 | com = TIOCLSET; break; | |
833 | case HPUXTIOCLGET: | |
834 | com = TIOCLGET; break; | |
835 | } | |
836 | return(com); | |
837 | } | |
838 | ||
839 | /* | |
840 | * HPUX ioctl system call. The differences here are: | |
841 | * IOC_IN also means IOC_VOID if the size portion is zero. | |
842 | * no FIOCLEX/FIONCLEX/FIONBIO/FIOASYNC/FIOGETOWN/FIOSETOWN | |
843 | * the sgttyb struct is 2 bytes longer | |
844 | */ | |
d9bd2b96 MH |
845 | hpuxioctl(p, uap, retval) |
846 | struct proc *p; | |
847 | register struct args { | |
a8fd2d0d KM |
848 | int fdes; |
849 | int cmd; | |
850 | caddr_t cmarg; | |
d9bd2b96 MH |
851 | } *uap; |
852 | int *retval; | |
853 | { | |
854 | register struct file *fp; | |
855 | register int com, error; | |
a8fd2d0d KM |
856 | register u_int size; |
857 | caddr_t memp = 0; | |
858 | #define STK_PARAMS 128 | |
859 | char stkbuf[STK_PARAMS]; | |
860 | caddr_t data = stkbuf; | |
861 | ||
862 | com = uap->cmd; | |
863 | ||
864 | /* XXX */ | |
d9bd2b96 | 865 | if (com == HPUXTIOCGETP || com == HPUXTIOCSETP) |
196c0567 | 866 | return (getsettty(uap->fdes, com, uap->cmarg)); |
a8fd2d0d KM |
867 | |
868 | if ((unsigned)uap->fdes >= NOFILE || | |
d9bd2b96 | 869 | (fp = u.u_ofile[uap->fdes]) == NULL) |
196c0567 | 870 | return (EBADF); |
d9bd2b96 | 871 | if ((fp->f_flag & (FREAD|FWRITE)) == 0) |
196c0567 | 872 | return (EBADF); |
a8fd2d0d KM |
873 | |
874 | /* | |
875 | * Interpret high order word to find | |
876 | * amount of data to be copied to/from the | |
877 | * user's address space. | |
878 | */ | |
879 | size = IOCPARM_LEN(com); | |
d9bd2b96 | 880 | if (size > IOCPARM_MAX) |
196c0567 | 881 | return (ENOTTY); |
a8fd2d0d | 882 | if (size > sizeof (stkbuf)) { |
d9bd2b96 | 883 | memp = (caddr_t)malloc((u_long)size, M_IOCTLOPS, M_WAITOK); |
a8fd2d0d KM |
884 | data = memp; |
885 | } | |
886 | if (com&IOC_IN) { | |
887 | if (size) { | |
d9bd2b96 MH |
888 | error = copyin(uap->cmarg, data, (u_int)size); |
889 | if (error) { | |
a8fd2d0d KM |
890 | if (memp) |
891 | free(memp, M_IOCTLOPS); | |
196c0567 | 892 | return (error); |
a8fd2d0d KM |
893 | } |
894 | } else | |
895 | *(caddr_t *)data = uap->cmarg; | |
896 | } else if ((com&IOC_OUT) && size) | |
897 | /* | |
d9bd2b96 MH |
898 | * Zero the buffer so the user always |
899 | * gets back something deterministic. | |
a8fd2d0d KM |
900 | */ |
901 | bzero(data, size); | |
902 | else if (com&IOC_VOID) | |
903 | *(caddr_t *)data = uap->cmarg; | |
904 | ||
905 | switch (com) { | |
906 | ||
907 | case HPUXTIOCCONS: | |
908 | *(int *)data = 1; | |
d9bd2b96 | 909 | error = (*fp->f_ops->fo_ioctl)(fp, TIOCCONS, data); |
a8fd2d0d KM |
910 | break; |
911 | ||
912 | /* BSD-style job control ioctls */ | |
913 | case HPUXTIOCLBIS: | |
914 | case HPUXTIOCLBIC: | |
915 | case HPUXTIOCLSET: | |
916 | *(int *)data &= HPUXLTOSTOP; | |
917 | if (*(int *)data & HPUXLTOSTOP) | |
918 | *(int *)data = LTOSTOP; | |
919 | /* fall into */ | |
920 | case HPUXTIOCLGET: | |
921 | case HPUXTIOCSLTC: | |
922 | case HPUXTIOCGLTC: | |
923 | case HPUXTIOCSPGRP: | |
924 | case HPUXTIOCGPGRP: | |
d9bd2b96 MH |
925 | error = (*fp->f_ops->fo_ioctl)(fp, hpuxtobsdioctl(com), data); |
926 | if (error == 0 && com == HPUXTIOCLGET) { | |
a8fd2d0d KM |
927 | *(int *)data &= LTOSTOP; |
928 | if (*(int *)data & LTOSTOP) | |
929 | *(int *)data = HPUXLTOSTOP; | |
930 | } | |
931 | break; | |
932 | ||
933 | /* SYS 5 termio */ | |
934 | case HPUXTCGETA: | |
935 | case HPUXTCSETA: | |
936 | case HPUXTCSETAW: | |
937 | case HPUXTCSETAF: | |
d9bd2b96 | 938 | error = hpuxtermio(fp, com, data); |
a8fd2d0d KM |
939 | break; |
940 | ||
941 | default: | |
d9bd2b96 | 942 | error = (*fp->f_ops->fo_ioctl)(fp, com, data); |
a8fd2d0d KM |
943 | break; |
944 | } | |
945 | /* | |
946 | * Copy any data to user, size was | |
947 | * already set and checked above. | |
948 | */ | |
d9bd2b96 MH |
949 | if (error == 0 && (com&IOC_OUT) && size) |
950 | error = copyout(data, uap->cmarg, (u_int)size); | |
a8fd2d0d KM |
951 | if (memp) |
952 | free(memp, M_IOCTLOPS); | |
196c0567 | 953 | return (error); |
a8fd2d0d KM |
954 | } |
955 | ||
956 | /* | |
957 | * Man page lies, behaviour here is based on observed behaviour. | |
958 | */ | |
d9bd2b96 MH |
959 | hpuxgetcontext(p, uap, retval) |
960 | struct proc *p; | |
961 | struct args { | |
a8fd2d0d KM |
962 | char *buf; |
963 | int len; | |
d9bd2b96 MH |
964 | } *uap; |
965 | int *retval; | |
966 | { | |
a8fd2d0d KM |
967 | int error = 0; |
968 | register int len; | |
969 | ||
970 | len = MIN(uap->len, sizeof(hpuxcontext)); | |
971 | if (len) | |
972 | error = copyout(hpuxcontext, uap->buf, (u_int)len); | |
d9bd2b96 MH |
973 | if (error == 0) |
974 | *retval = sizeof(hpuxcontext); | |
196c0567 | 975 | return (error); |
a8fd2d0d KM |
976 | } |
977 | ||
a8fd2d0d KM |
978 | /* |
979 | * This is the equivalent of BSD getpgrp but with more restrictions. | |
980 | * Note we do not check the real uid or "saved" uid. | |
981 | */ | |
d9bd2b96 MH |
982 | hpuxgetpgrp2(cp, uap, retval) |
983 | struct proc *cp; | |
984 | register struct args { | |
985 | int pid; | |
986 | } *uap; | |
987 | int *retval; | |
a8fd2d0d KM |
988 | { |
989 | register struct proc *p; | |
a8fd2d0d KM |
990 | |
991 | if (uap->pid == 0) | |
d9bd2b96 | 992 | uap->pid = cp->p_pid; |
a8fd2d0d | 993 | p = pfind(uap->pid); |
d9bd2b96 | 994 | if (p == 0) |
196c0567 | 995 | return (ESRCH); |
d9bd2b96 | 996 | if (u.u_uid && p->p_uid != u.u_uid && !inferior(p)) |
196c0567 | 997 | return (EPERM); |
d9bd2b96 | 998 | *retval = p->p_pgid; |
196c0567 | 999 | return (0); |
a8fd2d0d KM |
1000 | } |
1001 | ||
1002 | /* | |
1003 | * This is the equivalent of BSD setpgrp but with more restrictions. | |
1004 | * Note we do not check the real uid or "saved" uid or pgrp. | |
1005 | */ | |
d9bd2b96 MH |
1006 | hpuxsetpgrp2(p, uap, retval) |
1007 | struct proc *p; | |
1008 | struct args { | |
a8fd2d0d KM |
1009 | int pid; |
1010 | int pgrp; | |
d9bd2b96 MH |
1011 | } *uap; |
1012 | int *retval; | |
1013 | { | |
a8fd2d0d | 1014 | /* empirically determined */ |
d9bd2b96 | 1015 | if (uap->pgrp < 0 || uap->pgrp >= 30000) |
196c0567 MK |
1016 | return (EINVAL); |
1017 | return (setpgrp(p, uap, retval)); | |
a8fd2d0d KM |
1018 | } |
1019 | ||
22d09b27 KM |
1020 | /* |
1021 | * XXX Same as BSD setre[ug]id right now. Need to consider saved ids. | |
1022 | */ | |
1023 | hpuxsetresuid(p, uap, retval) | |
1024 | struct proc *p; | |
1025 | struct args { | |
1026 | int ruid; | |
1027 | int euid; | |
1028 | int suid; | |
1029 | } *uap; | |
1030 | int *retval; | |
1031 | { | |
1032 | return (osetreuid(p, uap, retval)); | |
1033 | } | |
1034 | ||
1035 | hpuxsetresgid(p, uap, retval) | |
1036 | struct proc *p; | |
1037 | struct args { | |
1038 | int rgid; | |
1039 | int egid; | |
1040 | int sgid; | |
1041 | } *uap; | |
1042 | int *retval; | |
1043 | { | |
1044 | return (osetregid(p, uap, retval)); | |
1045 | } | |
1046 | ||
1047 | /* | |
1048 | * XXX: simple recognition hack to see if we can make grmd work. | |
1049 | */ | |
1050 | hpuxlockf(p, uap, retval) | |
1051 | struct proc *p; | |
1052 | struct args { | |
1053 | int fd; | |
1054 | int func; | |
1055 | long size; | |
1056 | } *uap; | |
1057 | int *retval; | |
1058 | { | |
1059 | #ifdef DEBUG | |
1060 | log(LOG_DEBUG, "%d: lockf(%d, %d, %d)\n", | |
1061 | p->p_pid, uap->fd, uap->func, uap->size); | |
1062 | #endif | |
1063 | return (0); | |
1064 | } | |
1065 | ||
1066 | hpuxgetaccess(p, uap, retval) | |
1067 | register struct proc *p; | |
1068 | register struct args { | |
1069 | char *path; | |
1070 | int uid; | |
1071 | int ngroups; | |
1072 | int *gidset; | |
1073 | void *label; | |
1074 | void *privs; | |
1075 | } *uap; | |
1076 | int *retval; | |
1077 | { | |
1078 | struct nameidata *ndp = &u.u_nd; | |
1079 | int lgroups[NGROUPS]; | |
1080 | int error = 0; | |
1081 | register struct ucred *cred; | |
1082 | register struct vnode *vp; | |
1083 | ||
1084 | /* | |
1085 | * Build an appropriate credential structure | |
1086 | */ | |
1087 | cred = crdup(ndp->ni_cred); | |
1088 | switch (uap->uid) { | |
1089 | case 65502: /* UID_EUID */ | |
1090 | break; | |
1091 | case 65503: /* UID_RUID */ | |
1092 | cred->cr_uid = p->p_ruid; | |
1093 | break; | |
1094 | case 65504: /* UID_SUID */ | |
1095 | error = EINVAL; | |
1096 | break; | |
1097 | default: | |
1098 | if (uap->uid > 65504) | |
1099 | error = EINVAL; | |
1100 | cred->cr_uid = uap->uid; | |
1101 | break; | |
1102 | } | |
1103 | switch (uap->ngroups) { | |
1104 | case -1: /* NGROUPS_EGID */ | |
1105 | cred->cr_ngroups = 1; | |
1106 | break; | |
1107 | case -5: /* NGROUPS_EGID_SUPP */ | |
1108 | break; | |
1109 | case -2: /* NGROUPS_RGID */ | |
1110 | cred->cr_ngroups = 1; | |
1111 | cred->cr_gid = p->p_rgid; | |
1112 | break; | |
1113 | case -6: /* NGROUPS_RGID_SUPP */ | |
1114 | cred->cr_gid = p->p_rgid; | |
1115 | break; | |
1116 | case -3: /* NGROUPS_SGID */ | |
1117 | case -7: /* NGROUPS_SGID_SUPP */ | |
1118 | error = EINVAL; | |
1119 | break; | |
1120 | case -4: /* NGROUPS_SUPP */ | |
1121 | if (cred->cr_ngroups > 1) | |
1122 | cred->cr_gid = cred->cr_groups[1]; | |
1123 | else | |
1124 | error = EINVAL; | |
1125 | break; | |
1126 | default: | |
1127 | if (uap->ngroups > 0 && uap->ngroups <= NGROUPS) | |
1128 | error = copyin((caddr_t)uap->gidset, | |
1129 | (caddr_t)&lgroups[0], | |
1130 | uap->ngroups * sizeof(lgroups[0])); | |
1131 | else | |
1132 | error = EINVAL; | |
1133 | if (error == 0) { | |
1134 | int gid; | |
1135 | ||
1136 | for (gid = 0; gid < uap->ngroups; gid++) | |
1137 | cred->cr_groups[gid] = lgroups[gid]; | |
1138 | cred->cr_ngroups = uap->ngroups; | |
1139 | } | |
1140 | break; | |
1141 | } | |
1142 | /* | |
1143 | * Lookup file using caller's effective IDs. | |
1144 | */ | |
1145 | if (error == 0) { | |
1146 | ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; | |
1147 | ndp->ni_segflg = UIO_USERSPACE; | |
1148 | ndp->ni_dirp = uap->path; | |
1149 | error = namei(ndp); | |
1150 | } | |
1151 | if (error) { | |
1152 | crfree(cred); | |
1153 | return (error); | |
1154 | } | |
1155 | /* | |
1156 | * Use the constructed credentials for access checks. | |
1157 | */ | |
1158 | vp = ndp->ni_vp; | |
1159 | *retval = 0; | |
1160 | if (VOP_ACCESS(vp, VREAD, cred) == 0) | |
1161 | *retval |= R_OK; | |
1162 | if (vn_writechk(vp) == 0 && VOP_ACCESS(vp, VWRITE, cred) == 0) | |
1163 | *retval |= W_OK; | |
1164 | /* XXX we return X_OK for root on VREG even if not */ | |
1165 | if (VOP_ACCESS(vp, VEXEC, cred) == 0) | |
1166 | *retval |= X_OK; | |
1167 | vput(vp); | |
1168 | crfree(cred); | |
1169 | return (error); | |
1170 | } | |
1171 | ||
a8fd2d0d KM |
1172 | /* |
1173 | * Brutal hack! Map HPUX u-area offsets into BSD u offsets. | |
1174 | * No apologies offered, if you don't like it, rewrite it! | |
1175 | */ | |
1176 | ||
1177 | #define UOFF(f) ((int)&((struct user *)0)->f) | |
1178 | #define HPUOFF(f) ((int)&((struct hpuxuser *)0)->f) | |
1179 | ||
1180 | /* simplified FP structure */ | |
1181 | struct bsdfp { | |
1182 | int save[54]; | |
1183 | int reg[24]; | |
1184 | int ctrl[3]; | |
1185 | }; | |
1186 | ||
1187 | hpuxtobsduoff(off) | |
1188 | int *off; | |
1189 | { | |
1190 | struct hpuxfp *hp; | |
1191 | struct bsdfp *bp; | |
1192 | register u_int raddr; | |
1193 | ||
1194 | /* u_ar0 field */ | |
1195 | if ((int)off == HPUOFF(hpuxu_ar0)) | |
1196 | return(UOFF(u_ar0)); | |
1197 | ||
1198 | #ifdef FPCOPROC | |
1199 | /* 68881 registers from PCB */ | |
1200 | hp = (struct hpuxfp *)HPUOFF(hpuxu_fp); | |
1201 | bp = (struct bsdfp *)UOFF(u_pcb.pcb_fpregs); | |
1202 | if (off >= hp->hpfp_ctrl && off < &hp->hpfp_ctrl[3]) | |
1203 | return((int)&bp->ctrl[off - hp->hpfp_ctrl]); | |
1204 | if (off >= hp->hpfp_reg && off < &hp->hpfp_reg[24]) | |
1205 | return((int)&bp->reg[off - hp->hpfp_reg]); | |
1206 | #endif | |
1207 | ||
1208 | /* | |
1209 | * Everything else we recognize comes from the kernel stack, | |
1210 | * so we convert off to an absolute address (if not already) | |
1211 | * for simplicity. | |
1212 | */ | |
1213 | if (off < (int *)ctob(UPAGES)) | |
1214 | off = (int *)((u_int)off + (u_int)&u); | |
1215 | ||
1216 | /* | |
1217 | * 68020 registers. | |
1218 | * We know that the HPUX registers are in the same order as ours. | |
1219 | * The only difference is that their PS is 2 bytes instead of a | |
1220 | * padded 4 like ours throwing the alignment off. | |
1221 | */ | |
1222 | if (off >= u.u_ar0 && off < &u.u_ar0[18]) { | |
1223 | /* | |
1224 | * PS: return low word and high word of PC as HP-UX would | |
1225 | * (e.g. &u.u_ar0[16.5]). | |
1226 | */ | |
1227 | if (off == &u.u_ar0[PS]) | |
1228 | raddr = (u_int) &((short *)u.u_ar0)[PS*2+1]; | |
1229 | /* | |
1230 | * PC: off will be &u.u_ar0[16.5] | |
1231 | */ | |
1232 | else if (off == (int *)&(((short *)u.u_ar0)[PS*2+1])) | |
1233 | raddr = (u_int) &u.u_ar0[PC]; | |
1234 | /* | |
1235 | * D0-D7, A0-A7: easy | |
1236 | */ | |
1237 | else | |
1238 | raddr = (u_int) &u.u_ar0[(int)(off - u.u_ar0)]; | |
1239 | return((int)(raddr - (u_int)&u)); | |
1240 | } | |
1241 | ||
1242 | /* everything else */ | |
1243 | return(-1); | |
1244 | } | |
1245 | ||
1246 | /* | |
1247 | * Kludge up a uarea dump so that HPUX debuggers can find out | |
1248 | * what they need. IMPORTANT NOTE: we do not EVEN attempt to | |
1249 | * convert the entire user struct. | |
1250 | */ | |
1251 | hpuxdumpu(vp, cred) | |
1252 | struct vnode *vp; | |
1253 | struct ucred *cred; | |
1254 | { | |
1255 | int error; | |
1256 | struct hpuxuser *faku; | |
1257 | struct bsdfp *bp; | |
1258 | short *foop; | |
1259 | ||
1260 | faku = (struct hpuxuser *)malloc((u_long)ctob(1), M_TEMP, M_WAITOK); | |
1261 | /* | |
1262 | * Make sure there is no mistake about this | |
1263 | * being a real user structure. | |
1264 | */ | |
1265 | bzero((caddr_t)faku, ctob(1)); | |
1266 | /* | |
1267 | * Fill in the process sizes. | |
1268 | */ | |
1269 | faku->hpuxu_tsize = u.u_tsize; | |
1270 | faku->hpuxu_dsize = u.u_dsize; | |
1271 | faku->hpuxu_ssize = u.u_ssize; | |
1272 | /* | |
1273 | * Fill in the exec header for CDB. | |
1274 | * This was saved back in exec(). As far as I can tell CDB | |
1275 | * only uses this information to verify that a particular | |
1276 | * core file goes with a particular binary. | |
1277 | */ | |
1278 | bcopy((caddr_t)u.u_pcb.pcb_exec, | |
1279 | (caddr_t)&faku->hpuxu_exdata, sizeof (struct hpux_exec)); | |
1280 | /* | |
1281 | * Adjust user's saved registers (on kernel stack) to reflect | |
1282 | * HPUX order. Note that HPUX saves the SR as 2 bytes not 4 | |
1283 | * so we have to move it up. | |
1284 | */ | |
1285 | faku->hpuxu_ar0 = u.u_ar0; | |
1286 | foop = (short *) u.u_ar0; | |
1287 | foop[32] = foop[33]; | |
1288 | foop[33] = foop[34]; | |
1289 | foop[34] = foop[35]; | |
1290 | #ifdef FPCOPROC | |
1291 | /* | |
1292 | * Copy 68881 registers from our PCB format to HPUX format | |
1293 | */ | |
1294 | bp = (struct bsdfp *) &u.u_pcb.pcb_fpregs; | |
1295 | bcopy((caddr_t)bp->save, (caddr_t)faku->hpuxu_fp.hpfp_save, | |
1296 | sizeof(bp->save)); | |
1297 | bcopy((caddr_t)bp->ctrl, (caddr_t)faku->hpuxu_fp.hpfp_ctrl, | |
1298 | sizeof(bp->ctrl)); | |
1299 | bcopy((caddr_t)bp->reg, (caddr_t)faku->hpuxu_fp.hpfp_reg, | |
1300 | sizeof(bp->reg)); | |
1301 | #endif | |
1302 | /* | |
1303 | * Slay the dragon | |
1304 | */ | |
1305 | faku->hpuxu_dragon = -1; | |
1306 | /* | |
1307 | * Dump this artfully constructed page in place of the | |
1308 | * user struct page. | |
1309 | */ | |
1310 | error = vn_rdwr(UIO_WRITE, vp, | |
1311 | (caddr_t)faku, ctob(1), (off_t)0, | |
1312 | UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, cred, (int *)0); | |
1313 | /* | |
1314 | * Dump the remaining UPAGES-1 pages normally | |
1315 | */ | |
1316 | if (!error) | |
1317 | error = vn_rdwr(UIO_WRITE, vp, ((caddr_t)&u)+ctob(1), | |
1318 | ctob(UPAGES-1), (off_t)ctob(1), UIO_SYSSPACE, | |
1319 | IO_NODELOCKED|IO_UNIT, cred, (int *)0); | |
1320 | free((caddr_t)faku, M_TEMP); | |
1321 | return(error); | |
1322 | } | |
1323 | ||
1324 | /* | |
1325 | * The remaining routines are essentially the same as those in kern_xxx.c | |
1326 | * and vfs_xxx.c as defined under "#ifdef COMPAT". We replicate them here | |
1327 | * to avoid HPUXCOMPAT dependencies in those files and to make sure that | |
1328 | * HP-UX compatibility still works even when COMPAT is not defined. | |
1329 | */ | |
1330 | /* #ifdef COMPAT */ | |
1331 | ||
22d09b27 KM |
1332 | #define HPUX_HZ 50 |
1333 | ||
73db44b5 | 1334 | #include "../sys/times.h" |
a8fd2d0d KM |
1335 | |
1336 | /* from old timeb.h */ | |
1337 | struct hpuxtimeb { | |
1338 | time_t time; | |
1339 | u_short millitm; | |
1340 | short timezone; | |
1341 | short dstflag; | |
1342 | }; | |
1343 | ||
1344 | /* ye ole stat structure */ | |
1345 | struct ohpuxstat { | |
1346 | dev_t ohst_dev; | |
1347 | u_short ohst_ino; | |
1348 | u_short ohst_mode; | |
1349 | short ohst_nlink; | |
1350 | short ohst_uid; | |
1351 | short ohst_gid; | |
1352 | dev_t ohst_rdev; | |
1353 | int ohst_size; | |
1354 | int ohst_atime; | |
1355 | int ohst_mtime; | |
1356 | int ohst_ctime; | |
1357 | }; | |
1358 | ||
a8fd2d0d KM |
1359 | /* |
1360 | * SYS V style setpgrp() | |
1361 | */ | |
d9bd2b96 MH |
1362 | ohpuxsetpgrp(p, uap, retval) |
1363 | register struct proc *p; | |
1364 | int *uap, *retval; | |
a8fd2d0d | 1365 | { |
a8fd2d0d KM |
1366 | if (p->p_pid != p->p_pgid) |
1367 | pgmv(p, p->p_pid, 0); | |
d9bd2b96 | 1368 | *retval = p->p_pgid; |
22d09b27 | 1369 | return (0); |
a8fd2d0d KM |
1370 | } |
1371 | ||
d9bd2b96 MH |
1372 | ohpuxtime(p, uap, retval) |
1373 | struct proc *p; | |
1374 | register struct args { | |
a8fd2d0d | 1375 | long *tp; |
d9bd2b96 | 1376 | } *uap; |
3e6066b0 | 1377 | time_t *retval; |
d9bd2b96 | 1378 | { |
22d09b27 | 1379 | int error = 0; |
a8fd2d0d KM |
1380 | |
1381 | if (uap->tp) | |
d9bd2b96 MH |
1382 | error = copyout((caddr_t)&time.tv_sec, (caddr_t)uap->tp, |
1383 | sizeof (long)); | |
22d09b27 | 1384 | *retval = time.tv_sec; |
196c0567 | 1385 | return (error); |
a8fd2d0d KM |
1386 | } |
1387 | ||
d9bd2b96 MH |
1388 | ohpuxstime(p, uap, retval) |
1389 | struct proc *p; | |
1390 | register struct args { | |
a8fd2d0d | 1391 | int time; |
d9bd2b96 MH |
1392 | } *uap; |
1393 | int *retval; | |
1394 | { | |
a8fd2d0d | 1395 | struct timeval tv; |
d9bd2b96 | 1396 | int s, error; |
a8fd2d0d KM |
1397 | |
1398 | tv.tv_sec = uap->time; | |
1399 | tv.tv_usec = 0; | |
d9bd2b96 | 1400 | if (error = suser(u.u_cred, &u.u_acflag)) |
196c0567 | 1401 | return (error); |
a8fd2d0d KM |
1402 | |
1403 | /* WHAT DO WE DO ABOUT PENDING REAL-TIME TIMEOUTS??? */ | |
1404 | boottime.tv_sec += tv.tv_sec - time.tv_sec; | |
1405 | s = splhigh(); time = tv; splx(s); | |
1406 | resettodr(); | |
196c0567 | 1407 | return (0); |
a8fd2d0d KM |
1408 | } |
1409 | ||
d9bd2b96 MH |
1410 | ohpuxftime(p, uap, retval) |
1411 | struct proc *p; | |
1412 | register struct args { | |
a8fd2d0d KM |
1413 | struct hpuxtimeb *tp; |
1414 | } *uap; | |
d9bd2b96 MH |
1415 | int *retval; |
1416 | { | |
a8fd2d0d KM |
1417 | struct hpuxtimeb tb; |
1418 | int s; | |
1419 | ||
a8fd2d0d KM |
1420 | s = splhigh(); |
1421 | tb.time = time.tv_sec; | |
1422 | tb.millitm = time.tv_usec / 1000; | |
1423 | splx(s); | |
1424 | tb.timezone = tz.tz_minuteswest; | |
1425 | tb.dstflag = tz.tz_dsttime; | |
196c0567 | 1426 | return (copyout((caddr_t)&tb, (caddr_t)uap->tp, sizeof (tb))); |
a8fd2d0d KM |
1427 | } |
1428 | ||
d9bd2b96 MH |
1429 | ohpuxalarm(p, uap, retval) |
1430 | register struct proc *p; | |
1431 | register struct args { | |
a8fd2d0d | 1432 | int deltat; |
d9bd2b96 MH |
1433 | } *uap; |
1434 | int *retval; | |
1435 | { | |
a8fd2d0d KM |
1436 | int s = splhigh(); |
1437 | ||
1438 | untimeout(realitexpire, (caddr_t)p); | |
1439 | timerclear(&p->p_realtimer.it_interval); | |
d9bd2b96 | 1440 | *retval = 0; |
a8fd2d0d KM |
1441 | if (timerisset(&p->p_realtimer.it_value) && |
1442 | timercmp(&p->p_realtimer.it_value, &time, >)) | |
d9bd2b96 | 1443 | *retval = p->p_realtimer.it_value.tv_sec - time.tv_sec; |
a8fd2d0d KM |
1444 | if (uap->deltat == 0) { |
1445 | timerclear(&p->p_realtimer.it_value); | |
1446 | splx(s); | |
196c0567 | 1447 | return (0); |
a8fd2d0d KM |
1448 | } |
1449 | p->p_realtimer.it_value = time; | |
1450 | p->p_realtimer.it_value.tv_sec += uap->deltat; | |
1451 | timeout(realitexpire, (caddr_t)p, hzto(&p->p_realtimer.it_value)); | |
1452 | splx(s); | |
196c0567 | 1453 | return (0); |
a8fd2d0d KM |
1454 | } |
1455 | ||
d9bd2b96 MH |
1456 | ohpuxnice(p, uap, retval) |
1457 | register struct proc *p; | |
1458 | register struct args { | |
a8fd2d0d | 1459 | int niceness; |
d9bd2b96 MH |
1460 | } *uap; |
1461 | int *retval; | |
1462 | { | |
1463 | int error; | |
a8fd2d0d | 1464 | |
d9bd2b96 MH |
1465 | error = donice(p, p, (p->p_nice-NZERO)+uap->niceness); |
1466 | if (error == 0) | |
1467 | *retval = p->p_nice - NZERO; | |
196c0567 | 1468 | return (error); |
a8fd2d0d KM |
1469 | } |
1470 | ||
d9bd2b96 MH |
1471 | ohpuxtimes(p, uap, retval) |
1472 | struct proc *p; | |
1473 | register struct args { | |
a8fd2d0d | 1474 | struct tms *tmsb; |
d9bd2b96 | 1475 | } *uap; |
3e6066b0 | 1476 | time_t *retval; |
d9bd2b96 | 1477 | { |
a8fd2d0d | 1478 | struct tms atms; |
d9bd2b96 | 1479 | int error; |
a8fd2d0d | 1480 | |
22d09b27 KM |
1481 | atms.tms_utime = hpuxscale(&u.u_ru.ru_utime); |
1482 | atms.tms_stime = hpuxscale(&u.u_ru.ru_stime); | |
1483 | atms.tms_cutime = hpuxscale(&u.u_cru.ru_utime); | |
1484 | atms.tms_cstime = hpuxscale(&u.u_cru.ru_stime); | |
d9bd2b96 MH |
1485 | error = copyout((caddr_t)&atms, (caddr_t)uap->tmsb, sizeof (atms)); |
1486 | if (error == 0) | |
22d09b27 | 1487 | *retval = hpuxscale(&time) - hpuxscale(&boottime); |
196c0567 | 1488 | return (error); |
a8fd2d0d KM |
1489 | } |
1490 | ||
22d09b27 KM |
1491 | /* |
1492 | * Doesn't exactly do what the documentation says. | |
1493 | * What we really do is return 1/HPUX_HZ-th of a second since that | |
1494 | * is what HP-UX returns. | |
1495 | */ | |
1496 | hpuxscale(tvp) | |
a8fd2d0d KM |
1497 | register struct timeval *tvp; |
1498 | { | |
22d09b27 | 1499 | return (tvp->tv_sec * HPUX_HZ + tvp->tv_usec * HPUX_HZ / 1000000); |
a8fd2d0d KM |
1500 | } |
1501 | ||
1502 | /* | |
1503 | * Set IUPD and IACC times on file. | |
1504 | * Can't set ICHG. | |
1505 | */ | |
d9bd2b96 MH |
1506 | ohpuxutime(p, uap, retval) |
1507 | struct proc *p; | |
a8fd2d0d KM |
1508 | register struct a { |
1509 | char *fname; | |
1510 | time_t *tptr; | |
d9bd2b96 MH |
1511 | } *uap; |
1512 | int *retval; | |
1513 | { | |
a8fd2d0d KM |
1514 | struct vattr vattr; |
1515 | time_t tv[2]; | |
1516 | register struct vnode *vp; | |
1517 | register struct nameidata *ndp = &u.u_nd; | |
d9bd2b96 | 1518 | int error; |
a8fd2d0d KM |
1519 | |
1520 | if (uap->tptr) { | |
d9bd2b96 MH |
1521 | error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)); |
1522 | if (error) | |
196c0567 | 1523 | return (error); |
a8fd2d0d KM |
1524 | } else |
1525 | tv[0] = tv[1] = time.tv_sec; | |
1526 | ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; | |
1527 | ndp->ni_segflg = UIO_USERSPACE; | |
1528 | ndp->ni_dirp = uap->fname; | |
1529 | vattr_null(&vattr); | |
1530 | vattr.va_atime.tv_sec = tv[0]; | |
1531 | vattr.va_atime.tv_usec = 0; | |
1532 | vattr.va_mtime.tv_sec = tv[1]; | |
1533 | vattr.va_mtime.tv_usec = 0; | |
d9bd2b96 | 1534 | if (error = namei(ndp)) |
196c0567 | 1535 | return (error); |
a8fd2d0d | 1536 | vp = ndp->ni_vp; |
870ebb91 | 1537 | if (vp->v_mount->mnt_flag & MNT_RDONLY) |
d9bd2b96 | 1538 | error = EROFS; |
a8fd2d0d | 1539 | else |
d9bd2b96 | 1540 | error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); |
a8fd2d0d | 1541 | vput(vp); |
196c0567 | 1542 | return (error); |
a8fd2d0d KM |
1543 | } |
1544 | ||
d9bd2b96 MH |
1545 | ohpuxpause(p, uap, retval) |
1546 | struct proc *p; | |
1547 | int *uap, *retval; | |
a8fd2d0d | 1548 | { |
09d98f88 MK |
1549 | (void) tsleep((caddr_t)&u, PPAUSE | PCATCH, "pause", 0); |
1550 | /* always return EINTR rather than ERESTART... */ | |
196c0567 | 1551 | return (EINTR); |
a8fd2d0d KM |
1552 | } |
1553 | ||
1554 | /* | |
1555 | * The old fstat system call. | |
1556 | */ | |
d9bd2b96 MH |
1557 | ohpuxfstat(p, uap, retval) |
1558 | struct proc *p; | |
1559 | register struct args { | |
a8fd2d0d KM |
1560 | int fd; |
1561 | struct ohpuxstat *sb; | |
d9bd2b96 MH |
1562 | } *uap; |
1563 | int *retval; | |
1564 | { | |
a8fd2d0d | 1565 | struct file *fp; |
a8fd2d0d | 1566 | |
d9bd2b96 | 1567 | if ((unsigned)uap->fd >= NOFILE || (fp = u.u_ofile[uap->fd]) == NULL) |
196c0567 | 1568 | return (EBADF); |
d9bd2b96 | 1569 | if (fp->f_type != DTYPE_VNODE) |
196c0567 MK |
1570 | return (EINVAL); |
1571 | return (ohpuxstat1((struct vnode *)fp->f_data, uap->sb)); | |
a8fd2d0d KM |
1572 | } |
1573 | ||
1574 | /* | |
1575 | * Old stat system call. This version follows links. | |
1576 | */ | |
d9bd2b96 MH |
1577 | ohpuxstat(p, uap, retval) |
1578 | struct proc *p; | |
1579 | register struct args { | |
a8fd2d0d KM |
1580 | char *fname; |
1581 | struct ohpuxstat *sb; | |
d9bd2b96 MH |
1582 | } *uap; |
1583 | int *retval; | |
1584 | { | |
a8fd2d0d | 1585 | register struct nameidata *ndp = &u.u_nd; |
d9bd2b96 | 1586 | int error; |
a8fd2d0d KM |
1587 | |
1588 | ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW; | |
1589 | ndp->ni_segflg = UIO_USERSPACE; | |
1590 | ndp->ni_dirp = uap->fname; | |
d9bd2b96 | 1591 | if (error = namei(ndp)) |
196c0567 | 1592 | return (error); |
d9bd2b96 | 1593 | error = ohpuxstat1(ndp->ni_vp, uap->sb); |
a8fd2d0d | 1594 | vput(ndp->ni_vp); |
196c0567 | 1595 | return (error); |
a8fd2d0d KM |
1596 | } |
1597 | ||
1598 | int | |
1599 | ohpuxstat1(vp, ub) | |
1600 | register struct vnode *vp; | |
1601 | struct ohpuxstat *ub; | |
1602 | { | |
1603 | struct ohpuxstat ds; | |
1604 | struct vattr vattr; | |
1605 | register int error; | |
1606 | ||
1607 | error = VOP_GETATTR(vp, &vattr, u.u_cred); | |
1608 | if (error) | |
1609 | return(error); | |
1610 | /* | |
1611 | * Copy from inode table | |
1612 | */ | |
1613 | ds.ohst_dev = vattr.va_fsid; | |
1614 | ds.ohst_ino = (short)vattr.va_fileid; | |
1615 | ds.ohst_mode = (u_short)vattr.va_mode; | |
1616 | ds.ohst_nlink = vattr.va_nlink; | |
1617 | ds.ohst_uid = (short)vattr.va_uid; | |
1618 | ds.ohst_gid = (short)vattr.va_gid; | |
1619 | ds.ohst_rdev = (dev_t)vattr.va_rdev; | |
1620 | ds.ohst_size = (int)vattr.va_size; | |
1621 | ds.ohst_atime = (int)vattr.va_atime.tv_sec; | |
1622 | ds.ohst_mtime = (int)vattr.va_mtime.tv_sec; | |
1623 | ds.ohst_ctime = (int)vattr.va_ctime.tv_sec; | |
1624 | return (copyout((caddr_t)&ds, (caddr_t)ub, sizeof(ds))); | |
1625 | } | |
1626 | /* #endif */ | |
1627 | ||
1628 | #endif |