1 
2 #include <stdbool.h>
3 #include <stdint.h>
4 #include <string.h>
5 #include <errno.h>
6 
7 #include <sys/kassert.h>
8 #include <sys/kdebug.h>
9 #include <sys/sysctl.h>
10 
11 typedef struct SysCtlEntry {
12     char	path[64];
13     int		type;
14     int		flags;
15     char	description[128];
16     void	*node;
17 } SysCtlEntry;
18 
19 #define SYSCTL_STR(_PATH, _FLAGS, _DESCRIPTION, _DEFAULT) \
20     { #_PATH, SYSCTL_TYPE_STR, _FLAGS, _DESCRIPTION, &SYSCTL_##_PATH },
21 #define SYSCTL_INT(_PATH, _FLAGS, _DESCRIPTION, _DEFAULT) \
22     { #_PATH, SYSCTL_TYPE_INT, _FLAGS, _DESCRIPTION, &SYSCTL_##_PATH },
23 #define SYSCTL_BOOL(_PATH, _FLAGS, _DESCRIPTION, _DEFAULT) \
24     { #_PATH, SYSCTL_TYPE_BOOL, _FLAGS, _DESCRIPTION, &SYSCTL_##_PATH },
25 SysCtlEntry SYSCTLTable[] = {
26     SYSCTL_LIST
27     { "", 0, 0, "", NULL },
28 };
29 #undef SYSCTL_STR
30 #undef SYSCTL_INT
31 #undef SYSCTL_BOOL
32 
33 #define SYSCTL_STR(_PATH, _FLAGS, _DESCRIPTION, _DEFAULT) \
34 SysCtlString SYSCTL_##_PATH = { #_PATH, _DEFAULT };
35 #define SYSCTL_INT(_PATH, _FLAGS, _DESCRIPTION, _DEFAULT) \
36 SysCtlInt SYSCTL_##_PATH = { #_PATH, _DEFAULT };
37 #define SYSCTL_BOOL(_PATH, _FLAGS, _DESCRIPTION, _DEFAULT) \
38 SysCtlBool SYSCTL_##_PATH = { #_PATH, _DEFAULT };
39 SYSCTL_LIST
40 #undef SYSCTL_STR
41 #undef SYSCTL_INT
42 #undef SYSCTL_BOOL
43 
44 int
SysCtl_Lookup(const char * path)45 SysCtl_Lookup(const char *path)
46 {
47     int i;
48 
49     for (i = 0; SYSCTLTable[i].path[0] != '\0'; i++) {
50 	if (strcmp(path, SYSCTLTable[i].path) == 0)
51 	    return i;
52     }
53 
54     return -1;
55 }
56 
57 uint64_t
SysCtl_GetType(const char * node)58 SysCtl_GetType(const char *node)
59 {
60     int i = SysCtl_Lookup(node);
61     if (i == -1) {
62 	return SYSCTL_TYPE_INVALID;
63     }
64 
65     return SYSCTLTable[i].type;
66 }
67 
68 void *
SysCtl_GetObject(const char * node)69 SysCtl_GetObject(const char *node)
70 {
71     int i = SysCtl_Lookup(node);
72     if (i == -1) {
73 	return NULL;
74     }
75 
76     return SYSCTLTable[i].node;
77 }
78 
79 uint64_t
SysCtl_SetObject(const char * node,void * obj)80 SysCtl_SetObject(const char *node, void *obj)
81 {
82     int i = SysCtl_Lookup(node);
83     if (i == -1) {
84 	return ENOENT;
85     }
86 
87     if (SYSCTLTable[i].flags == SYSCTL_FLAG_RO) {
88 	kprintf("Sysctl node is read-only!\n");
89 	return EACCES;
90     }
91 
92     switch (SYSCTLTable[i].type) {
93 	case SYSCTL_TYPE_STR: {
94 	    SysCtlString *val = (SysCtlString *)SYSCTLTable[i].node;
95 	    memcpy(val, obj, sizeof(*val));
96 	}
97 	case SYSCTL_TYPE_INT: {
98 	    SysCtlInt *val = (SysCtlInt *)SYSCTLTable[i].node;
99 	    memcpy(val, obj, sizeof(*val));
100 	}
101 	case SYSCTL_TYPE_BOOL: {
102 	    SysCtlBool *val = (SysCtlBool *)SYSCTLTable[i].node;
103 	    memcpy(val, obj, sizeof(*val));
104 	}
105     }
106 
107     return 0;
108 }
109 
110 void
Debug_SysCtl(int argc,const char * argv[])111 Debug_SysCtl(int argc, const char *argv[])
112 {
113     int i;
114 
115     if (argc == 1) {
116         kprintf("%-20s %s\n", "Name", "Description");
117 	for (i = 0; SYSCTLTable[i].path[0] != '\0'; i++) {
118 	    kprintf("%-20s %s\n", SYSCTLTable[i].path, SYSCTLTable[i].description);
119 	}
120 
121 	return;
122     }
123 
124     if (argc != 2 && argc != 3) {
125 	kprintf("Usage: sysctl NODE [VALUE]\n");
126 	return;
127     }
128 
129     i = SysCtl_Lookup(argv[1]);
130     if (i == -1) {
131 	kprintf("Unknown sysctl node!\n");
132 	return;
133     }
134 
135     if (argc == 2) {
136 	switch (SYSCTLTable[i].type) {
137 	    case SYSCTL_TYPE_STR: {
138 		SysCtlString *val = (SysCtlString *)SYSCTLTable[i].node;
139 		kprintf("%s: %s\n", argv[1], val->value);
140 		break;
141 	    }
142 	    case SYSCTL_TYPE_INT: {
143 		SysCtlInt *val = (SysCtlInt *)SYSCTLTable[i].node;
144 		kprintf("%s: %ld\n", argv[1], val->value);
145 		break;
146 	    }
147 	    case SYSCTL_TYPE_BOOL: {
148 		SysCtlBool *val = (SysCtlBool *)SYSCTLTable[i].node;
149 		kprintf("%s: %s\n", argv[1], val->value ? "true" : "false");
150 		break;
151 	    }
152 	}
153 
154 	return;
155     }
156 
157     if (argc == 3) {
158 	if (SYSCTLTable[i].flags == SYSCTL_FLAG_RO) {
159 	    kprintf("Sysctl node is read-only!\n");
160 	    return;
161 	}
162 
163 	switch (SYSCTLTable[i].type) {
164 	    case SYSCTL_TYPE_STR: {
165 		SysCtlString *val = (SysCtlString *)SYSCTLTable[i].node;
166 		strncpy(&val->value[0], argv[2], SYSCTL_STR_MAXLENGTH);
167 		break;
168 	    }
169 	    case SYSCTL_TYPE_INT: {
170 		SysCtlInt *val = (SysCtlInt *)SYSCTLTable[i].node;
171 		val->value = Debug_StrToInt(argv[2]);
172 		break;
173 	    }
174 	    case SYSCTL_TYPE_BOOL: {
175 		SysCtlBool *val = (SysCtlBool *)SYSCTLTable[i].node;
176 		if (strcmp(argv[2], "0") == 0) {
177 		    val->value = false;
178 		} else if (strcmp(argv[2], "1") == 0) {
179 		    val->value = true;
180 		} else {
181 		    kprintf("Invalid value!\n");
182 		}
183 		break;
184 	    }
185 	}
186     }
187 }
188 
189 REGISTER_DBGCMD(sysctl, "SYSCTL", Debug_SysCtl);
190 
191