3 * Copyright (c) 2003 The Regents of the University of California. All
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * - Neither the name of the University nor the names of its
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS''
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
19 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
21 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
25 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 * FUSD - The Framework for UserSpace Devices - Example program
35 * Jeremy Elson <jelson@circlemud.org>
37 * ioctl.c: Shows both the client side and server side of FUSD ioctl
40 * There's a lot of extra cruft in this example program (compared to
41 * the other examples, anyway), because this program is both an
42 * example and part of the regression test suite.
53 #include <sys/fcntl.h>
54 #include <sys/ioctl.h>
59 /* EXAMPLE START ioctl.h */
60 /* definition of the structure exchanged between client and server */
66 #define IOCTL_APP_TYPE 71 /* arbitrary number unique to this app */
68 #define IOCTL_TEST0 _IO(IOCTL_APP_TYPE, 0) /* no argument */ /* SKIPLINE */
69 #define IOCTL_TEST1 _IO(IOCTL_APP_TYPE, 1) /* int argument */ /* SKIPLINE */
70 #define IOCTL_TEST2 _IO(IOCTL_APP_TYPE, 2) /* int argument */
71 #define IOCTL_TEST3 _IOR(IOCTL_APP_TYPE, 3, struct ioctl_data_t)
72 #define IOCTL_TEST4 _IOW(IOCTL_APP_TYPE, 4, struct ioctl_data_t)
73 #define IOCTL_TEST5 _IOWR(IOCTL_APP_TYPE, 5, struct ioctl_data_t)
74 /* EXAMPLE STOP ioctl.h */
75 #define IOCTL_TEST_TERMINATE _IO(IOCTL_APP_TYPE, 6)
77 #define TEST1_NUM 12345
78 #define TEST3_STRING1 "This is test3 - string1"
79 #define TEST3_STRING2 "This is test3 - string2"
80 #define TEST4_STRING1 "This is test 4's string1"
81 #define TEST4_STRING2 "This is test 4's string2"
82 #define TEST5_STRING1_IN "If you're happy and you know it"
83 #define TEST5_STRING2_IN "clap your hands!"
84 #define TEST5_STRING1_OUT "IF YOU'RE HAPPY AND YOU KNOW IT"
85 #define TEST5_STRING2_OUT "CLAP YOUR HANDS!"
88 #define CHECK(condition) do { \
90 printf("%s: TEST FAILED\n", __STRING(condition)); \
96 int zeroreturn(struct fusd_file_info
*file
) { return 0; }
98 /* EXAMPLE START ioctl-server.c */
99 /* This function is run by the driver */
100 int do_ioctl(struct fusd_file_info
*file
, int cmd
, void *arg
)
102 static int errors
= 0; /* SKIPLINE */
103 char *c
; /* SKIPLINE */
104 struct ioctl_data_t
*d
;
106 if (_IOC_TYPE(cmd
) != IOCTL_APP_TYPE
)
110 /* EXAMPLE STOP ioctl-server.c */
112 printf("ioctl server: got test0, returning 0\n");
118 printf("ioctl server: got test1/2, arg=%p, *arg= %d, returning it\n",
123 /* EXAMPLE START ioctl-server.c */
124 case IOCTL_TEST3
: /* returns data to the client */
126 printf("ioctl server: got test3 request (read-only)\n");/* SKIPLINE */
127 printf("ioctl server: ...returning test strings for client to read\n"); /* SKIPLINE */
128 strcpy(d
->string1
, TEST3_STRING1
);
129 strcpy(d
->string2
, TEST3_STRING2
);
133 case IOCTL_TEST4
: /* gets data from the client */
135 printf("ioctl server: got test4 request (write-only)\n"); /* SKIPLINE */
136 printf("ioctl server: ...got the following strings written by client:\n"); /* SKIPLINE */
137 printf("ioctl server: test4, string1: got '%s'\n", d
->string1
);
138 printf("ioctl server: test4, string2: got '%s'\n", d
->string2
);
139 CHECK(!strcmp(d
->string1
, TEST4_STRING1
));/* SKIPLINE */
140 CHECK(!strcmp(d
->string2
, TEST4_STRING2
)); /* SKIPLINE */
143 /* EXAMPLE STOP ioctl-server.c */
147 printf("ioctl server: got test5 request (read+write)\n");
148 printf("ioctl server: test5, string1: got '%s'\n", d
->string1
);
149 printf("ioctl server: test5, string2: got '%s'\n", d
->string2
);
150 printf("ioctl server: capitalizing the strings and returning them\n");
151 for (c
= d
->string1
; *c
; c
++)
153 for (c
= d
->string2
; *c
; c
++)
158 case IOCTL_TEST_TERMINATE
:
159 printf("ioctl server: got request to terminate, calling exit(%d)\n",
161 printf("ioctl server: note: client should see -EPIPE\n");
165 /* EXAMPLE START ioctl-server.c */
167 printf("ioctl server: got unknown cmd, sigh, this is broken\n");
174 /* EXAMPLE STOP ioctl-server.c */
176 int main(int argc
, char *argv
[])
178 pid_t server_pid
, retpid
;
180 if ((server_pid
= fork()) < 0) {
181 perror("error creating server");
185 if (server_pid
== 0) {
187 struct fusd_file_operations f
= { open
: zeroreturn
, close
: zeroreturn
,
189 if (fusd_register("/dev/ioctltest", "misc", "ioctltest",
191 perror("registering ioctltest");
192 printf("server starting\n");
196 /* EXAMPLE START ioctl-client.c */
198 struct ioctl_data_t d
;
199 /* EXAMPLE STOP ioctl-client.c */
205 /* EXAMPLE START ioctl-client.c */
207 if ((fd
= open("/dev/ioctltest", O_RDWR
)) < 0) {
208 perror("client: can't open ioctltest");
212 /* EXAMPLE STOP ioctl-client.c */
215 /* test0: simply issue a command and get a retval */
216 ret
= ioctl(fd
, IOCTL_TEST0
);
217 printf("ioctl test0: got %d (expecting 0)\n\n", ret
);
220 /* test1: issue a command with a simple (integer) argument */
223 ret
= ioctl(fd
, IOCTL_TEST1
, &arg
);
224 CHECK(ret
== TEST1_NUM
);
226 printf("ioctl test1: got %d, errno=%d (expecting %d, errno=0)\n\n",
227 ret
, errno
, TEST1_NUM
);
230 /* test2 again: make sure errno is set properly */
233 ret
= ioctl(fd
, IOCTL_TEST2
, &arg
);
234 CHECK(errno
== ELIBBAD
);
236 printf("ioctl test2: got %d, errno=%d (expecting -1, errno=%d)\n\n",
237 ret
, errno
, ELIBBAD
);
240 printf("ioctl test3: expecting retval 0, string This Is Test3\n");
241 /* EXAMPLE START ioctl-client.c */
242 /* test3: make sure we can get data FROM a driver using ioctl */
243 ret
= ioctl(fd
, IOCTL_TEST3
, &d
);
244 CHECK(ret
== 0); /* SKIPLINE */
245 CHECK(!strcmp(d
.string1
, TEST3_STRING1
)); /* SKIPLINE */
246 CHECK(!strcmp(d
.string2
, TEST3_STRING2
)); /* SKIPLINE */
247 printf("ioctl test3: got retval=%d\n", ret
);
248 printf("ioctl test3: got string1='%s'\n", d
.string1
);
249 printf("ioctl test3: got string2='%s'\n", d
.string2
);
250 printf("\n"); /* SKIPLINE */
252 /* test4: make sure we can send data TO a driver using an ioctl */
253 printf("ioctl test4: server should see string 'This Is Test4'\n");/* SKIPLINE */
254 sprintf(d
.string1
, TEST4_STRING1
);
255 sprintf(d
.string2
, TEST4_STRING2
);
256 ret
= ioctl(fd
, IOCTL_TEST4
, &d
);
257 /* EXAMPLE STOP ioctl-client.c */
261 /* test5: we send 2 strings to the ioctl server, they should come
262 * back in all caps */
263 printf("ioctl test5: we send strings that should come back capitalized\n");
264 sprintf(d
.string1
, TEST5_STRING1_IN
);
265 sprintf(d
.string2
, TEST5_STRING2_IN
);
266 printf("ioctl test5: sending string1='%s'\n", d
.string1
);
267 printf("ioctl test5: sending string2='%s'\n", d
.string2
);
268 ret
= ioctl(fd
, IOCTL_TEST5
, &d
);
270 CHECK(!strcmp(d
.string1
, TEST5_STRING1_OUT
));
271 CHECK(!strcmp(d
.string2
, TEST5_STRING2_OUT
));
272 printf("ioctl test5: got retval=%d\n", ret
);
273 printf("ioctl test5: got back string1='%s'\n", d
.string1
);
274 printf("ioctl test5: got back string2='%s'\n", d
.string2
);
277 /* now tell the server to terminate, we should get EPIPE */
278 ret
= ioctl(fd
, IOCTL_TEST_TERMINATE
);
279 CHECK(errno
== EPIPE
);
281 printf("ioctl termination test: got %d (errno=%d)\n", ret
, errno
);
282 printf("ioctl termination tets: expecting ret=-1, errno=%d\n\n", EPIPE
);
284 printf("ioctl client: waiting for server to terminate...\n");
285 retpid
= wait(&status
);
286 CHECK(retpid
== server_pid
);
287 CHECK(WEXITSTATUS(status
) == 0);
289 printf("ioctl test done - %d errors\n", errors
);
291 printf("IOCTL REGRESSION TEST FAILED\n");
294 printf("all tests passed\n");