1 /* Remote MIB (RMIB) test service - by D.C. van Moolenbroek */
3 * This test is a good start, but not an exhaustive coverage test for all
4 * possible failure cases. The reason for that is mainly that there are
5 * various scenarios that we cannot generate without implementing our own local
6 * bogus RMIB code. Adding that is something for later - TODO.
8 #include <minix/drivers.h>
9 #include <minix/sysctl.h>
10 #include <minix/rmib.h>
14 /* The following is a copy of the minix.test subtree in the MIB service. */
15 static char test_string
[16], test_struct
[12];
17 static struct rmib_node minix_test_secret_table
[] = {
18 /* 0*/ [SECRET_VALUE
] = RMIB_INT(RMIB_RO
, 12345, "value",
19 "The combination to my luggage"),
22 static struct rmib_node minix_test_table
[] = {
23 /* 0*/ [TEST_INT
] = RMIB_INT(RMIB_RO
| CTLFLAG_HEX
, 0x01020304,
24 "int", "Value test field"),
25 /* 1*/ [TEST_BOOL
] = RMIB_BOOL(RMIB_RW
, 0, "bool",
26 "Boolean test field"),
27 /* 2*/ [TEST_QUAD
] = RMIB_QUAD(RMIB_RW
, 0, "quad",
29 /* 3*/ [TEST_STRING
] = RMIB_STRING(RMIB_RW
, test_string
, "string",
31 /* 4*/ [TEST_STRUCT
] = RMIB_STRUCT(RMIB_RW
, sizeof(test_struct
),
32 test_struct
, "struct",
33 "Structure test field"),
34 /* 5*/ [TEST_PRIVATE
] = RMIB_INT(RMIB_RW
| CTLFLAG_PRIVATE
, -5375,
35 "private", "Private test field"),
36 /* 6*/ [TEST_ANYWRITE
] = RMIB_INT(RMIB_RW
| CTLFLAG_ANYWRITE
, 0,
37 "anywrite", "AnyWrite test field"),
38 /* 7*/ [TEST_DYNAMIC
] = RMIB_INT(RMIB_RO
, 0, "deleteme",
39 "This node will be destroyed"),
40 /* 8*/ [TEST_SECRET
] = RMIB_NODE(RMIB_RO
| CTLFLAG_PRIVATE
,
41 minix_test_secret_table
, "secret",
43 /* 9*/ [TEST_PERM
] = RMIB_INT(RMIB_RO
, 1, "permanent", NULL
),
44 /*10*/ [TEST_DESTROY1
] = RMIB_INT(RMIB_RO
, 123, "destroy1", NULL
),
45 /*11*/ [TEST_DESTROY2
] = RMIB_INT(RMIB_RO
, 456, "destroy2",
46 "This node will be destroyed"),
49 static struct rmib_node minix_test
= RMIB_NODE(RMIB_RW
| CTLFLAG_HIDDEN
,
50 minix_test_table
, "test", "Test87 testing ground");
51 /* Here ends the copy of the minix.test subtree in the MIB service. */
53 static struct rmib_node test_table
[] = {
56 static struct rmib_node test_rnode
= RMIB_NODE(RMIB_RO
, test_table
, "test",
59 static int value
= 5375123;
61 static ssize_t
test_func(struct rmib_call
*, struct rmib_node
*,
62 struct rmib_oldp
*, struct rmib_newp
*);
64 /* No defined constants because userland will access these by name anyway. */
65 static struct rmib_node minix_rtest_table
[] = {
66 [1] = RMIB_INTPTR(RMIB_RW
, &value
, "int",
68 [2] = RMIB_FUNC(CTLTYPE_INT
| RMIB_RW
, sizeof(int),
69 test_func
, "func", "Test function"),
72 static struct rmib_node minix_rtest
= RMIB_NODE(RMIB_RO
, minix_rtest_table
,
73 "rtest", "Remote test subtree");
76 * Test function that deflects reads and writes to its sibling node. Not a
77 * super useful thing to do, but a decent test of functionality regardless.
80 test_func(struct rmib_call
* call
, struct rmib_node
* node
,
81 struct rmib_oldp
* oldp
, struct rmib_newp
* newp
)
84 return rmib_readwrite(call
, &minix_rtest_table
[1], oldp
, newp
);
88 * Attempt to perform registrations that should be rejected locally, and thus
89 * result in failure immediately. Unfortunately, we cannot verify that the MIB
90 * service also verifies these aspects remotely, at least without talking to it
94 test_local_failures(void)
96 int r
, mib
[CTL_SHORTNAME
+ 1];
98 memset(mib
, 0, sizeof(mib
));
100 /* Test an empty path. */
101 if ((r
= rmib_register(mib
, 0, &test_rnode
)) != EINVAL
)
102 panic("registering remote MIB subtree yielded: %d", r
);
104 /* Test a path that is too long. */
105 if ((r
= rmib_register(mib
, CTL_SHORTNAME
+ 1, &test_rnode
)) != EINVAL
)
106 panic("registering remote MIB subtree yielded: %d", r
);
108 /* Test a mount point that is not a node-type (parent) node. */
112 if ((r
= rmib_register(mib
, 3, &minix_test_table
[TEST_INT
])) != EINVAL
)
113 panic("registering remote MIB subtree yielded: %d", r
);
117 * Perform a number of registrations that will not be accepted by the MIB
118 * service. We will never know, but the userland test script can verify the
119 * difference by comparing the number of remotes before and after.
122 test_remote_failures(void)
124 int r
, mib
[CTL_SHORTNAME
];
126 /* Test an existing one-node path. */
128 if ((r
= rmib_register(mib
, 1, &test_rnode
)) != OK
)
129 panic("unable to register remote MIB subtree: %d", r
);
132 /* Test a path in which a non-final component does not exist. */
133 mib
[1] = CREATE_BASE
- 1; /* probably as safe as it gets.. */
135 if ((r
= rmib_register(mib
, 3, &test_rnode
)) != OK
)
136 panic("unable to register remote MIB subtree: %d", r
);
139 /* Test a path in which a non-final component is not a parent node. */
140 mib
[1] = KERN_OSTYPE
;
141 if ((r
= rmib_register(mib
, 3, &test_rnode
)) != OK
)
142 panic("unable to register remote MIB subtree: %d", r
);
145 /* Test a path in which a non-final component is a meta-identifier. */
147 if ((r
= rmib_register(mib
, 3, &test_rnode
)) != OK
)
148 panic("unable to register remote MIB subtree: %d", r
);
151 /* Test a path in which the final component is a meta-identifier. */
152 if ((r
= rmib_register(mib
, 2, &test_rnode
)) != OK
)
153 panic("unable to register remote MIB subtree: %d", r
);
156 /* Test a path in which the final component identifies a non-parent. */
157 mib
[1] = KERN_OSTYPE
;
158 if ((r
= rmib_register(mib
, 2, &test_rnode
)) != OK
)
159 panic("unable to register remote MIB subtree: %d", r
);
162 /* Test a path with unacceptable flags for the final component. */
165 mib
[2] = TEST_SECRET
;
166 if ((r
= rmib_register(mib
, 3, &test_rnode
)) != OK
)
167 panic("unable to register remote MIB subtree: %d", r
);
170 /* Test a path of which the name, but not the ID, already exists. */
171 mib
[1] = CREATE_BASE
- 1;
172 if ((r
= rmib_register(mib
, 2, &test_rnode
)) != OK
)
173 panic("unable to register remote MIB subtree: %d", r
);
175 * Do NOT call rmib_reset() anymore now: we want to let the MIB service
176 * get the name from us.
181 init(int type __unused
, sef_init_info_t
* info __unused
)
183 const int new_mib
[] = { CTL_MINIX
, CREATE_BASE
- 2 };
184 const int shadow_mib
[] = { CTL_MINIX
, MINIX_TEST
};
187 test_local_failures();
189 test_remote_failures();
192 * We must now register our new test tree before shadowing minix.test,
193 * because if any of the previous requests actually did succeed, the
194 * next registration will be rejected (ID 0 already in use) and no
195 * difference would be detected because of "successful" shadowing.
197 r
= rmib_register(new_mib
, __arraycount(new_mib
), &minix_rtest
);
199 panic("unable to register remote MIB subtree: %d", r
);
201 r
= rmib_register(shadow_mib
, __arraycount(shadow_mib
), &minix_test
);
203 panic("unable to register remote MIB subtree: %d", r
);
215 if ((r
= rmib_deregister(&minix_rtest
)) != OK
)
216 panic("unable to deregister: %d", r
);
217 if ((r
= rmib_deregister(&minix_test
)) != OK
)
218 panic("unable to deregister: %d", r
);
221 * TODO: the fact that the MIB service can currently not detect the
222 * death of other services is creating somewhat of a problem here: if
223 * we deregister shortly before exiting, the asynchronous deregister
224 * requests may not be delivered before we actually exit (and take our
225 * asynsend table with us), and leave around the remote subtrees until
226 * a user process tries accessing them. We work around this here by
227 * delaying the exit by half a second - shorter than RS's timeout, but
228 * long enough to allow deregistration.
230 sys_setalarm(sys_hz() / 2, 0);
239 if (sig
== SIGTERM
&& running
)
249 sef_setcb_init_fresh(init
);
250 sef_setcb_signal_handler(got_signal
);
255 r
= sef_receive_status(ANY
, &m
, &ipc_status
);
258 panic("sef_receive_status failed: %d", r
);
260 if (m
.m_source
== CLOCK
&& is_ipc_notify(ipc_status
))
261 break; /* the intended exit path; see above */
262 if (m
.m_source
== MIB_PROC_NR
)
263 rmib_process(&m
, ipc_status
);