Merge branch 'reiserfs/kill-bkl' of git://git.kernel.org/pub/scm/linux/kernel/git...
[sfrench/cifs-2.6.git] / Documentation / connector / ucon.c
1 /*
2  *      ucon.c
3  *
4  * Copyright (c) 2004+ Evgeniy Polyakov <zbr@ioremap.net>
5  *
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20  */
21
22 #include <asm/types.h>
23
24 #include <sys/types.h>
25 #include <sys/socket.h>
26 #include <sys/poll.h>
27
28 #include <linux/netlink.h>
29 #include <linux/rtnetlink.h>
30
31 #include <arpa/inet.h>
32
33 #include <stdbool.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <unistd.h>
37 #include <string.h>
38 #include <errno.h>
39 #include <time.h>
40 #include <getopt.h>
41
42 #include <linux/connector.h>
43
44 #define DEBUG
45 #define NETLINK_CONNECTOR       11
46
47 /* Hopefully your userspace connector.h matches this kernel */
48 #define CN_TEST_IDX             CN_NETLINK_USERS + 3
49 #define CN_TEST_VAL             0x456
50
51 #ifdef DEBUG
52 #define ulog(f, a...) fprintf(stdout, f, ##a)
53 #else
54 #define ulog(f, a...) do {} while (0)
55 #endif
56
57 static int need_exit;
58 static __u32 seq;
59
60 static int netlink_send(int s, struct cn_msg *msg)
61 {
62         struct nlmsghdr *nlh;
63         unsigned int size;
64         int err;
65         char buf[128];
66         struct cn_msg *m;
67
68         size = NLMSG_SPACE(sizeof(struct cn_msg) + msg->len);
69
70         nlh = (struct nlmsghdr *)buf;
71         nlh->nlmsg_seq = seq++;
72         nlh->nlmsg_pid = getpid();
73         nlh->nlmsg_type = NLMSG_DONE;
74         nlh->nlmsg_len = NLMSG_LENGTH(size - sizeof(*nlh));
75         nlh->nlmsg_flags = 0;
76
77         m = NLMSG_DATA(nlh);
78 #if 0
79         ulog("%s: [%08x.%08x] len=%u, seq=%u, ack=%u.\n",
80                __func__, msg->id.idx, msg->id.val, msg->len, msg->seq, msg->ack);
81 #endif
82         memcpy(m, msg, sizeof(*m) + msg->len);
83
84         err = send(s, nlh, size, 0);
85         if (err == -1)
86                 ulog("Failed to send: %s [%d].\n",
87                         strerror(errno), errno);
88
89         return err;
90 }
91
92 static void usage(void)
93 {
94         printf(
95                 "Usage: ucon [options] [output file]\n"
96                 "\n"
97                 "\t-h\tthis help screen\n"
98                 "\t-s\tsend buffers to the test module\n"
99                 "\n"
100                 "The default behavior of ucon is to subscribe to the test module\n"
101                 "and wait for state messages.  Any ones received are dumped to the\n"
102                 "specified output file (or stdout).  The test module is assumed to\n"
103                 "have an id of {%u.%u}\n"
104                 "\n"
105                 "If you get no output, then verify the cn_test module id matches\n"
106                 "the expected id above.\n"
107                 , CN_TEST_IDX, CN_TEST_VAL
108         );
109 }
110
111 int main(int argc, char *argv[])
112 {
113         int s;
114         char buf[1024];
115         int len;
116         struct nlmsghdr *reply;
117         struct sockaddr_nl l_local;
118         struct cn_msg *data;
119         FILE *out;
120         time_t tm;
121         struct pollfd pfd;
122         bool send_msgs = false;
123
124         while ((s = getopt(argc, argv, "hs")) != -1) {
125                 switch (s) {
126                 case 's':
127                         send_msgs = true;
128                         break;
129
130                 case 'h':
131                         usage();
132                         return 0;
133
134                 default:
135                         /* getopt() outputs an error for us */
136                         usage();
137                         return 1;
138                 }
139         }
140
141         if (argc != optind) {
142                 out = fopen(argv[optind], "a+");
143                 if (!out) {
144                         ulog("Unable to open %s for writing: %s\n",
145                                 argv[1], strerror(errno));
146                         out = stdout;
147                 }
148         } else
149                 out = stdout;
150
151         memset(buf, 0, sizeof(buf));
152
153         s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
154         if (s == -1) {
155                 perror("socket");
156                 return -1;
157         }
158
159         l_local.nl_family = AF_NETLINK;
160         l_local.nl_groups = -1; /* bitmask of requested groups */
161         l_local.nl_pid = 0;
162
163         ulog("subscribing to %u.%u\n", CN_TEST_IDX, CN_TEST_VAL);
164
165         if (bind(s, (struct sockaddr *)&l_local, sizeof(struct sockaddr_nl)) == -1) {
166                 perror("bind");
167                 close(s);
168                 return -1;
169         }
170
171 #if 0
172         {
173                 int on = 0x57; /* Additional group number */
174                 setsockopt(s, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &on, sizeof(on));
175         }
176 #endif
177         if (send_msgs) {
178                 int i, j;
179
180                 memset(buf, 0, sizeof(buf));
181
182                 data = (struct cn_msg *)buf;
183
184                 data->id.idx = CN_TEST_IDX;
185                 data->id.val = CN_TEST_VAL;
186                 data->seq = seq++;
187                 data->ack = 0;
188                 data->len = 0;
189
190                 for (j=0; j<10; ++j) {
191                         for (i=0; i<1000; ++i) {
192                                 len = netlink_send(s, data);
193                         }
194
195                         ulog("%d messages have been sent to %08x.%08x.\n", i, data->id.idx, data->id.val);
196                 }
197
198                 return 0;
199         }
200
201
202         pfd.fd = s;
203
204         while (!need_exit) {
205                 pfd.events = POLLIN;
206                 pfd.revents = 0;
207                 switch (poll(&pfd, 1, -1)) {
208                         case 0:
209                                 need_exit = 1;
210                                 break;
211                         case -1:
212                                 if (errno != EINTR) {
213                                         need_exit = 1;
214                                         break;
215                                 }
216                                 continue;
217                 }
218                 if (need_exit)
219                         break;
220
221                 memset(buf, 0, sizeof(buf));
222                 len = recv(s, buf, sizeof(buf), 0);
223                 if (len == -1) {
224                         perror("recv buf");
225                         close(s);
226                         return -1;
227                 }
228                 reply = (struct nlmsghdr *)buf;
229
230                 switch (reply->nlmsg_type) {
231                 case NLMSG_ERROR:
232                         fprintf(out, "Error message received.\n");
233                         fflush(out);
234                         break;
235                 case NLMSG_DONE:
236                         data = (struct cn_msg *)NLMSG_DATA(reply);
237
238                         time(&tm);
239                         fprintf(out, "%.24s : [%x.%x] [%08u.%08u].\n",
240                                 ctime(&tm), data->id.idx, data->id.val, data->seq, data->ack);
241                         fflush(out);
242                         break;
243                 default:
244                         break;
245                 }
246         }
247
248         close(s);
249         return 0;
250 }