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