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