]> git.proxmox.com Git - mirror_qemu.git/blob - contrib/ivshmem-server/main.c
ivshmem-server: Fix and clean up command line help
[mirror_qemu.git] / contrib / ivshmem-server / main.c
1 /*
2 * Copyright 6WIND S.A., 2014
3 *
4 * This work is licensed under the terms of the GNU GPL, version 2 or
5 * (at your option) any later version. See the COPYING file in the
6 * top-level directory.
7 */
8
9 #include "qemu/osdep.h"
10 #include "qemu-common.h"
11
12 #include "ivshmem-server.h"
13
14 #define IVSHMEM_SERVER_DEFAULT_VERBOSE 0
15 #define IVSHMEM_SERVER_DEFAULT_FOREGROUND 0
16 #define IVSHMEM_SERVER_DEFAULT_PID_FILE "/var/run/ivshmem-server.pid"
17 #define IVSHMEM_SERVER_DEFAULT_UNIX_SOCK_PATH "/tmp/ivshmem_socket"
18 #define IVSHMEM_SERVER_DEFAULT_SHM_PATH "ivshmem"
19 #define IVSHMEM_SERVER_DEFAULT_SHM_SIZE (4*1024*1024)
20 #define IVSHMEM_SERVER_DEFAULT_N_VECTORS 1
21
22 /* used to quit on signal SIGTERM */
23 static int ivshmem_server_quit;
24
25 /* arguments given by the user */
26 typedef struct IvshmemServerArgs {
27 bool verbose;
28 bool foreground;
29 const char *pid_file;
30 const char *unix_socket_path;
31 const char *shm_path;
32 uint64_t shm_size;
33 unsigned n_vectors;
34 } IvshmemServerArgs;
35
36 static void
37 ivshmem_server_usage(const char *progname)
38 {
39 printf("Usage: %s [OPTION]...\n"
40 " -h: show this help\n"
41 " -v: verbose mode\n"
42 " -F: foreground mode (default is to daemonize)\n"
43 " -p <pid-file>: path to the PID file (used in daemon mode only)\n"
44 " default " IVSHMEM_SERVER_DEFAULT_PID_FILE "\n"
45 " -S <unix-socket-path>: path to the unix socket to listen to\n"
46 " default " IVSHMEM_SERVER_DEFAULT_UNIX_SOCK_PATH "\n"
47 " -m <shm-path>: POSIX shared memory object name or a hugetlbfs mount point\n"
48 " default " IVSHMEM_SERVER_DEFAULT_SHM_PATH "\n"
49 " -l <size>: size of shared memory in bytes\n"
50 " suffixes K, M and G can be used, e.g. 1K means 1024\n"
51 " default %u\n"
52 " -n <nvectors>: number of vectors\n"
53 " default %u\n",
54 progname, IVSHMEM_SERVER_DEFAULT_SHM_SIZE,
55 IVSHMEM_SERVER_DEFAULT_N_VECTORS);
56 }
57
58 static void
59 ivshmem_server_help(const char *progname)
60 {
61 fprintf(stderr, "Try '%s -h' for more information.\n", progname);
62 }
63
64 /* parse the program arguments, exit on error */
65 static void
66 ivshmem_server_parse_args(IvshmemServerArgs *args, int argc, char *argv[])
67 {
68 int c;
69 unsigned long long v;
70 Error *err = NULL;
71
72 while ((c = getopt(argc, argv, "hvFp:S:m:l:n:")) != -1) {
73
74 switch (c) {
75 case 'h': /* help */
76 ivshmem_server_usage(argv[0]);
77 exit(0);
78 break;
79
80 case 'v': /* verbose */
81 args->verbose = 1;
82 break;
83
84 case 'F': /* foreground */
85 args->foreground = 1;
86 break;
87
88 case 'p': /* pid file */
89 args->pid_file = optarg;
90 break;
91
92 case 'S': /* unix socket path */
93 args->unix_socket_path = optarg;
94 break;
95
96 case 'm': /* shm path */
97 args->shm_path = optarg;
98 break;
99
100 case 'l': /* shm size */
101 parse_option_size("shm_size", optarg, &args->shm_size, &err);
102 if (err) {
103 error_report_err(err);
104 ivshmem_server_help(argv[0]);
105 exit(1);
106 }
107 break;
108
109 case 'n': /* number of vectors */
110 if (parse_uint_full(optarg, &v, 0) < 0) {
111 fprintf(stderr, "cannot parse n_vectors\n");
112 ivshmem_server_help(argv[0]);
113 exit(1);
114 }
115 args->n_vectors = v;
116 break;
117
118 default:
119 ivshmem_server_usage(argv[0]);
120 exit(1);
121 break;
122 }
123 }
124
125 if (args->n_vectors > IVSHMEM_SERVER_MAX_VECTORS) {
126 fprintf(stderr, "too many requested vectors (max is %d)\n",
127 IVSHMEM_SERVER_MAX_VECTORS);
128 ivshmem_server_help(argv[0]);
129 exit(1);
130 }
131
132 if (args->verbose == 1 && args->foreground == 0) {
133 fprintf(stderr, "cannot use verbose in daemon mode\n");
134 ivshmem_server_help(argv[0]);
135 exit(1);
136 }
137 }
138
139 /* wait for events on listening server unix socket and connected client
140 * sockets */
141 static int
142 ivshmem_server_poll_events(IvshmemServer *server)
143 {
144 fd_set fds;
145 int ret = 0, maxfd;
146
147 while (!ivshmem_server_quit) {
148
149 FD_ZERO(&fds);
150 maxfd = 0;
151 ivshmem_server_get_fds(server, &fds, &maxfd);
152
153 ret = select(maxfd, &fds, NULL, NULL, NULL);
154
155 if (ret < 0) {
156 if (errno == EINTR) {
157 continue;
158 }
159
160 fprintf(stderr, "select error: %s\n", strerror(errno));
161 break;
162 }
163 if (ret == 0) {
164 continue;
165 }
166
167 if (ivshmem_server_handle_fds(server, &fds, maxfd) < 0) {
168 fprintf(stderr, "ivshmem_server_handle_fds() failed\n");
169 break;
170 }
171 }
172
173 return ret;
174 }
175
176 static void
177 ivshmem_server_quit_cb(int signum)
178 {
179 ivshmem_server_quit = 1;
180 }
181
182 int
183 main(int argc, char *argv[])
184 {
185 IvshmemServer server;
186 struct sigaction sa, sa_quit;
187 IvshmemServerArgs args = {
188 .verbose = IVSHMEM_SERVER_DEFAULT_VERBOSE,
189 .foreground = IVSHMEM_SERVER_DEFAULT_FOREGROUND,
190 .pid_file = IVSHMEM_SERVER_DEFAULT_PID_FILE,
191 .unix_socket_path = IVSHMEM_SERVER_DEFAULT_UNIX_SOCK_PATH,
192 .shm_path = IVSHMEM_SERVER_DEFAULT_SHM_PATH,
193 .shm_size = IVSHMEM_SERVER_DEFAULT_SHM_SIZE,
194 .n_vectors = IVSHMEM_SERVER_DEFAULT_N_VECTORS,
195 };
196 int ret = 1;
197
198 /* parse arguments, will exit on error */
199 ivshmem_server_parse_args(&args, argc, argv);
200
201 /* Ignore SIGPIPE, see this link for more info:
202 * http://www.mail-archive.com/libevent-users@monkey.org/msg01606.html */
203 sa.sa_handler = SIG_IGN;
204 sa.sa_flags = 0;
205 if (sigemptyset(&sa.sa_mask) == -1 ||
206 sigaction(SIGPIPE, &sa, 0) == -1) {
207 perror("failed to ignore SIGPIPE; sigaction");
208 goto err;
209 }
210
211 sa_quit.sa_handler = ivshmem_server_quit_cb;
212 sa_quit.sa_flags = 0;
213 if (sigemptyset(&sa_quit.sa_mask) == -1 ||
214 sigaction(SIGTERM, &sa_quit, 0) == -1) {
215 perror("failed to add SIGTERM handler; sigaction");
216 goto err;
217 }
218
219 /* init the ivshms structure */
220 if (ivshmem_server_init(&server, args.unix_socket_path, args.shm_path,
221 args.shm_size, args.n_vectors, args.verbose) < 0) {
222 fprintf(stderr, "cannot init server\n");
223 goto err;
224 }
225
226 /* start the ivshmem server (open shm & unix socket) */
227 if (ivshmem_server_start(&server) < 0) {
228 fprintf(stderr, "cannot bind\n");
229 goto err;
230 }
231
232 /* daemonize if asked to */
233 if (!args.foreground) {
234 FILE *fp;
235
236 if (qemu_daemon(1, 1) < 0) {
237 fprintf(stderr, "cannot daemonize: %s\n", strerror(errno));
238 goto err_close;
239 }
240
241 /* write pid file */
242 fp = fopen(args.pid_file, "w");
243 if (fp == NULL) {
244 fprintf(stderr, "cannot write pid file: %s\n", strerror(errno));
245 goto err_close;
246 }
247
248 fprintf(fp, "%d\n", (int) getpid());
249 fclose(fp);
250 }
251
252 ivshmem_server_poll_events(&server);
253 fprintf(stdout, "server disconnected\n");
254 ret = 0;
255
256 err_close:
257 ivshmem_server_close(&server);
258 err:
259 return ret;
260 }