linux_misc_notalpha.c revision 1.58 1 /* $NetBSD: linux_misc_notalpha.c,v 1.58 2000/08/29 14:33:27 sommerfeld 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/proc.h>
49 #include <sys/ptrace.h>
50 #include <sys/resource.h>
51 #include <sys/resourcevar.h>
52 #include <sys/wait.h>
53
54 #include <sys/syscallargs.h>
55
56 #include <compat/linux/common/linux_types.h>
57 #include <compat/linux/common/linux_fcntl.h>
58 #include <compat/linux/common/linux_misc.h>
59 #include <compat/linux/common/linux_mmap.h>
60 #include <compat/linux/common/linux_signal.h>
61 #include <compat/linux/common/linux_util.h>
62
63 #include <compat/linux/linux_syscallargs.h>
64
65 /*
66 * This file contains routines which are used
67 * on every linux architechture except the Alpha.
68 */
69
70 /* Used on: arm, i386, m68k, mips, ppc, sparc, sparc64 */
71 /* Not used on: alpha */
72
73 /*
74 * Alarm. This is a libc call which uses setitimer(2) in NetBSD.
75 * Fiddle with the timers to make it work.
76 */
77 int
78 linux_sys_alarm(p, v, retval)
79 struct proc *p;
80 void *v;
81 register_t *retval;
82 {
83 struct linux_sys_alarm_args /* {
84 syscallarg(unsigned int) secs;
85 } */ *uap = v;
86 int s;
87 struct itimerval *itp, it;
88
89 itp = &p->p_realtimer;
90 s = splclock();
91 /*
92 * Clear any pending timer alarms.
93 */
94 callout_stop(&p->p_realit_ch);
95 timerclear(&itp->it_interval);
96 if (timerisset(&itp->it_value) &&
97 timercmp(&itp->it_value, &time, >))
98 timersub(&itp->it_value, &time, &itp->it_value);
99 /*
100 * Return how many seconds were left (rounded up)
101 */
102 retval[0] = itp->it_value.tv_sec;
103 if (itp->it_value.tv_usec)
104 retval[0]++;
105
106 /*
107 * alarm(0) just resets the timer.
108 */
109 if (SCARG(uap, secs) == 0) {
110 timerclear(&itp->it_value);
111 splx(s);
112 return 0;
113 }
114
115 /*
116 * Check the new alarm time for sanity, and set it.
117 */
118 timerclear(&it.it_interval);
119 it.it_value.tv_sec = SCARG(uap, secs);
120 it.it_value.tv_usec = 0;
121 if (itimerfix(&it.it_value) || itimerfix(&it.it_interval)) {
122 splx(s);
123 return (EINVAL);
124 }
125
126 if (timerisset(&it.it_value)) {
127 /*
128 * Don't need to check hzto() return value, here.
129 * callout_reset() does it for us.
130 */
131 timeradd(&it.it_value, &time, &it.it_value);
132 callout_reset(&p->p_realit_ch, hzto(&it.it_value),
133 realitexpire, p);
134 }
135 p->p_realtimer = it;
136 splx(s);
137
138 return 0;
139 }
140
141 int
142 linux_sys_nice(p, v, retval)
143 struct proc *p;
144 void *v;
145 register_t *retval;
146 {
147 struct linux_sys_nice_args /* {
148 syscallarg(int) incr;
149 } */ *uap = v;
150 struct sys_setpriority_args bsa;
151
152 SCARG(&bsa, which) = PRIO_PROCESS;
153 SCARG(&bsa, who) = 0;
154 SCARG(&bsa, prio) = SCARG(uap, incr);
155 return sys_setpriority(p, &bsa, retval);
156 }
157
158 /*
159 * The old Linux readdir was only able to read one entry at a time,
160 * even though it had a 'count' argument. In fact, the emulation
161 * of the old call was better than the original, because it did handle
162 * the count arg properly. Don't bother with it anymore now, and use
163 * it to distinguish between old and new. The difference is that the
164 * newer one actually does multiple entries, and the reclen field
165 * really is the reclen, not the namelength.
166 */
167 int
168 linux_sys_readdir(p, v, retval)
169 struct proc *p;
170 void *v;
171 register_t *retval;
172 {
173 struct linux_sys_readdir_args /* {
174 syscallarg(int) fd;
175 syscallarg(struct linux_dirent *) dent;
176 syscallarg(unsigned int) count;
177 } */ *uap = v;
178
179 SCARG(uap, count) = 1;
180 return linux_sys_getdents(p, uap, retval);
181 }
182
183 /*
184 * I wonder why Linux has gettimeofday() _and_ time().. Still, we
185 * need to deal with it.
186 */
187 int
188 linux_sys_time(p, v, retval)
189 struct proc *p;
190 void *v;
191 register_t *retval;
192 {
193 struct linux_sys_time_args /* {
194 linux_time_t *t;
195 } */ *uap = v;
196 struct timeval atv;
197 linux_time_t tt;
198 int error;
199
200 microtime(&atv);
201
202 tt = atv.tv_sec;
203 if (SCARG(uap, t) && (error = copyout(&tt, SCARG(uap, t), sizeof tt)))
204 return error;
205
206 retval[0] = tt;
207 return 0;
208 }
209
210 /*
211 * utime(). Do conversion to things that utimes() understands,
212 * and pass it on.
213 */
214 int
215 linux_sys_utime(p, v, retval)
216 struct proc *p;
217 void *v;
218 register_t *retval;
219 {
220 struct linux_sys_utime_args /* {
221 syscallarg(const char *) path;
222 syscallarg(struct linux_utimbuf *)times;
223 } */ *uap = v;
224 caddr_t sg;
225 int error;
226 struct sys_utimes_args ua;
227 struct timeval tv[2], *tvp;
228 struct linux_utimbuf lut;
229
230 sg = stackgap_init(p->p_emul);
231 tvp = (struct timeval *) stackgap_alloc(&sg, sizeof(tv));
232 LINUX_CHECK_ALT_EXIST(p, &sg, SCARG(uap, path));
233
234 SCARG(&ua, path) = SCARG(uap, path);
235
236 if (SCARG(uap, times) != NULL) {
237 if ((error = copyin(SCARG(uap, times), &lut, sizeof lut)))
238 return error;
239 tv[0].tv_usec = tv[1].tv_usec = 0;
240 tv[0].tv_sec = lut.l_actime;
241 tv[1].tv_sec = lut.l_modtime;
242 if ((error = copyout(tv, tvp, sizeof tv)))
243 return error;
244 SCARG(&ua, tptr) = tvp;
245 }
246 else
247 SCARG(&ua, tptr) = NULL;
248
249 return sys_utimes(p, &ua, retval);
250 }
251
252 /*
253 * waitpid(2). Passed on to the NetBSD call, surrounded by code to
254 * reserve some space for a NetBSD-style wait status, and converting
255 * it to what Linux wants.
256 */
257 int
258 linux_sys_waitpid(p, v, retval)
259 struct proc *p;
260 void *v;
261 register_t *retval;
262 {
263 struct linux_sys_waitpid_args /* {
264 syscallarg(int) pid;
265 syscallarg(int *) status;
266 syscallarg(int) options;
267 } */ *uap = v;
268 struct sys_wait4_args w4a;
269 int error, *status, tstat;
270 caddr_t sg;
271
272 if (SCARG(uap, status) != NULL) {
273 sg = stackgap_init(p->p_emul);
274 status = (int *) stackgap_alloc(&sg, sizeof status);
275 } else
276 status = NULL;
277
278 SCARG(&w4a, pid) = SCARG(uap, pid);
279 SCARG(&w4a, status) = status;
280 SCARG(&w4a, options) = SCARG(uap, options);
281 SCARG(&w4a, rusage) = NULL;
282
283 if ((error = sys_wait4(p, &w4a, retval)))
284 return error;
285
286 sigdelset(&p->p_siglist, SIGCHLD);
287
288 if (status != NULL) {
289 if ((error = copyin(status, &tstat, sizeof tstat)))
290 return error;
291
292 bsd_to_linux_wstat(&tstat);
293 return copyout(&tstat, SCARG(uap, status), sizeof tstat);
294 }
295
296 return 0;
297 }
298
299 int
300 linux_sys_setresgid(p, v, retval)
301 struct proc *p;
302 void *v;
303 register_t *retval;
304 {
305 struct linux_sys_setresgid_args /* {
306 syscallarg(gid_t) rgid;
307 syscallarg(gid_t) egid;
308 syscallarg(gid_t) sgid;
309 } */ *uap = v;
310 struct pcred *pc = p->p_cred;
311 gid_t rgid, egid, sgid;
312 int error;
313
314 rgid = SCARG(uap, rgid);
315 egid = SCARG(uap, egid);
316 sgid = SCARG(uap, sgid);
317
318 /*
319 * Note: These checks are a little different than the NetBSD
320 * setregid(2) call performs. This precisely follows the
321 * behavior of the Linux kernel.
322 */
323 if (rgid != (gid_t)-1 &&
324 rgid != pc->p_rgid &&
325 rgid != pc->pc_ucred->cr_gid &&
326 rgid != pc->p_svgid &&
327 (error = suser(pc->pc_ucred, &p->p_acflag)))
328 return (error);
329
330 if (egid != (gid_t)-1 &&
331 egid != pc->p_rgid &&
332 egid != pc->pc_ucred->cr_gid &&
333 egid != pc->p_svgid &&
334 (error = suser(pc->pc_ucred, &p->p_acflag)))
335 return (error);
336
337 if (sgid != (gid_t)-1 &&
338 sgid != pc->p_rgid &&
339 sgid != pc->pc_ucred->cr_gid &&
340 sgid != pc->p_svgid &&
341 (error = suser(pc->pc_ucred, &p->p_acflag)))
342 return (error);
343
344 /*
345 * Now assign the real, effective, and saved GIDs.
346 * Note that Linux, unlike NetBSD in setregid(2), does not
347 * set the saved UID in this call unless the user specifies
348 * it.
349 */
350 if (rgid != (gid_t)-1)
351 pc->p_rgid = rgid;
352
353 if (egid != (gid_t)-1) {
354 pc->pc_ucred = crcopy(pc->pc_ucred);
355 pc->pc_ucred->cr_gid = egid;
356 }
357
358 if (sgid != (gid_t)-1)
359 pc->p_svgid = sgid;
360
361 if (rgid != (gid_t)-1 && egid != (gid_t)-1 && sgid != (gid_t)-1)
362 p->p_flag |= P_SUGID;
363 return (0);
364 }
365
366 int
367 linux_sys_getresgid(p, v, retval)
368 struct proc *p;
369 void *v;
370 register_t *retval;
371 {
372 struct linux_sys_getresgid_args /* {
373 syscallarg(gid_t *) rgid;
374 syscallarg(gid_t *) egid;
375 syscallarg(gid_t *) sgid;
376 } */ *uap = v;
377 struct pcred *pc = p->p_cred;
378 int error;
379
380 /*
381 * Linux copies these values out to userspace like so:
382 *
383 * 1. Copy out rgid.
384 * 2. If that succeeds, copy out egid.
385 * 3. If both of those succeed, copy out sgid.
386 */
387 if ((error = copyout(&pc->p_rgid, SCARG(uap, rgid),
388 sizeof(gid_t))) != 0)
389 return (error);
390
391 if ((error = copyout(&pc->pc_ucred->cr_uid, SCARG(uap, egid),
392 sizeof(gid_t))) != 0)
393 return (error);
394
395 return (copyout(&pc->p_svgid, SCARG(uap, sgid), sizeof(gid_t)));
396 }
397
398 /*
399 * I wonder why Linux has settimeofday() _and_ stime().. Still, we
400 * need to deal with it.
401 */
402 int
403 linux_sys_stime(p, v, retval)
404 struct proc *p;
405 void *v;
406 register_t *retval;
407 {
408 struct linux_sys_time_args /* {
409 linux_time_t *t;
410 } */ *uap = v;
411 struct timeval atv;
412 linux_time_t tt;
413 int error;
414
415 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
416 return (error);
417
418 if ((error = copyin(&tt, SCARG(uap, t), sizeof tt)) != 0)
419 return error;
420
421 atv.tv_sec = tt;
422 atv.tv_usec = 0;
423
424 if ((error = settime(&atv)))
425 return (error);
426
427 return 0;
428 }
429