183221Smarcel/*-
283221Smarcel * Copyright (c) 2001 Marcel Moolenaar
383221Smarcel * All rights reserved.
483221Smarcel *
583221Smarcel * Redistribution and use in source and binary forms, with or without
683221Smarcel * modification, are permitted provided that the following conditions
783221Smarcel * are met:
883221Smarcel * 1. Redistributions of source code must retain the above copyright
9111798Sdes *    notice, this list of conditions and the following disclaimer
1083221Smarcel *    in this position and unchanged.
1183221Smarcel * 2. Redistributions in binary form must reproduce the above copyright
1283221Smarcel *    notice, this list of conditions and the following disclaimer in the
1383221Smarcel *    documentation and/or other materials provided with the distribution.
1483221Smarcel * 3. The name of the author may not be used to endorse or promote products
1583221Smarcel *    derived from this software without specific prior written permission.
1683221Smarcel *
1783221Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1883221Smarcel * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1983221Smarcel * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2083221Smarcel * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2183221Smarcel * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2283221Smarcel * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2383221Smarcel * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2483221Smarcel * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2583221Smarcel * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2683221Smarcel * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2783221Smarcel */
2883221Smarcel
29116173Sobrien#include <sys/cdefs.h>
30116173Sobrien__FBSDID("$FreeBSD$");
31116173Sobrien
32156874Sru#include "opt_compat.h"
33235063Snetchild#include "opt_kdtrace.h"
34156874Sru
3583221Smarcel#include <sys/param.h>
36235063Snetchild#include <sys/kernel.h>
37103839Smini#include <sys/lock.h>
38102954Sbde#include <sys/malloc.h>
39103839Smini#include <sys/mutex.h>
40103839Smini#include <sys/proc.h>
41235063Snetchild#include <sys/sdt.h>
42103839Smini#include <sys/sysctl.h>
4383221Smarcel#include <sys/systm.h>
44108541Salfred#include <sys/sbuf.h>
4583221Smarcel
46140214Sobrien#ifdef COMPAT_LINUX32
47140214Sobrien#include <machine/../linux32/linux.h>
48140214Sobrien#include <machine/../linux32/linux32_proto.h>
49140214Sobrien#else
5083221Smarcel#include <machine/../linux/linux.h>
5183221Smarcel#include <machine/../linux/linux_proto.h>
52133816Stjr#endif
5383221Smarcel
54235063Snetchild#include <compat/linux/linux_dtrace.h>
55246085Sjhb#include <compat/linux/linux_misc.h>
56108541Salfred#include <compat/linux/linux_util.h>
57108541Salfred
5883221Smarcel#define	LINUX_CTL_KERN		1
5983221Smarcel#define	LINUX_CTL_VM		2
6083221Smarcel#define	LINUX_CTL_NET		3
6183221Smarcel#define	LINUX_CTL_PROC		4
6283221Smarcel#define	LINUX_CTL_FS		5
6383221Smarcel#define	LINUX_CTL_DEBUG		6
6483221Smarcel#define	LINUX_CTL_DEV		7
6583221Smarcel#define	LINUX_CTL_BUS		8
6683221Smarcel
6783221Smarcel/* CTL_KERN names */
6883221Smarcel#define	LINUX_KERN_OSTYPE	1
6983221Smarcel#define	LINUX_KERN_OSRELEASE	2
7083221Smarcel#define	LINUX_KERN_OSREV	3
7183221Smarcel#define	LINUX_KERN_VERSION	4
7283221Smarcel
73235063Snetchild/* DTrace init */
74235063SnetchildLIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE);
75235063Snetchild
76235063Snetchild/**
77235063Snetchild * DTrace probes in this module.
78235063Snetchild */
79235063SnetchildLIN_SDT_PROBE_DEFINE2(sysctl, handle_string, entry, "struct l___sysctl_args *",
80235063Snetchild    "char *");
81235063SnetchildLIN_SDT_PROBE_DEFINE1(sysctl, handle_string, copyout_error, "int");
82235063SnetchildLIN_SDT_PROBE_DEFINE1(sysctl, handle_string, return, "int");
83235063SnetchildLIN_SDT_PROBE_DEFINE2(sysctl, linux_sysctl, entry, "struct l___sysctl_args *",
84235063Snetchild    "struct thread *");
85235063SnetchildLIN_SDT_PROBE_DEFINE1(sysctl, linux_sysctl, copyin_error, "int");
86235063SnetchildLIN_SDT_PROBE_DEFINE2(sysctl, linux_sysctl, wrong_length, "int", "int");
87235063SnetchildLIN_SDT_PROBE_DEFINE1(sysctl, linux_sysctl, unsupported_sysctl, "char *");
88235063SnetchildLIN_SDT_PROBE_DEFINE1(sysctl, linux_sysctl, return, "int");
89235063Snetchild
9083221Smarcelstatic int
9183221Smarcelhandle_string(struct l___sysctl_args *la, char *value)
9283221Smarcel{
9383221Smarcel	int error;
9483221Smarcel
95235063Snetchild	LIN_SDT_PROBE2(sysctl, handle_string, entry, la, value);
96235063Snetchild
97133816Stjr	if (la->oldval != 0) {
9883221Smarcel		l_int len = strlen(value);
99133816Stjr		error = copyout(value, PTRIN(la->oldval), len + 1);
100133816Stjr		if (!error && la->oldlenp != 0)
101133816Stjr			error = copyout(&len, PTRIN(la->oldlenp), sizeof(len));
102235063Snetchild		if (error) {
103235063Snetchild			LIN_SDT_PROBE1(sysctl, handle_string, copyout_error,
104235063Snetchild			    error);
105235063Snetchild			LIN_SDT_PROBE1(sysctl, handle_string, return, error);
10683221Smarcel			return (error);
107235063Snetchild		}
10883221Smarcel	}
10983221Smarcel
110235063Snetchild	if (la->newval != 0) {
111235063Snetchild		LIN_SDT_PROBE1(sysctl, handle_string, return, ENOTDIR);
11283221Smarcel		return (ENOTDIR);
113235063Snetchild	}
11483221Smarcel
115235063Snetchild	LIN_SDT_PROBE1(sysctl, handle_string, return, 0);
11683221Smarcel	return (0);
11783221Smarcel}
11883221Smarcel
11983221Smarcelint
12083366Sjulianlinux_sysctl(struct thread *td, struct linux_sysctl_args *args)
12183221Smarcel{
12283221Smarcel	struct l___sysctl_args la;
123108541Salfred	struct sbuf *sb;
12483221Smarcel	l_int *mib;
125235063Snetchild	char *sysctl_string;
12683221Smarcel	int error, i;
12783221Smarcel
128235063Snetchild	LIN_SDT_PROBE2(sysctl, linux_sysctl, entry, td, args->args);
129235063Snetchild
130111797Sdes	error = copyin(args->args, &la, sizeof(la));
131235063Snetchild	if (error) {
132235063Snetchild		LIN_SDT_PROBE1(sysctl, linux_sysctl, copyin_error, error);
133235063Snetchild		LIN_SDT_PROBE1(sysctl, linux_sysctl, return, error);
13483221Smarcel		return (error);
135235063Snetchild	}
13683221Smarcel
137235063Snetchild	if (la.nlen <= 0 || la.nlen > LINUX_CTL_MAXNAME) {
138235063Snetchild		LIN_SDT_PROBE2(sysctl, linux_sysctl, wrong_length, la.nlen,
139235063Snetchild		    LINUX_CTL_MAXNAME);
140235063Snetchild		LIN_SDT_PROBE1(sysctl, linux_sysctl, return, ENOTDIR);
14183221Smarcel		return (ENOTDIR);
142235063Snetchild	}
14383221Smarcel
144111119Simp	mib = malloc(la.nlen * sizeof(l_int), M_TEMP, M_WAITOK);
145133816Stjr	error = copyin(PTRIN(la.name), mib, la.nlen * sizeof(l_int));
146102814Siedowse	if (error) {
147235063Snetchild		LIN_SDT_PROBE1(sysctl, linux_sysctl, copyin_error, error);
148235063Snetchild		LIN_SDT_PROBE1(sysctl, linux_sysctl, return, error);
149102814Siedowse		free(mib, M_TEMP);
15083221Smarcel		return (error);
151102814Siedowse	}
15283221Smarcel
15383221Smarcel	switch (mib[0]) {
15483221Smarcel	case LINUX_CTL_KERN:
15583221Smarcel		if (la.nlen < 2)
15683221Smarcel			break;
15783221Smarcel
15883221Smarcel		switch (mib[1]) {
15983221Smarcel		case LINUX_KERN_VERSION:
160102814Siedowse			error = handle_string(&la, version);
161102814Siedowse			free(mib, M_TEMP);
162235063Snetchild			LIN_SDT_PROBE1(sysctl, linux_sysctl, return, error);
163102814Siedowse			return (error);
16483221Smarcel		default:
16583221Smarcel			break;
16683221Smarcel		}
16783221Smarcel		break;
16883221Smarcel	default:
16983221Smarcel		break;
17083221Smarcel	}
17183221Smarcel
172108541Salfred	sb = sbuf_new(NULL, NULL, 20 + la.nlen * 5, SBUF_AUTOEXTEND);
173108541Salfred	if (sb == NULL) {
174108541Salfred		linux_msg(td, "sysctl is not implemented");
175235063Snetchild		LIN_SDT_PROBE1(sysctl, linux_sysctl, unsupported_sysctl,
176235063Snetchild		    "unknown sysctl, ENOMEM during lookup");
177108541Salfred	} else {
178108541Salfred		sbuf_printf(sb, "sysctl ");
179108541Salfred		for (i = 0; i < la.nlen; i++)
180108541Salfred			sbuf_printf(sb, "%c%d", (i) ? ',' : '{', mib[i]);
181108541Salfred		sbuf_printf(sb, "} is not implemented");
182108541Salfred		sbuf_finish(sb);
183235063Snetchild		sysctl_string = sbuf_data(sb);
184108541Salfred		linux_msg(td, "%s", sbuf_data(sb));
185235063Snetchild		LIN_SDT_PROBE1(sysctl, linux_sysctl, unsupported_sysctl,
186235063Snetchild		    sysctl_string);
187108541Salfred		sbuf_delete(sb);
188108541Salfred	}
18983221Smarcel
190102814Siedowse	free(mib, M_TEMP);
191235063Snetchild
192235063Snetchild	LIN_SDT_PROBE1(sysctl, linux_sysctl, return, ENOTDIR);
19383221Smarcel	return (ENOTDIR);
19483221Smarcel}
195