1*1b481fc3SMaciej Żenczykowski /*
2*1b481fc3SMaciej Żenczykowski * monitor.c - netlink notification monitor
3*1b481fc3SMaciej Żenczykowski *
4*1b481fc3SMaciej Żenczykowski * Implementation of "ethtool --monitor" for watching netlink notifications.
5*1b481fc3SMaciej Żenczykowski */
6*1b481fc3SMaciej Żenczykowski
7*1b481fc3SMaciej Żenczykowski #include <errno.h>
8*1b481fc3SMaciej Żenczykowski
9*1b481fc3SMaciej Żenczykowski #include "../internal.h"
10*1b481fc3SMaciej Żenczykowski #include "netlink.h"
11*1b481fc3SMaciej Żenczykowski #include "nlsock.h"
12*1b481fc3SMaciej Żenczykowski #include "strset.h"
13*1b481fc3SMaciej Żenczykowski
14*1b481fc3SMaciej Żenczykowski static struct {
15*1b481fc3SMaciej Żenczykowski uint8_t cmd;
16*1b481fc3SMaciej Żenczykowski mnl_cb_t cb;
17*1b481fc3SMaciej Żenczykowski } monitor_callbacks[] = {
18*1b481fc3SMaciej Żenczykowski {
19*1b481fc3SMaciej Żenczykowski .cmd = ETHTOOL_MSG_LINKMODES_NTF,
20*1b481fc3SMaciej Żenczykowski .cb = linkmodes_reply_cb,
21*1b481fc3SMaciej Żenczykowski },
22*1b481fc3SMaciej Żenczykowski {
23*1b481fc3SMaciej Żenczykowski .cmd = ETHTOOL_MSG_LINKINFO_NTF,
24*1b481fc3SMaciej Żenczykowski .cb = linkinfo_reply_cb,
25*1b481fc3SMaciej Żenczykowski },
26*1b481fc3SMaciej Żenczykowski {
27*1b481fc3SMaciej Żenczykowski .cmd = ETHTOOL_MSG_WOL_NTF,
28*1b481fc3SMaciej Żenczykowski .cb = wol_reply_cb,
29*1b481fc3SMaciej Żenczykowski },
30*1b481fc3SMaciej Żenczykowski {
31*1b481fc3SMaciej Żenczykowski .cmd = ETHTOOL_MSG_DEBUG_NTF,
32*1b481fc3SMaciej Żenczykowski .cb = debug_reply_cb,
33*1b481fc3SMaciej Żenczykowski },
34*1b481fc3SMaciej Żenczykowski {
35*1b481fc3SMaciej Żenczykowski .cmd = ETHTOOL_MSG_FEATURES_NTF,
36*1b481fc3SMaciej Żenczykowski .cb = features_reply_cb,
37*1b481fc3SMaciej Żenczykowski },
38*1b481fc3SMaciej Żenczykowski {
39*1b481fc3SMaciej Żenczykowski .cmd = ETHTOOL_MSG_PRIVFLAGS_NTF,
40*1b481fc3SMaciej Żenczykowski .cb = privflags_reply_cb,
41*1b481fc3SMaciej Żenczykowski },
42*1b481fc3SMaciej Żenczykowski {
43*1b481fc3SMaciej Żenczykowski .cmd = ETHTOOL_MSG_RINGS_NTF,
44*1b481fc3SMaciej Żenczykowski .cb = rings_reply_cb,
45*1b481fc3SMaciej Żenczykowski },
46*1b481fc3SMaciej Żenczykowski {
47*1b481fc3SMaciej Żenczykowski .cmd = ETHTOOL_MSG_CHANNELS_NTF,
48*1b481fc3SMaciej Żenczykowski .cb = channels_reply_cb,
49*1b481fc3SMaciej Żenczykowski },
50*1b481fc3SMaciej Żenczykowski {
51*1b481fc3SMaciej Żenczykowski .cmd = ETHTOOL_MSG_COALESCE_NTF,
52*1b481fc3SMaciej Żenczykowski .cb = coalesce_reply_cb,
53*1b481fc3SMaciej Żenczykowski },
54*1b481fc3SMaciej Żenczykowski {
55*1b481fc3SMaciej Żenczykowski .cmd = ETHTOOL_MSG_PAUSE_NTF,
56*1b481fc3SMaciej Żenczykowski .cb = pause_reply_cb,
57*1b481fc3SMaciej Żenczykowski },
58*1b481fc3SMaciej Żenczykowski {
59*1b481fc3SMaciej Żenczykowski .cmd = ETHTOOL_MSG_EEE_NTF,
60*1b481fc3SMaciej Żenczykowski .cb = eee_reply_cb,
61*1b481fc3SMaciej Żenczykowski },
62*1b481fc3SMaciej Żenczykowski {
63*1b481fc3SMaciej Żenczykowski .cmd = ETHTOOL_MSG_CABLE_TEST_NTF,
64*1b481fc3SMaciej Żenczykowski .cb = cable_test_ntf_cb,
65*1b481fc3SMaciej Żenczykowski },
66*1b481fc3SMaciej Żenczykowski {
67*1b481fc3SMaciej Żenczykowski .cmd = ETHTOOL_MSG_CABLE_TEST_TDR_NTF,
68*1b481fc3SMaciej Żenczykowski .cb = cable_test_tdr_ntf_cb,
69*1b481fc3SMaciej Żenczykowski },
70*1b481fc3SMaciej Żenczykowski {
71*1b481fc3SMaciej Żenczykowski .cmd = ETHTOOL_MSG_FEC_NTF,
72*1b481fc3SMaciej Żenczykowski .cb = fec_reply_cb,
73*1b481fc3SMaciej Żenczykowski },
74*1b481fc3SMaciej Żenczykowski {
75*1b481fc3SMaciej Żenczykowski .cmd = ETHTOOL_MSG_MODULE_NTF,
76*1b481fc3SMaciej Żenczykowski .cb = module_reply_cb,
77*1b481fc3SMaciej Żenczykowski },
78*1b481fc3SMaciej Żenczykowski };
79*1b481fc3SMaciej Żenczykowski
clear_filter(struct nl_context * nlctx)80*1b481fc3SMaciej Żenczykowski static void clear_filter(struct nl_context *nlctx)
81*1b481fc3SMaciej Żenczykowski {
82*1b481fc3SMaciej Żenczykowski unsigned int i;
83*1b481fc3SMaciej Żenczykowski
84*1b481fc3SMaciej Żenczykowski for (i = 0; i < CMDMASK_WORDS; i++)
85*1b481fc3SMaciej Żenczykowski nlctx->filter_cmds[i] = 0;
86*1b481fc3SMaciej Żenczykowski }
87*1b481fc3SMaciej Żenczykowski
test_filter_cmd(const struct nl_context * nlctx,unsigned int cmd)88*1b481fc3SMaciej Żenczykowski static bool test_filter_cmd(const struct nl_context *nlctx, unsigned int cmd)
89*1b481fc3SMaciej Żenczykowski {
90*1b481fc3SMaciej Żenczykowski return nlctx->filter_cmds[cmd / 32] & (1U << (cmd % 32));
91*1b481fc3SMaciej Żenczykowski }
92*1b481fc3SMaciej Żenczykowski
set_filter_cmd(struct nl_context * nlctx,unsigned int cmd)93*1b481fc3SMaciej Żenczykowski static void set_filter_cmd(struct nl_context *nlctx, unsigned int cmd)
94*1b481fc3SMaciej Żenczykowski {
95*1b481fc3SMaciej Żenczykowski nlctx->filter_cmds[cmd / 32] |= (1U << (cmd % 32));
96*1b481fc3SMaciej Żenczykowski }
97*1b481fc3SMaciej Żenczykowski
set_filter_all(struct nl_context * nlctx)98*1b481fc3SMaciej Żenczykowski static void set_filter_all(struct nl_context *nlctx)
99*1b481fc3SMaciej Żenczykowski {
100*1b481fc3SMaciej Żenczykowski unsigned int i;
101*1b481fc3SMaciej Żenczykowski
102*1b481fc3SMaciej Żenczykowski for (i = 0; i < ARRAY_SIZE(monitor_callbacks); i++)
103*1b481fc3SMaciej Żenczykowski set_filter_cmd(nlctx, monitor_callbacks[i].cmd);
104*1b481fc3SMaciej Żenczykowski }
105*1b481fc3SMaciej Żenczykowski
monitor_any_cb(const struct nlmsghdr * nlhdr,void * data)106*1b481fc3SMaciej Żenczykowski static int monitor_any_cb(const struct nlmsghdr *nlhdr, void *data)
107*1b481fc3SMaciej Żenczykowski {
108*1b481fc3SMaciej Żenczykowski const struct genlmsghdr *ghdr = (const struct genlmsghdr *)(nlhdr + 1);
109*1b481fc3SMaciej Żenczykowski struct nl_context *nlctx = data;
110*1b481fc3SMaciej Żenczykowski unsigned int i;
111*1b481fc3SMaciej Żenczykowski
112*1b481fc3SMaciej Żenczykowski if (!test_filter_cmd(nlctx, ghdr->cmd))
113*1b481fc3SMaciej Żenczykowski return MNL_CB_OK;
114*1b481fc3SMaciej Żenczykowski
115*1b481fc3SMaciej Żenczykowski for (i = 0; i < MNL_ARRAY_SIZE(monitor_callbacks); i++)
116*1b481fc3SMaciej Żenczykowski if (monitor_callbacks[i].cmd == ghdr->cmd)
117*1b481fc3SMaciej Żenczykowski return monitor_callbacks[i].cb(nlhdr, data);
118*1b481fc3SMaciej Żenczykowski
119*1b481fc3SMaciej Żenczykowski return MNL_CB_OK;
120*1b481fc3SMaciej Żenczykowski }
121*1b481fc3SMaciej Żenczykowski
122*1b481fc3SMaciej Żenczykowski struct monitor_option {
123*1b481fc3SMaciej Żenczykowski const char *pattern;
124*1b481fc3SMaciej Żenczykowski uint8_t cmd;
125*1b481fc3SMaciej Żenczykowski uint32_t info_mask;
126*1b481fc3SMaciej Żenczykowski };
127*1b481fc3SMaciej Żenczykowski
128*1b481fc3SMaciej Żenczykowski static struct monitor_option monitor_opts[] = {
129*1b481fc3SMaciej Żenczykowski {
130*1b481fc3SMaciej Żenczykowski .pattern = "|--all",
131*1b481fc3SMaciej Żenczykowski .cmd = 0,
132*1b481fc3SMaciej Żenczykowski },
133*1b481fc3SMaciej Żenczykowski {
134*1b481fc3SMaciej Żenczykowski .pattern = "-s|--change",
135*1b481fc3SMaciej Żenczykowski .cmd = ETHTOOL_MSG_LINKINFO_NTF,
136*1b481fc3SMaciej Żenczykowski },
137*1b481fc3SMaciej Żenczykowski {
138*1b481fc3SMaciej Żenczykowski .pattern = "-s|--change",
139*1b481fc3SMaciej Żenczykowski .cmd = ETHTOOL_MSG_LINKMODES_NTF,
140*1b481fc3SMaciej Żenczykowski },
141*1b481fc3SMaciej Żenczykowski {
142*1b481fc3SMaciej Żenczykowski .pattern = "-s|--change",
143*1b481fc3SMaciej Żenczykowski .cmd = ETHTOOL_MSG_WOL_NTF,
144*1b481fc3SMaciej Żenczykowski },
145*1b481fc3SMaciej Żenczykowski {
146*1b481fc3SMaciej Żenczykowski .pattern = "-s|--change",
147*1b481fc3SMaciej Żenczykowski .cmd = ETHTOOL_MSG_DEBUG_NTF,
148*1b481fc3SMaciej Żenczykowski },
149*1b481fc3SMaciej Żenczykowski {
150*1b481fc3SMaciej Żenczykowski .pattern = "-k|--show-features|--show-offload|-K|--features|--offload",
151*1b481fc3SMaciej Żenczykowski .cmd = ETHTOOL_MSG_FEATURES_NTF,
152*1b481fc3SMaciej Żenczykowski },
153*1b481fc3SMaciej Żenczykowski {
154*1b481fc3SMaciej Żenczykowski .pattern = "--show-priv-flags|--set-priv-flags",
155*1b481fc3SMaciej Żenczykowski .cmd = ETHTOOL_MSG_PRIVFLAGS_NTF,
156*1b481fc3SMaciej Żenczykowski },
157*1b481fc3SMaciej Żenczykowski {
158*1b481fc3SMaciej Żenczykowski .pattern = "-g|--show-ring|-G|--set-ring",
159*1b481fc3SMaciej Żenczykowski .cmd = ETHTOOL_MSG_RINGS_NTF,
160*1b481fc3SMaciej Żenczykowski },
161*1b481fc3SMaciej Żenczykowski {
162*1b481fc3SMaciej Żenczykowski .pattern = "-l|--show-channels|-L|--set-channels",
163*1b481fc3SMaciej Żenczykowski .cmd = ETHTOOL_MSG_CHANNELS_NTF,
164*1b481fc3SMaciej Żenczykowski },
165*1b481fc3SMaciej Żenczykowski {
166*1b481fc3SMaciej Żenczykowski .pattern = "-c|--show-coalesce|-C|--coalesce",
167*1b481fc3SMaciej Żenczykowski .cmd = ETHTOOL_MSG_COALESCE_NTF,
168*1b481fc3SMaciej Żenczykowski },
169*1b481fc3SMaciej Żenczykowski {
170*1b481fc3SMaciej Żenczykowski .pattern = "-a|--show-pause|-A|--pause",
171*1b481fc3SMaciej Żenczykowski .cmd = ETHTOOL_MSG_PAUSE_NTF,
172*1b481fc3SMaciej Żenczykowski },
173*1b481fc3SMaciej Żenczykowski {
174*1b481fc3SMaciej Żenczykowski .pattern = "--show-eee|--set-eee",
175*1b481fc3SMaciej Żenczykowski .cmd = ETHTOOL_MSG_EEE_NTF,
176*1b481fc3SMaciej Żenczykowski },
177*1b481fc3SMaciej Żenczykowski {
178*1b481fc3SMaciej Żenczykowski .pattern = "--cable-test",
179*1b481fc3SMaciej Żenczykowski .cmd = ETHTOOL_MSG_CABLE_TEST_NTF,
180*1b481fc3SMaciej Żenczykowski },
181*1b481fc3SMaciej Żenczykowski {
182*1b481fc3SMaciej Żenczykowski .pattern = "--cable-test-tdr",
183*1b481fc3SMaciej Żenczykowski .cmd = ETHTOOL_MSG_CABLE_TEST_TDR_NTF,
184*1b481fc3SMaciej Żenczykowski },
185*1b481fc3SMaciej Żenczykowski {
186*1b481fc3SMaciej Żenczykowski .pattern = "--show-module|--set-module",
187*1b481fc3SMaciej Żenczykowski .cmd = ETHTOOL_MSG_MODULE_NTF,
188*1b481fc3SMaciej Żenczykowski },
189*1b481fc3SMaciej Żenczykowski };
190*1b481fc3SMaciej Żenczykowski
pattern_match(const char * s,const char * pattern)191*1b481fc3SMaciej Żenczykowski static bool pattern_match(const char *s, const char *pattern)
192*1b481fc3SMaciej Żenczykowski {
193*1b481fc3SMaciej Żenczykowski const char *opt = pattern;
194*1b481fc3SMaciej Żenczykowski const char *next;
195*1b481fc3SMaciej Żenczykowski int slen = strlen(s);
196*1b481fc3SMaciej Żenczykowski int optlen;
197*1b481fc3SMaciej Żenczykowski
198*1b481fc3SMaciej Żenczykowski do {
199*1b481fc3SMaciej Żenczykowski next = opt;
200*1b481fc3SMaciej Żenczykowski while (*next && *next != '|')
201*1b481fc3SMaciej Żenczykowski next++;
202*1b481fc3SMaciej Żenczykowski optlen = next - opt;
203*1b481fc3SMaciej Żenczykowski if (slen == optlen && !strncmp(s, opt, optlen))
204*1b481fc3SMaciej Żenczykowski return true;
205*1b481fc3SMaciej Żenczykowski
206*1b481fc3SMaciej Żenczykowski opt = next;
207*1b481fc3SMaciej Żenczykowski if (*opt == '|')
208*1b481fc3SMaciej Żenczykowski opt++;
209*1b481fc3SMaciej Żenczykowski } while (*opt);
210*1b481fc3SMaciej Żenczykowski
211*1b481fc3SMaciej Żenczykowski return false;
212*1b481fc3SMaciej Żenczykowski }
213*1b481fc3SMaciej Żenczykowski
parse_monitor(struct cmd_context * ctx)214*1b481fc3SMaciej Żenczykowski static int parse_monitor(struct cmd_context *ctx)
215*1b481fc3SMaciej Żenczykowski {
216*1b481fc3SMaciej Żenczykowski struct nl_context *nlctx = ctx->nlctx;
217*1b481fc3SMaciej Żenczykowski char **argp = ctx->argp;
218*1b481fc3SMaciej Żenczykowski int argc = ctx->argc;
219*1b481fc3SMaciej Żenczykowski const char *opt = "";
220*1b481fc3SMaciej Żenczykowski bool opt_found;
221*1b481fc3SMaciej Żenczykowski unsigned int i;
222*1b481fc3SMaciej Żenczykowski
223*1b481fc3SMaciej Żenczykowski if (*argp && argp[0][0] == '-') {
224*1b481fc3SMaciej Żenczykowski opt = *argp;
225*1b481fc3SMaciej Żenczykowski argp++;
226*1b481fc3SMaciej Żenczykowski argc--;
227*1b481fc3SMaciej Żenczykowski }
228*1b481fc3SMaciej Żenczykowski opt_found = false;
229*1b481fc3SMaciej Żenczykowski clear_filter(nlctx);
230*1b481fc3SMaciej Żenczykowski for (i = 0; i < MNL_ARRAY_SIZE(monitor_opts); i++) {
231*1b481fc3SMaciej Żenczykowski if (pattern_match(opt, monitor_opts[i].pattern)) {
232*1b481fc3SMaciej Żenczykowski unsigned int cmd = monitor_opts[i].cmd;
233*1b481fc3SMaciej Żenczykowski
234*1b481fc3SMaciej Żenczykowski if (!cmd)
235*1b481fc3SMaciej Żenczykowski set_filter_all(nlctx);
236*1b481fc3SMaciej Żenczykowski else
237*1b481fc3SMaciej Żenczykowski set_filter_cmd(nlctx, cmd);
238*1b481fc3SMaciej Żenczykowski opt_found = true;
239*1b481fc3SMaciej Żenczykowski }
240*1b481fc3SMaciej Żenczykowski }
241*1b481fc3SMaciej Żenczykowski if (!opt_found) {
242*1b481fc3SMaciej Żenczykowski fprintf(stderr, "monitoring for option '%s' not supported\n",
243*1b481fc3SMaciej Żenczykowski *argp);
244*1b481fc3SMaciej Żenczykowski return -1;
245*1b481fc3SMaciej Żenczykowski }
246*1b481fc3SMaciej Żenczykowski
247*1b481fc3SMaciej Żenczykowski if (*argp && strcmp(*argp, WILDCARD_DEVNAME))
248*1b481fc3SMaciej Żenczykowski ctx->devname = *argp;
249*1b481fc3SMaciej Żenczykowski return 0;
250*1b481fc3SMaciej Żenczykowski }
251*1b481fc3SMaciej Żenczykowski
nl_monitor(struct cmd_context * ctx)252*1b481fc3SMaciej Żenczykowski int nl_monitor(struct cmd_context *ctx)
253*1b481fc3SMaciej Żenczykowski {
254*1b481fc3SMaciej Żenczykowski struct nl_context *nlctx;
255*1b481fc3SMaciej Żenczykowski struct nl_socket *nlsk;
256*1b481fc3SMaciej Żenczykowski uint32_t grpid;
257*1b481fc3SMaciej Żenczykowski bool is_dev;
258*1b481fc3SMaciej Żenczykowski int ret;
259*1b481fc3SMaciej Żenczykowski
260*1b481fc3SMaciej Żenczykowski ret = netlink_init(ctx);
261*1b481fc3SMaciej Żenczykowski if (ret < 0) {
262*1b481fc3SMaciej Żenczykowski fprintf(stderr, "Netlink interface initialization failed, option --monitor not supported.\n");
263*1b481fc3SMaciej Żenczykowski return ret;
264*1b481fc3SMaciej Żenczykowski }
265*1b481fc3SMaciej Żenczykowski nlctx = ctx->nlctx;
266*1b481fc3SMaciej Żenczykowski nlsk = nlctx->ethnl_socket;
267*1b481fc3SMaciej Żenczykowski grpid = nlctx->ethnl_mongrp;
268*1b481fc3SMaciej Żenczykowski if (!grpid) {
269*1b481fc3SMaciej Żenczykowski fprintf(stderr, "multicast group 'monitor' not found\n");
270*1b481fc3SMaciej Żenczykowski return -EOPNOTSUPP;
271*1b481fc3SMaciej Żenczykowski }
272*1b481fc3SMaciej Żenczykowski
273*1b481fc3SMaciej Żenczykowski if (parse_monitor(ctx) < 0)
274*1b481fc3SMaciej Żenczykowski return 1;
275*1b481fc3SMaciej Żenczykowski is_dev = ctx->devname && strcmp(ctx->devname, WILDCARD_DEVNAME);
276*1b481fc3SMaciej Żenczykowski
277*1b481fc3SMaciej Żenczykowski ret = preload_global_strings(nlsk);
278*1b481fc3SMaciej Żenczykowski if (ret < 0)
279*1b481fc3SMaciej Żenczykowski return ret;
280*1b481fc3SMaciej Żenczykowski ret = mnl_socket_setsockopt(nlsk->sk, NETLINK_ADD_MEMBERSHIP,
281*1b481fc3SMaciej Żenczykowski &grpid, sizeof(grpid));
282*1b481fc3SMaciej Żenczykowski if (ret < 0)
283*1b481fc3SMaciej Żenczykowski return ret;
284*1b481fc3SMaciej Żenczykowski if (is_dev) {
285*1b481fc3SMaciej Żenczykowski ret = preload_perdev_strings(nlsk, ctx->devname);
286*1b481fc3SMaciej Żenczykowski if (ret < 0)
287*1b481fc3SMaciej Żenczykowski goto out_strings;
288*1b481fc3SMaciej Żenczykowski }
289*1b481fc3SMaciej Żenczykowski
290*1b481fc3SMaciej Żenczykowski nlctx->filter_devname = ctx->devname;
291*1b481fc3SMaciej Żenczykowski nlctx->is_monitor = true;
292*1b481fc3SMaciej Żenczykowski nlsk->port = 0;
293*1b481fc3SMaciej Żenczykowski nlsk->seq = 0;
294*1b481fc3SMaciej Żenczykowski
295*1b481fc3SMaciej Żenczykowski fputs("listening...\n", stdout);
296*1b481fc3SMaciej Żenczykowski fflush(stdout);
297*1b481fc3SMaciej Żenczykowski ret = nlsock_process_reply(nlsk, monitor_any_cb, nlctx);
298*1b481fc3SMaciej Żenczykowski
299*1b481fc3SMaciej Żenczykowski out_strings:
300*1b481fc3SMaciej Żenczykowski cleanup_all_strings();
301*1b481fc3SMaciej Żenczykowski return ret;
302*1b481fc3SMaciej Żenczykowski }
303*1b481fc3SMaciej Żenczykowski
nl_monitor_usage(void)304*1b481fc3SMaciej Żenczykowski void nl_monitor_usage(void)
305*1b481fc3SMaciej Żenczykowski {
306*1b481fc3SMaciej Żenczykowski unsigned int i;
307*1b481fc3SMaciej Żenczykowski const char *p;
308*1b481fc3SMaciej Żenczykowski
309*1b481fc3SMaciej Żenczykowski fputs(" ethtool --monitor Show kernel notifications\n",
310*1b481fc3SMaciej Żenczykowski stdout);
311*1b481fc3SMaciej Żenczykowski fputs(" ( [ --all ]", stdout);
312*1b481fc3SMaciej Żenczykowski for (i = 1; i < MNL_ARRAY_SIZE(monitor_opts); i++) {
313*1b481fc3SMaciej Żenczykowski if (!strcmp(monitor_opts[i].pattern, monitor_opts[i - 1].pattern))
314*1b481fc3SMaciej Żenczykowski continue;
315*1b481fc3SMaciej Żenczykowski fputs("\n | ", stdout);
316*1b481fc3SMaciej Żenczykowski for (p = monitor_opts[i].pattern; *p; p++)
317*1b481fc3SMaciej Żenczykowski if (*p == '|')
318*1b481fc3SMaciej Żenczykowski fputs(" | ", stdout);
319*1b481fc3SMaciej Żenczykowski else
320*1b481fc3SMaciej Żenczykowski fputc(*p, stdout);
321*1b481fc3SMaciej Żenczykowski }
322*1b481fc3SMaciej Żenczykowski fputs(" )\n", stdout);
323*1b481fc3SMaciej Żenczykowski fputs(" [ DEVNAME | * ]\n", stdout);
324*1b481fc3SMaciej Żenczykowski }
325