1*6f3e0bcdSDavid van Moolenbroek /* Remote MIB (RMIB) test service - by D.C. van Moolenbroek */
2*6f3e0bcdSDavid van Moolenbroek /*
3*6f3e0bcdSDavid van Moolenbroek * This test is a good start, but not an exhaustive coverage test for all
4*6f3e0bcdSDavid van Moolenbroek * possible failure cases. The reason for that is mainly that there are
5*6f3e0bcdSDavid van Moolenbroek * various scenarios that we cannot generate without implementing our own local
6*6f3e0bcdSDavid van Moolenbroek * bogus RMIB code. Adding that is something for later - TODO.
7*6f3e0bcdSDavid van Moolenbroek */
8*6f3e0bcdSDavid van Moolenbroek #include <minix/drivers.h>
9*6f3e0bcdSDavid van Moolenbroek #include <minix/sysctl.h>
10*6f3e0bcdSDavid van Moolenbroek #include <minix/rmib.h>
11*6f3e0bcdSDavid van Moolenbroek
12*6f3e0bcdSDavid van Moolenbroek static int running;
13*6f3e0bcdSDavid van Moolenbroek
14*6f3e0bcdSDavid van Moolenbroek /* The following is a copy of the minix.test subtree in the MIB service. */
15*6f3e0bcdSDavid van Moolenbroek static char test_string[16], test_struct[12];
16*6f3e0bcdSDavid van Moolenbroek
17*6f3e0bcdSDavid van Moolenbroek static struct rmib_node minix_test_secret_table[] = {
18*6f3e0bcdSDavid van Moolenbroek /* 0*/ [SECRET_VALUE] = RMIB_INT(RMIB_RO, 12345, "value",
19*6f3e0bcdSDavid van Moolenbroek "The combination to my luggage"),
20*6f3e0bcdSDavid van Moolenbroek };
21*6f3e0bcdSDavid van Moolenbroek
22*6f3e0bcdSDavid van Moolenbroek static struct rmib_node minix_test_table[] = {
23*6f3e0bcdSDavid van Moolenbroek /* 0*/ [TEST_INT] = RMIB_INT(RMIB_RO | CTLFLAG_HEX, 0x01020304,
24*6f3e0bcdSDavid van Moolenbroek "int", "Value test field"),
25*6f3e0bcdSDavid van Moolenbroek /* 1*/ [TEST_BOOL] = RMIB_BOOL(RMIB_RW, 0, "bool",
26*6f3e0bcdSDavid van Moolenbroek "Boolean test field"),
27*6f3e0bcdSDavid van Moolenbroek /* 2*/ [TEST_QUAD] = RMIB_QUAD(RMIB_RW, 0, "quad",
28*6f3e0bcdSDavid van Moolenbroek "Quad test field"),
29*6f3e0bcdSDavid van Moolenbroek /* 3*/ [TEST_STRING] = RMIB_STRING(RMIB_RW, test_string, "string",
30*6f3e0bcdSDavid van Moolenbroek "String test field"),
31*6f3e0bcdSDavid van Moolenbroek /* 4*/ [TEST_STRUCT] = RMIB_STRUCT(RMIB_RW, sizeof(test_struct),
32*6f3e0bcdSDavid van Moolenbroek test_struct, "struct",
33*6f3e0bcdSDavid van Moolenbroek "Structure test field"),
34*6f3e0bcdSDavid van Moolenbroek /* 5*/ [TEST_PRIVATE] = RMIB_INT(RMIB_RW | CTLFLAG_PRIVATE, -5375,
35*6f3e0bcdSDavid van Moolenbroek "private", "Private test field"),
36*6f3e0bcdSDavid van Moolenbroek /* 6*/ [TEST_ANYWRITE] = RMIB_INT(RMIB_RW | CTLFLAG_ANYWRITE, 0,
37*6f3e0bcdSDavid van Moolenbroek "anywrite", "AnyWrite test field"),
38*6f3e0bcdSDavid van Moolenbroek /* 7*/ [TEST_DYNAMIC] = RMIB_INT(RMIB_RO, 0, "deleteme",
39*6f3e0bcdSDavid van Moolenbroek "This node will be destroyed"),
40*6f3e0bcdSDavid van Moolenbroek /* 8*/ [TEST_SECRET] = RMIB_NODE(RMIB_RO | CTLFLAG_PRIVATE,
41*6f3e0bcdSDavid van Moolenbroek minix_test_secret_table, "secret",
42*6f3e0bcdSDavid van Moolenbroek "Private subtree"),
43*6f3e0bcdSDavid van Moolenbroek /* 9*/ [TEST_PERM] = RMIB_INT(RMIB_RO, 1, "permanent", NULL),
44*6f3e0bcdSDavid van Moolenbroek /*10*/ [TEST_DESTROY1] = RMIB_INT(RMIB_RO, 123, "destroy1", NULL),
45*6f3e0bcdSDavid van Moolenbroek /*11*/ [TEST_DESTROY2] = RMIB_INT(RMIB_RO, 456, "destroy2",
46*6f3e0bcdSDavid van Moolenbroek "This node will be destroyed"),
47*6f3e0bcdSDavid van Moolenbroek };
48*6f3e0bcdSDavid van Moolenbroek
49*6f3e0bcdSDavid van Moolenbroek static struct rmib_node minix_test = RMIB_NODE(RMIB_RW | CTLFLAG_HIDDEN,
50*6f3e0bcdSDavid van Moolenbroek minix_test_table, "test", "Test87 testing ground");
51*6f3e0bcdSDavid van Moolenbroek /* Here ends the copy of the minix.test subtree in the MIB service. */
52*6f3e0bcdSDavid van Moolenbroek
53*6f3e0bcdSDavid van Moolenbroek static struct rmib_node test_table[] = {
54*6f3e0bcdSDavid van Moolenbroek };
55*6f3e0bcdSDavid van Moolenbroek
56*6f3e0bcdSDavid van Moolenbroek static struct rmib_node test_rnode = RMIB_NODE(RMIB_RO, test_table, "test",
57*6f3e0bcdSDavid van Moolenbroek "Test node");
58*6f3e0bcdSDavid van Moolenbroek
59*6f3e0bcdSDavid van Moolenbroek static int value = 5375123;
60*6f3e0bcdSDavid van Moolenbroek
61*6f3e0bcdSDavid van Moolenbroek static ssize_t test_func(struct rmib_call *, struct rmib_node *,
62*6f3e0bcdSDavid van Moolenbroek struct rmib_oldp *, struct rmib_newp *);
63*6f3e0bcdSDavid van Moolenbroek
64*6f3e0bcdSDavid van Moolenbroek /* No defined constants because userland will access these by name anyway. */
65*6f3e0bcdSDavid van Moolenbroek static struct rmib_node minix_rtest_table[] = {
66*6f3e0bcdSDavid van Moolenbroek [1] = RMIB_INTPTR(RMIB_RW, &value, "int",
67*6f3e0bcdSDavid van Moolenbroek "Test description"),
68*6f3e0bcdSDavid van Moolenbroek [2] = RMIB_FUNC(CTLTYPE_INT | RMIB_RW, sizeof(int),
69*6f3e0bcdSDavid van Moolenbroek test_func, "func", "Test function"),
70*6f3e0bcdSDavid van Moolenbroek };
71*6f3e0bcdSDavid van Moolenbroek
72*6f3e0bcdSDavid van Moolenbroek static struct rmib_node minix_rtest = RMIB_NODE(RMIB_RO, minix_rtest_table,
73*6f3e0bcdSDavid van Moolenbroek "rtest", "Remote test subtree");
74*6f3e0bcdSDavid van Moolenbroek
75*6f3e0bcdSDavid van Moolenbroek /*
76*6f3e0bcdSDavid van Moolenbroek * Test function that deflects reads and writes to its sibling node. Not a
77*6f3e0bcdSDavid van Moolenbroek * super useful thing to do, but a decent test of functionality regardless.
78*6f3e0bcdSDavid van Moolenbroek */
79*6f3e0bcdSDavid van Moolenbroek static ssize_t
test_func(struct rmib_call * call,struct rmib_node * node,struct rmib_oldp * oldp,struct rmib_newp * newp)80*6f3e0bcdSDavid van Moolenbroek test_func(struct rmib_call * call, struct rmib_node * node,
81*6f3e0bcdSDavid van Moolenbroek struct rmib_oldp * oldp, struct rmib_newp * newp)
82*6f3e0bcdSDavid van Moolenbroek {
83*6f3e0bcdSDavid van Moolenbroek
84*6f3e0bcdSDavid van Moolenbroek return rmib_readwrite(call, &minix_rtest_table[1], oldp, newp);
85*6f3e0bcdSDavid van Moolenbroek }
86*6f3e0bcdSDavid van Moolenbroek
87*6f3e0bcdSDavid van Moolenbroek /*
88*6f3e0bcdSDavid van Moolenbroek * Attempt to perform registrations that should be rejected locally, and thus
89*6f3e0bcdSDavid van Moolenbroek * result in failure immediately. Unfortunately, we cannot verify that the MIB
90*6f3e0bcdSDavid van Moolenbroek * service also verifies these aspects remotely, at least without talking to it
91*6f3e0bcdSDavid van Moolenbroek * directly.
92*6f3e0bcdSDavid van Moolenbroek */
93*6f3e0bcdSDavid van Moolenbroek static void
test_local_failures(void)94*6f3e0bcdSDavid van Moolenbroek test_local_failures(void)
95*6f3e0bcdSDavid van Moolenbroek {
96*6f3e0bcdSDavid van Moolenbroek int r, mib[CTL_SHORTNAME + 1];
97*6f3e0bcdSDavid van Moolenbroek
98*6f3e0bcdSDavid van Moolenbroek memset(mib, 0, sizeof(mib));
99*6f3e0bcdSDavid van Moolenbroek
100*6f3e0bcdSDavid van Moolenbroek /* Test an empty path. */
101*6f3e0bcdSDavid van Moolenbroek if ((r = rmib_register(mib, 0, &test_rnode)) != EINVAL)
102*6f3e0bcdSDavid van Moolenbroek panic("registering remote MIB subtree yielded: %d", r);
103*6f3e0bcdSDavid van Moolenbroek
104*6f3e0bcdSDavid van Moolenbroek /* Test a path that is too long. */
105*6f3e0bcdSDavid van Moolenbroek if ((r = rmib_register(mib, CTL_SHORTNAME + 1, &test_rnode)) != EINVAL)
106*6f3e0bcdSDavid van Moolenbroek panic("registering remote MIB subtree yielded: %d", r);
107*6f3e0bcdSDavid van Moolenbroek
108*6f3e0bcdSDavid van Moolenbroek /* Test a mount point that is not a node-type (parent) node. */
109*6f3e0bcdSDavid van Moolenbroek mib[0] = CTL_MINIX;
110*6f3e0bcdSDavid van Moolenbroek mib[1] = MINIX_TEST;
111*6f3e0bcdSDavid van Moolenbroek mib[2] = TEST_INT;
112*6f3e0bcdSDavid van Moolenbroek if ((r = rmib_register(mib, 3, &minix_test_table[TEST_INT])) != EINVAL)
113*6f3e0bcdSDavid van Moolenbroek panic("registering remote MIB subtree yielded: %d", r);
114*6f3e0bcdSDavid van Moolenbroek }
115*6f3e0bcdSDavid van Moolenbroek
116*6f3e0bcdSDavid van Moolenbroek /*
117*6f3e0bcdSDavid van Moolenbroek * Perform a number of registrations that will not be accepted by the MIB
118*6f3e0bcdSDavid van Moolenbroek * service. We will never know, but the userland test script can verify the
119*6f3e0bcdSDavid van Moolenbroek * difference by comparing the number of remotes before and after.
120*6f3e0bcdSDavid van Moolenbroek */
121*6f3e0bcdSDavid van Moolenbroek static void
test_remote_failures(void)122*6f3e0bcdSDavid van Moolenbroek test_remote_failures(void)
123*6f3e0bcdSDavid van Moolenbroek {
124*6f3e0bcdSDavid van Moolenbroek int r, mib[CTL_SHORTNAME];
125*6f3e0bcdSDavid van Moolenbroek
126*6f3e0bcdSDavid van Moolenbroek /* Test an existing one-node path. */
127*6f3e0bcdSDavid van Moolenbroek mib[0] = CTL_KERN;
128*6f3e0bcdSDavid van Moolenbroek if ((r = rmib_register(mib, 1, &test_rnode)) != OK)
129*6f3e0bcdSDavid van Moolenbroek panic("unable to register remote MIB subtree: %d", r);
130*6f3e0bcdSDavid van Moolenbroek rmib_reset();
131*6f3e0bcdSDavid van Moolenbroek
132*6f3e0bcdSDavid van Moolenbroek /* Test a path in which a non-final component does not exist. */
133*6f3e0bcdSDavid van Moolenbroek mib[1] = CREATE_BASE - 1; /* probably as safe as it gets.. */
134*6f3e0bcdSDavid van Moolenbroek mib[2] = 0;
135*6f3e0bcdSDavid van Moolenbroek if ((r = rmib_register(mib, 3, &test_rnode)) != OK)
136*6f3e0bcdSDavid van Moolenbroek panic("unable to register remote MIB subtree: %d", r);
137*6f3e0bcdSDavid van Moolenbroek rmib_reset();
138*6f3e0bcdSDavid van Moolenbroek
139*6f3e0bcdSDavid van Moolenbroek /* Test a path in which a non-final component is not a parent node. */
140*6f3e0bcdSDavid van Moolenbroek mib[1] = KERN_OSTYPE;
141*6f3e0bcdSDavid van Moolenbroek if ((r = rmib_register(mib, 3, &test_rnode)) != OK)
142*6f3e0bcdSDavid van Moolenbroek panic("unable to register remote MIB subtree: %d", r);
143*6f3e0bcdSDavid van Moolenbroek rmib_reset();
144*6f3e0bcdSDavid van Moolenbroek
145*6f3e0bcdSDavid van Moolenbroek /* Test a path in which a non-final component is a meta-identifier. */
146*6f3e0bcdSDavid van Moolenbroek mib[1] = CTL_QUERY;
147*6f3e0bcdSDavid van Moolenbroek if ((r = rmib_register(mib, 3, &test_rnode)) != OK)
148*6f3e0bcdSDavid van Moolenbroek panic("unable to register remote MIB subtree: %d", r);
149*6f3e0bcdSDavid van Moolenbroek rmib_reset();
150*6f3e0bcdSDavid van Moolenbroek
151*6f3e0bcdSDavid van Moolenbroek /* Test a path in which the final component is a meta-identifier. */
152*6f3e0bcdSDavid van Moolenbroek if ((r = rmib_register(mib, 2, &test_rnode)) != OK)
153*6f3e0bcdSDavid van Moolenbroek panic("unable to register remote MIB subtree: %d", r);
154*6f3e0bcdSDavid van Moolenbroek rmib_reset();
155*6f3e0bcdSDavid van Moolenbroek
156*6f3e0bcdSDavid van Moolenbroek /* Test a path in which the final component identifies a non-parent. */
157*6f3e0bcdSDavid van Moolenbroek mib[1] = KERN_OSTYPE;
158*6f3e0bcdSDavid van Moolenbroek if ((r = rmib_register(mib, 2, &test_rnode)) != OK)
159*6f3e0bcdSDavid van Moolenbroek panic("unable to register remote MIB subtree: %d", r);
160*6f3e0bcdSDavid van Moolenbroek rmib_reset();
161*6f3e0bcdSDavid van Moolenbroek
162*6f3e0bcdSDavid van Moolenbroek /* Test a path with unacceptable flags for the final component. */
163*6f3e0bcdSDavid van Moolenbroek mib[0] = CTL_MINIX;
164*6f3e0bcdSDavid van Moolenbroek mib[1] = MINIX_TEST;
165*6f3e0bcdSDavid van Moolenbroek mib[2] = TEST_SECRET;
166*6f3e0bcdSDavid van Moolenbroek if ((r = rmib_register(mib, 3, &test_rnode)) != OK)
167*6f3e0bcdSDavid van Moolenbroek panic("unable to register remote MIB subtree: %d", r);
168*6f3e0bcdSDavid van Moolenbroek rmib_reset();
169*6f3e0bcdSDavid van Moolenbroek
170*6f3e0bcdSDavid van Moolenbroek /* Test a path of which the name, but not the ID, already exists. */
171*6f3e0bcdSDavid van Moolenbroek mib[1] = CREATE_BASE - 1;
172*6f3e0bcdSDavid van Moolenbroek if ((r = rmib_register(mib, 2, &test_rnode)) != OK)
173*6f3e0bcdSDavid van Moolenbroek panic("unable to register remote MIB subtree: %d", r);
174*6f3e0bcdSDavid van Moolenbroek /*
175*6f3e0bcdSDavid van Moolenbroek * Do NOT call rmib_reset() anymore now: we want to let the MIB service
176*6f3e0bcdSDavid van Moolenbroek * get the name from us.
177*6f3e0bcdSDavid van Moolenbroek */
178*6f3e0bcdSDavid van Moolenbroek }
179*6f3e0bcdSDavid van Moolenbroek
180*6f3e0bcdSDavid van Moolenbroek static int
init(int type __unused,sef_init_info_t * info __unused)181*6f3e0bcdSDavid van Moolenbroek init(int type __unused, sef_init_info_t * info __unused)
182*6f3e0bcdSDavid van Moolenbroek {
183*6f3e0bcdSDavid van Moolenbroek const int new_mib[] = { CTL_MINIX, CREATE_BASE - 2 };
184*6f3e0bcdSDavid van Moolenbroek const int shadow_mib[] = { CTL_MINIX, MINIX_TEST };
185*6f3e0bcdSDavid van Moolenbroek int r;
186*6f3e0bcdSDavid van Moolenbroek
187*6f3e0bcdSDavid van Moolenbroek test_local_failures();
188*6f3e0bcdSDavid van Moolenbroek
189*6f3e0bcdSDavid van Moolenbroek test_remote_failures();
190*6f3e0bcdSDavid van Moolenbroek
191*6f3e0bcdSDavid van Moolenbroek /*
192*6f3e0bcdSDavid van Moolenbroek * We must now register our new test tree before shadowing minix.test,
193*6f3e0bcdSDavid van Moolenbroek * because if any of the previous requests actually did succeed, the
194*6f3e0bcdSDavid van Moolenbroek * next registration will be rejected (ID 0 already in use) and no
195*6f3e0bcdSDavid van Moolenbroek * difference would be detected because of "successful" shadowing.
196*6f3e0bcdSDavid van Moolenbroek */
197*6f3e0bcdSDavid van Moolenbroek r = rmib_register(new_mib, __arraycount(new_mib), &minix_rtest);
198*6f3e0bcdSDavid van Moolenbroek if (r != OK)
199*6f3e0bcdSDavid van Moolenbroek panic("unable to register remote MIB subtree: %d", r);
200*6f3e0bcdSDavid van Moolenbroek
201*6f3e0bcdSDavid van Moolenbroek r = rmib_register(shadow_mib, __arraycount(shadow_mib), &minix_test);
202*6f3e0bcdSDavid van Moolenbroek if (r != OK)
203*6f3e0bcdSDavid van Moolenbroek panic("unable to register remote MIB subtree: %d", r);
204*6f3e0bcdSDavid van Moolenbroek
205*6f3e0bcdSDavid van Moolenbroek running = TRUE;
206*6f3e0bcdSDavid van Moolenbroek
207*6f3e0bcdSDavid van Moolenbroek return OK;
208*6f3e0bcdSDavid van Moolenbroek }
209*6f3e0bcdSDavid van Moolenbroek
210*6f3e0bcdSDavid van Moolenbroek static void
cleanup(void)211*6f3e0bcdSDavid van Moolenbroek cleanup(void)
212*6f3e0bcdSDavid van Moolenbroek {
213*6f3e0bcdSDavid van Moolenbroek int r;
214*6f3e0bcdSDavid van Moolenbroek
215*6f3e0bcdSDavid van Moolenbroek if ((r = rmib_deregister(&minix_rtest)) != OK)
216*6f3e0bcdSDavid van Moolenbroek panic("unable to deregister: %d", r);
217*6f3e0bcdSDavid van Moolenbroek if ((r = rmib_deregister(&minix_test)) != OK)
218*6f3e0bcdSDavid van Moolenbroek panic("unable to deregister: %d", r);
219*6f3e0bcdSDavid van Moolenbroek
220*6f3e0bcdSDavid van Moolenbroek /*
221*6f3e0bcdSDavid van Moolenbroek * TODO: the fact that the MIB service can currently not detect the
222*6f3e0bcdSDavid van Moolenbroek * death of other services is creating somewhat of a problem here: if
223*6f3e0bcdSDavid van Moolenbroek * we deregister shortly before exiting, the asynchronous deregister
224*6f3e0bcdSDavid van Moolenbroek * requests may not be delivered before we actually exit (and take our
225*6f3e0bcdSDavid van Moolenbroek * asynsend table with us), and leave around the remote subtrees until
226*6f3e0bcdSDavid van Moolenbroek * a user process tries accessing them. We work around this here by
227*6f3e0bcdSDavid van Moolenbroek * delaying the exit by half a second - shorter than RS's timeout, but
228*6f3e0bcdSDavid van Moolenbroek * long enough to allow deregistration.
229*6f3e0bcdSDavid van Moolenbroek */
230*6f3e0bcdSDavid van Moolenbroek sys_setalarm(sys_hz() / 2, 0);
231*6f3e0bcdSDavid van Moolenbroek
232*6f3e0bcdSDavid van Moolenbroek running = FALSE;
233*6f3e0bcdSDavid van Moolenbroek }
234*6f3e0bcdSDavid van Moolenbroek
235*6f3e0bcdSDavid van Moolenbroek static void
got_signal(int sig)236*6f3e0bcdSDavid van Moolenbroek got_signal(int sig)
237*6f3e0bcdSDavid van Moolenbroek {
238*6f3e0bcdSDavid van Moolenbroek
239*6f3e0bcdSDavid van Moolenbroek if (sig == SIGTERM && running)
240*6f3e0bcdSDavid van Moolenbroek cleanup();
241*6f3e0bcdSDavid van Moolenbroek }
242*6f3e0bcdSDavid van Moolenbroek
243*6f3e0bcdSDavid van Moolenbroek int
main(void)244*6f3e0bcdSDavid van Moolenbroek main(void)
245*6f3e0bcdSDavid van Moolenbroek {
246*6f3e0bcdSDavid van Moolenbroek message m;
247*6f3e0bcdSDavid van Moolenbroek int r, ipc_status;
248*6f3e0bcdSDavid van Moolenbroek
249*6f3e0bcdSDavid van Moolenbroek sef_setcb_init_fresh(init);
250*6f3e0bcdSDavid van Moolenbroek sef_setcb_signal_handler(got_signal);
251*6f3e0bcdSDavid van Moolenbroek
252*6f3e0bcdSDavid van Moolenbroek sef_startup();
253*6f3e0bcdSDavid van Moolenbroek
254*6f3e0bcdSDavid van Moolenbroek for (;;) {
255*6f3e0bcdSDavid van Moolenbroek r = sef_receive_status(ANY, &m, &ipc_status);
256*6f3e0bcdSDavid van Moolenbroek
257*6f3e0bcdSDavid van Moolenbroek if (r != OK)
258*6f3e0bcdSDavid van Moolenbroek panic("sef_receive_status failed: %d", r);
259*6f3e0bcdSDavid van Moolenbroek
260*6f3e0bcdSDavid van Moolenbroek if (m.m_source == CLOCK && is_ipc_notify(ipc_status))
261*6f3e0bcdSDavid van Moolenbroek break; /* the intended exit path; see above */
262*6f3e0bcdSDavid van Moolenbroek if (m.m_source == MIB_PROC_NR)
263*6f3e0bcdSDavid van Moolenbroek rmib_process(&m, ipc_status);
264*6f3e0bcdSDavid van Moolenbroek }
265*6f3e0bcdSDavid van Moolenbroek
266*6f3e0bcdSDavid van Moolenbroek return EXIT_SUCCESS;
267*6f3e0bcdSDavid van Moolenbroek }
268