1/*-
2 * Copyright (c) 1982, 1986, 1989, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 4. Neither the name of the University nor the names of its contributors
14 *    may be used to endorse or promote products derived from this software
15 *    without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 *	@(#)kern_xxx.c	8.2 (Berkeley) 11/14/93
30 */
31
32#include <sys/cdefs.h>
33__FBSDID("$FreeBSD$");
34
35#include "opt_compat.h"
36
37#include <sys/param.h>
38#include <sys/systm.h>
39#include <sys/sysproto.h>
40#include <sys/kernel.h>
41#include <sys/priv.h>
42#include <sys/proc.h>
43#include <sys/lock.h>
44#include <sys/mutex.h>
45#include <sys/socket.h>
46#include <sys/sysctl.h>
47#include <sys/utsname.h>
48
49#include <vm/vm_param.h>
50
51#if defined(COMPAT_43)
52
53#ifndef _SYS_SYSPROTO_H_
54struct gethostname_args {
55	char	*hostname;
56	u_int	len;
57};
58#endif
59/* ARGSUSED */
60int
61ogethostname(td, uap)
62	struct thread *td;
63	struct gethostname_args *uap;
64{
65	int name[2];
66	size_t len = uap->len;
67
68	name[0] = CTL_KERN;
69	name[1] = KERN_HOSTNAME;
70	return (userland_sysctl(td, name, 2, uap->hostname, &len,
71	    1, 0, 0, 0, 0));
72}
73
74#ifndef _SYS_SYSPROTO_H_
75struct sethostname_args {
76	char	*hostname;
77	u_int	len;
78};
79#endif
80/* ARGSUSED */
81int
82osethostname(td, uap)
83	struct thread *td;
84	register struct sethostname_args *uap;
85{
86	int name[2];
87
88	name[0] = CTL_KERN;
89	name[1] = KERN_HOSTNAME;
90	return (userland_sysctl(td, name, 2, 0, 0, 0, uap->hostname,
91	    uap->len, 0, 0));
92}
93
94#ifndef _SYS_SYSPROTO_H_
95struct ogethostid_args {
96	int	dummy;
97};
98#endif
99/* ARGSUSED */
100int
101ogethostid(td, uap)
102	struct thread *td;
103	struct ogethostid_args *uap;
104{
105	size_t len = sizeof(long);
106	int name[2];
107
108	name[0] = CTL_KERN;
109	name[1] = KERN_HOSTID;
110	return (kernel_sysctl(td, name, 2, (long *)td->td_retval, &len,
111	    NULL, 0, NULL, 0));
112}
113#endif /* COMPAT_43 */
114
115#ifdef COMPAT_43
116#ifndef _SYS_SYSPROTO_H_
117struct osethostid_args {
118	long	hostid;
119};
120#endif
121/* ARGSUSED */
122int
123osethostid(td, uap)
124	struct thread *td;
125	struct osethostid_args *uap;
126{
127	int name[2];
128
129	name[0] = CTL_KERN;
130	name[1] = KERN_HOSTID;
131	return (kernel_sysctl(td, name, 2, NULL, NULL, &uap->hostid,
132	    sizeof(uap->hostid), NULL, 0));
133}
134
135int
136oquota(td, uap)
137	struct thread *td;
138	struct oquota_args *uap;
139{
140
141	return (ENOSYS);
142}
143
144#define	KINFO_PROC		(0<<8)
145#define	KINFO_RT		(1<<8)
146#define	KINFO_VNODE		(2<<8)
147#define	KINFO_FILE		(3<<8)
148#define	KINFO_METER		(4<<8)
149#define	KINFO_LOADAVG		(5<<8)
150#define	KINFO_CLOCKRATE		(6<<8)
151
152/* Non-standard BSDI extension - only present on their 4.3 net-2 releases */
153#define	KINFO_BSDI_SYSINFO	(101<<8)
154
155/*
156 * XXX this is bloat, but I hope it's better here than on the potentially
157 * limited kernel stack...  -Peter
158 */
159
160static struct {
161	int	bsdi_machine;		/* "i386" on BSD/386 */
162/*      ^^^ this is an offset to the string, relative to the struct start */
163	char	*pad0;
164	long	pad1;
165	long	pad2;
166	long	pad3;
167	u_long	pad4;
168	u_long	pad5;
169	u_long	pad6;
170
171	int	bsdi_ostype;		/* "BSD/386" on BSD/386 */
172	int	bsdi_osrelease;		/* "1.1" on BSD/386 */
173	long	pad7;
174	long	pad8;
175	char	*pad9;
176
177	long	pad10;
178	long	pad11;
179	int	pad12;
180	long	pad13;
181	quad_t	pad14;
182	long	pad15;
183
184	struct	timeval pad16;
185	/* we dont set this, because BSDI's uname used gethostname() instead */
186	int	bsdi_hostname;		/* hostname on BSD/386 */
187
188	/* the actual string data is appended here */
189
190} bsdi_si;
191
192/*
193 * this data is appended to the end of the bsdi_si structure during copyout.
194 * The "char *" offsets are relative to the base of the bsdi_si struct.
195 * This contains "FreeBSD\02.0-BUILT-nnnnnn\0i386\0", and these strings
196 * should not exceed the length of the buffer here... (or else!! :-)
197 */
198static char bsdi_strings[80];	/* It had better be less than this! */
199
200#ifndef _SYS_SYSPROTO_H_
201struct getkerninfo_args {
202	int	op;
203	char	*where;
204	size_t	*size;
205	int	arg;
206};
207#endif
208int
209ogetkerninfo(struct thread *td, struct getkerninfo_args *uap)
210{
211	int error, name[6];
212	size_t size;
213	u_int needed = 0;
214
215	switch (uap->op & 0xff00) {
216
217	case KINFO_RT:
218		name[0] = CTL_NET;
219		name[1] = PF_ROUTE;
220		name[2] = 0;
221		name[3] = (uap->op & 0xff0000) >> 16;
222		name[4] = uap->op & 0xff;
223		name[5] = uap->arg;
224		error = userland_sysctl(td, name, 6, uap->where, uap->size,
225			0, 0, 0, &size, 0);
226		break;
227
228	case KINFO_VNODE:
229		name[0] = CTL_KERN;
230		name[1] = KERN_VNODE;
231		error = userland_sysctl(td, name, 2, uap->where, uap->size,
232			0, 0, 0, &size, 0);
233		break;
234
235	case KINFO_PROC:
236		name[0] = CTL_KERN;
237		name[1] = KERN_PROC;
238		name[2] = uap->op & 0xff;
239		name[3] = uap->arg;
240		error = userland_sysctl(td, name, 4, uap->where, uap->size,
241			0, 0, 0, &size, 0);
242		break;
243
244	case KINFO_FILE:
245		name[0] = CTL_KERN;
246		name[1] = KERN_FILE;
247		error = userland_sysctl(td, name, 2, uap->where, uap->size,
248			0, 0, 0, &size, 0);
249		break;
250
251	case KINFO_METER:
252		name[0] = CTL_VM;
253		name[1] = VM_TOTAL;
254		error = userland_sysctl(td, name, 2, uap->where, uap->size,
255			0, 0, 0, &size, 0);
256		break;
257
258	case KINFO_LOADAVG:
259		name[0] = CTL_VM;
260		name[1] = VM_LOADAVG;
261		error = userland_sysctl(td, name, 2, uap->where, uap->size,
262			0, 0, 0, &size, 0);
263		break;
264
265	case KINFO_CLOCKRATE:
266		name[0] = CTL_KERN;
267		name[1] = KERN_CLOCKRATE;
268		error = userland_sysctl(td, name, 2, uap->where, uap->size,
269			0, 0, 0, &size, 0);
270		break;
271
272	case KINFO_BSDI_SYSINFO: {
273		/*
274		 * this is pretty crude, but it's just enough for uname()
275		 * from BSDI's 1.x libc to work.
276		 *
277		 * *size gives the size of the buffer before the call, and
278		 * the amount of data copied after a successful call.
279		 * If successful, the return value is the amount of data
280		 * available, which can be larger than *size.
281		 *
282		 * BSDI's 2.x product apparently fails with ENOMEM if *size
283		 * is too small.
284		 */
285
286		u_int left;
287		char *s;
288
289		bzero((char *)&bsdi_si, sizeof(bsdi_si));
290		bzero(bsdi_strings, sizeof(bsdi_strings));
291
292		s = bsdi_strings;
293
294		bsdi_si.bsdi_ostype = (s - bsdi_strings) + sizeof(bsdi_si);
295		strcpy(s, ostype);
296		s += strlen(s) + 1;
297
298		bsdi_si.bsdi_osrelease = (s - bsdi_strings) + sizeof(bsdi_si);
299		strcpy(s, osrelease);
300		s += strlen(s) + 1;
301
302		bsdi_si.bsdi_machine = (s - bsdi_strings) + sizeof(bsdi_si);
303		strcpy(s, machine);
304		s += strlen(s) + 1;
305
306		needed = sizeof(bsdi_si) + (s - bsdi_strings);
307
308		if ((uap->where == NULL) || (uap->size == NULL)) {
309			/* process is asking how much buffer to supply.. */
310			size = needed;
311			error = 0;
312			break;
313		}
314
315		if ((error = copyin(uap->size, &size, sizeof(size))) != 0)
316			break;
317
318		/* if too much buffer supplied, trim it down */
319		if (size > needed)
320			size = needed;
321
322		/* how much of the buffer is remaining */
323		left = size;
324
325		if ((error = copyout((char *)&bsdi_si, uap->where, left)) != 0)
326			break;
327
328		/* is there any point in continuing? */
329		if (left > sizeof(bsdi_si)) {
330			left -= sizeof(bsdi_si);
331			error = copyout(&bsdi_strings,
332					uap->where + sizeof(bsdi_si), left);
333		}
334		break;
335	}
336
337	default:
338		error = EOPNOTSUPP;
339		break;
340	}
341	if (error == 0) {
342		td->td_retval[0] = needed ? needed : size;
343		if (uap->size) {
344			error = copyout(&size, uap->size, sizeof(size));
345		}
346	}
347	return (error);
348}
349#endif /* COMPAT_43 */
350
351#ifdef COMPAT_FREEBSD4
352/*
353 * This is the FreeBSD-1.1 compatible uname(2) interface.  These days it is
354 * done in libc as a wrapper around a bunch of sysctl's.  This must maintain
355 * the old 1.1 binary ABI.
356 */
357#if SYS_NMLN != 32
358#error "FreeBSD-1.1 uname syscall has been broken"
359#endif
360#ifndef _SYS_SYSPROTO_H_
361struct uname_args {
362	struct utsname  *name;
363};
364#endif
365/* ARGSUSED */
366int
367freebsd4_uname(struct thread *td, struct freebsd4_uname_args *uap)
368{
369	int name[2], error;
370	size_t len;
371	char *s, *us;
372
373	name[0] = CTL_KERN;
374	name[1] = KERN_OSTYPE;
375	len = sizeof (uap->name->sysname);
376	error = userland_sysctl(td, name, 2, uap->name->sysname, &len,
377		1, 0, 0, 0, 0);
378	if (error)
379		return (error);
380	subyte( uap->name->sysname + sizeof(uap->name->sysname) - 1, 0);
381
382	name[1] = KERN_HOSTNAME;
383	len = sizeof uap->name->nodename;
384	error = userland_sysctl(td, name, 2, uap->name->nodename, &len,
385		1, 0, 0, 0, 0);
386	if (error)
387		return (error);
388	subyte( uap->name->nodename + sizeof(uap->name->nodename) - 1, 0);
389
390	name[1] = KERN_OSRELEASE;
391	len = sizeof uap->name->release;
392	error = userland_sysctl(td, name, 2, uap->name->release, &len,
393		1, 0, 0, 0, 0);
394	if (error)
395		return (error);
396	subyte( uap->name->release + sizeof(uap->name->release) - 1, 0);
397
398/*
399	name = KERN_VERSION;
400	len = sizeof uap->name->version;
401	error = userland_sysctl(td, name, 2, uap->name->version, &len,
402		1, 0, 0, 0, 0);
403	if (error)
404		return (error);
405	subyte( uap->name->version + sizeof(uap->name->version) - 1, 0);
406*/
407
408/*
409 * this stupid hackery to make the version field look like FreeBSD 1.1
410 */
411	for(s = version; *s && *s != '#'; s++);
412
413	for(us = uap->name->version; *s && *s != ':'; s++) {
414		error = subyte( us++, *s);
415		if (error)
416			return (error);
417	}
418	error = subyte( us++, 0);
419	if (error)
420		return (error);
421
422	name[0] = CTL_HW;
423	name[1] = HW_MACHINE;
424	len = sizeof uap->name->machine;
425	error = userland_sysctl(td, name, 2, uap->name->machine, &len,
426		1, 0, 0, 0, 0);
427	if (error)
428		return (error);
429	subyte( uap->name->machine + sizeof(uap->name->machine) - 1, 0);
430	return (0);
431}
432
433#ifndef _SYS_SYSPROTO_H_
434struct getdomainname_args {
435	char    *domainname;
436	int     len;
437};
438#endif
439/* ARGSUSED */
440int
441freebsd4_getdomainname(struct thread *td,
442    struct freebsd4_getdomainname_args *uap)
443{
444	int name[2];
445	size_t len = uap->len;
446
447	name[0] = CTL_KERN;
448	name[1] = KERN_NISDOMAINNAME;
449	return (userland_sysctl(td, name, 2, uap->domainname, &len,
450	    1, 0, 0, 0, 0));
451}
452
453#ifndef _SYS_SYSPROTO_H_
454struct setdomainname_args {
455	char    *domainname;
456	int     len;
457};
458#endif
459/* ARGSUSED */
460int
461freebsd4_setdomainname(struct thread *td,
462    struct freebsd4_setdomainname_args *uap)
463{
464	int name[2];
465
466	name[0] = CTL_KERN;
467	name[1] = KERN_NISDOMAINNAME;
468	return (userland_sysctl(td, name, 2, 0, 0, 0, uap->domainname,
469	    uap->len, 0, 0));
470}
471#endif /* COMPAT_FREEBSD4 */
472