linux_misc_notalpha.c revision 1.56 1 /* $NetBSD: linux_misc_notalpha.c,v 1.56 2000/07/13 17:32:51 thorpej Exp $ */
2
3 /*-
4 * Copyright (c) 1995, 1998 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Frank van der Linden and Eric Haszlakiewicz; by Jason R. Thorpe
9 * of the Numerical Aerospace Simulation Facility, NASA Ames Research Center.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the NetBSD
22 * Foundation, Inc. and its contributors.
23 * 4. Neither the name of The NetBSD Foundation nor the names of its
24 * contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/kernel.h>
43 #include <sys/mman.h>
44 #include <sys/mount.h>
45 #include <sys/malloc.h>
46 #include <sys/mbuf.h>
47 #include <sys/namei.h>
48 #include <sys/ptrace.h>
49 #include <sys/resource.h>
50 #include <sys/resourcevar.h>
51 #include <sys/wait.h>
52
53 #include <sys/syscallargs.h>
54
55 #include <compat/linux/common/linux_types.h>
56 #include <compat/linux/common/linux_fcntl.h>
57 #include <compat/linux/common/linux_misc.h>
58 #include <compat/linux/common/linux_mmap.h>
59 #include <compat/linux/common/linux_signal.h>
60 #include <compat/linux/common/linux_util.h>
61
62 #include <compat/linux/linux_syscallargs.h>
63
64 /*
65 * This file contains routines which are used
66 * on every linux architechture except the Alpha.
67 */
68
69 /* Used on: arm, i386, m68k, mips, ppc, sparc, sparc64 */
70 /* Not used on: alpha */
71
72 /*
73 * Alarm. This is a libc call which uses setitimer(2) in NetBSD.
74 * Fiddle with the timers to make it work.
75 */
76 int
77 linux_sys_alarm(p, v, retval)
78 struct proc *p;
79 void *v;
80 register_t *retval;
81 {
82 struct linux_sys_alarm_args /* {
83 syscallarg(unsigned int) secs;
84 } */ *uap = v;
85 int s;
86 struct itimerval *itp, it;
87
88 itp = &p->p_realtimer;
89 s = splclock();
90 /*
91 * Clear any pending timer alarms.
92 */
93 callout_stop(&p->p_realit_ch);
94 timerclear(&itp->it_interval);
95 if (timerisset(&itp->it_value) &&
96 timercmp(&itp->it_value, &time, >))
97 timersub(&itp->it_value, &time, &itp->it_value);
98 /*
99 * Return how many seconds were left (rounded up)
100 */
101 retval[0] = itp->it_value.tv_sec;
102 if (itp->it_value.tv_usec)
103 retval[0]++;
104
105 /*
106 * alarm(0) just resets the timer.
107 */
108 if (SCARG(uap, secs) == 0) {
109 timerclear(&itp->it_value);
110 splx(s);
111 return 0;
112 }
113
114 /*
115 * Check the new alarm time for sanity, and set it.
116 */
117 timerclear(&it.it_interval);
118 it.it_value.tv_sec = SCARG(uap, secs);
119 it.it_value.tv_usec = 0;
120 if (itimerfix(&it.it_value) || itimerfix(&it.it_interval)) {
121 splx(s);
122 return (EINVAL);
123 }
124
125 if (timerisset(&it.it_value)) {
126 /*
127 * Don't need to check hzto() return value, here.
128 * callout_reset() does it for us.
129 */
130 timeradd(&it.it_value, &time, &it.it_value);
131 callout_reset(&p->p_realit_ch, hzto(&it.it_value),
132 realitexpire, p);
133 }
134 p->p_realtimer = it;
135 splx(s);
136
137 return 0;
138 }
139
140 int
141 linux_sys_nice(p, v, retval)
142 struct proc *p;
143 void *v;
144 register_t *retval;
145 {
146 struct linux_sys_nice_args /* {
147 syscallarg(int) incr;
148 } */ *uap = v;
149 struct sys_setpriority_args bsa;
150
151 SCARG(&bsa, which) = PRIO_PROCESS;
152 SCARG(&bsa, who) = 0;
153 SCARG(&bsa, prio) = SCARG(uap, incr);
154 return sys_setpriority(p, &bsa, retval);
155 }
156
157 /*
158 * The old Linux readdir was only able to read one entry at a time,
159 * even though it had a 'count' argument. In fact, the emulation
160 * of the old call was better than the original, because it did handle
161 * the count arg properly. Don't bother with it anymore now, and use
162 * it to distinguish between old and new. The difference is that the
163 * newer one actually does multiple entries, and the reclen field
164 * really is the reclen, not the namelength.
165 */
166 int
167 linux_sys_readdir(p, v, retval)
168 struct proc *p;
169 void *v;
170 register_t *retval;
171 {
172 struct linux_sys_readdir_args /* {
173 syscallarg(int) fd;
174 syscallarg(struct linux_dirent *) dent;
175 syscallarg(unsigned int) count;
176 } */ *uap = v;
177
178 SCARG(uap, count) = 1;
179 return linux_sys_getdents(p, uap, retval);
180 }
181
182 /*
183 * I wonder why Linux has gettimeofday() _and_ time().. Still, we
184 * need to deal with it.
185 */
186 int
187 linux_sys_time(p, v, retval)
188 struct proc *p;
189 void *v;
190 register_t *retval;
191 {
192 struct linux_sys_time_args /* {
193 linux_time_t *t;
194 } */ *uap = v;
195 struct timeval atv;
196 linux_time_t tt;
197 int error;
198
199 microtime(&atv);
200
201 tt = atv.tv_sec;
202 if (SCARG(uap, t) && (error = copyout(&tt, SCARG(uap, t), sizeof tt)))
203 return error;
204
205 retval[0] = tt;
206 return 0;
207 }
208
209 /*
210 * utime(). Do conversion to things that utimes() understands,
211 * and pass it on.
212 */
213 int
214 linux_sys_utime(p, v, retval)
215 struct proc *p;
216 void *v;
217 register_t *retval;
218 {
219 struct linux_sys_utime_args /* {
220 syscallarg(const char *) path;
221 syscallarg(struct linux_utimbuf *)times;
222 } */ *uap = v;
223 caddr_t sg;
224 int error;
225 struct sys_utimes_args ua;
226 struct timeval tv[2], *tvp;
227 struct linux_utimbuf lut;
228
229 sg = stackgap_init(p->p_emul);
230 LINUX_CHECK_ALT_EXIST(p, &sg, SCARG(uap, path));
231
232 SCARG(&ua, path) = SCARG(uap, path);
233
234 if (SCARG(uap, times) != NULL) {
235 if ((error = copyin(SCARG(uap, times), &lut, sizeof lut)))
236 return error;
237 tv[0].tv_usec = tv[1].tv_usec = 0;
238 tv[0].tv_sec = lut.l_actime;
239 tv[1].tv_sec = lut.l_modtime;
240 tvp = (struct timeval *) stackgap_alloc(&sg, sizeof(tv));
241 if ((error = copyout(tv, tvp, sizeof tv)))
242 return error;
243 SCARG(&ua, tptr) = tvp;
244 }
245 else
246 SCARG(&ua, tptr) = NULL;
247
248 return sys_utimes(p, &ua, retval);
249 }
250
251 /*
252 * waitpid(2). Passed on to the NetBSD call, surrounded by code to
253 * reserve some space for a NetBSD-style wait status, and converting
254 * it to what Linux wants.
255 */
256 int
257 linux_sys_waitpid(p, v, retval)
258 struct proc *p;
259 void *v;
260 register_t *retval;
261 {
262 struct linux_sys_waitpid_args /* {
263 syscallarg(int) pid;
264 syscallarg(int *) status;
265 syscallarg(int) options;
266 } */ *uap = v;
267 struct sys_wait4_args w4a;
268 int error, *status, tstat;
269 caddr_t sg;
270
271 if (SCARG(uap, status) != NULL) {
272 sg = stackgap_init(p->p_emul);
273 status = (int *) stackgap_alloc(&sg, sizeof status);
274 } else
275 status = NULL;
276
277 SCARG(&w4a, pid) = SCARG(uap, pid);
278 SCARG(&w4a, status) = status;
279 SCARG(&w4a, options) = SCARG(uap, options);
280 SCARG(&w4a, rusage) = NULL;
281
282 if ((error = sys_wait4(p, &w4a, retval)))
283 return error;
284
285 sigdelset(&p->p_siglist, SIGCHLD);
286
287 if (status != NULL) {
288 if ((error = copyin(status, &tstat, sizeof tstat)))
289 return error;
290
291 bsd_to_linux_wstat(&tstat);
292 return copyout(&tstat, SCARG(uap, status), sizeof tstat);
293 }
294
295 return 0;
296 }
297
298 int
299 linux_sys_setresgid(p, v, retval)
300 struct proc *p;
301 void *v;
302 register_t *retval;
303 {
304 struct linux_sys_setresgid_args /* {
305 syscallarg(gid_t) rgid;
306 syscallarg(gid_t) egid;
307 syscallarg(gid_t) sgid;
308 } */ *uap = v;
309 struct pcred *pc = p->p_cred;
310 gid_t rgid, egid, sgid;
311 int error;
312
313 rgid = SCARG(uap, rgid);
314 egid = SCARG(uap, egid);
315 sgid = SCARG(uap, sgid);
316
317 /*
318 * Note: These checks are a little different than the NetBSD
319 * setregid(2) call performs. This precisely follows the
320 * behavior of the Linux kernel.
321 */
322 if (rgid != (gid_t)-1 &&
323 rgid != pc->p_rgid &&
324 rgid != pc->pc_ucred->cr_gid &&
325 rgid != pc->p_svgid &&
326 (error = suser(pc->pc_ucred, &p->p_acflag)))
327 return (error);
328
329 if (egid != (gid_t)-1 &&
330 egid != pc->p_rgid &&
331 egid != pc->pc_ucred->cr_gid &&
332 egid != pc->p_svgid &&
333 (error = suser(pc->pc_ucred, &p->p_acflag)))
334 return (error);
335
336 if (sgid != (gid_t)-1 &&
337 sgid != pc->p_rgid &&
338 sgid != pc->pc_ucred->cr_gid &&
339 sgid != pc->p_svgid &&
340 (error = suser(pc->pc_ucred, &p->p_acflag)))
341 return (error);
342
343 /*
344 * Now assign the real, effective, and saved GIDs.
345 * Note that Linux, unlike NetBSD in setregid(2), does not
346 * set the saved UID in this call unless the user specifies
347 * it.
348 */
349 if (rgid != (gid_t)-1)
350 pc->p_rgid = rgid;
351
352 if (egid != (gid_t)-1) {
353 pc->pc_ucred = crcopy(pc->pc_ucred);
354 pc->pc_ucred->cr_gid = egid;
355 }
356
357 if (sgid != (gid_t)-1)
358 pc->p_svgid = sgid;
359
360 if (rgid != (gid_t)-1 && egid != (gid_t)-1 && sgid != (gid_t)-1)
361 p->p_flag |= P_SUGID;
362 return (0);
363 }
364
365 int
366 linux_sys_getresgid(p, v, retval)
367 struct proc *p;
368 void *v;
369 register_t *retval;
370 {
371 struct linux_sys_getresgid_args /* {
372 syscallarg(gid_t *) rgid;
373 syscallarg(gid_t *) egid;
374 syscallarg(gid_t *) sgid;
375 } */ *uap = v;
376 struct pcred *pc = p->p_cred;
377 int error;
378
379 /*
380 * Linux copies these values out to userspace like so:
381 *
382 * 1. Copy out rgid.
383 * 2. If that succeeds, copy out egid.
384 * 3. If both of those succeed, copy out sgid.
385 */
386 if ((error = copyout(&pc->p_rgid, SCARG(uap, rgid),
387 sizeof(gid_t))) != 0)
388 return (error);
389
390 if ((error = copyout(&pc->pc_ucred->cr_uid, SCARG(uap, egid),
391 sizeof(gid_t))) != 0)
392 return (error);
393
394 return (copyout(&pc->p_svgid, SCARG(uap, sgid), sizeof(gid_t)));
395 }
396
397 /*
398 * I wonder why Linux has settimeofday() _and_ stime().. Still, we
399 * need to deal with it.
400 */
401 int
402 linux_sys_stime(p, v, retval)
403 struct proc *p;
404 void *v;
405 register_t *retval;
406 {
407 struct linux_sys_time_args /* {
408 linux_time_t *t;
409 } */ *uap = v;
410 struct timeval atv;
411 linux_time_t tt;
412 int error;
413
414 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
415 return (error);
416
417 if ((error = copyin(&tt, SCARG(uap, t), sizeof tt)) != 0)
418 return error;
419
420 atv.tv_sec = tt;
421 atv.tv_usec = 0;
422
423 if ((error = settime(&atv)))
424 return (error);
425
426 return 0;
427 }
428