int main(int argc, char *argv[]) { int c = 0; int maxcore = 0; bool do_daemonize = false; char *pid_file = "/tmp/memlockd.pid"; char *username = NULL; struct passwd *pw = NULL; struct rlimit rlim; /* register signal callback */ signals_init(); /* init settings */ settings_init(); /* set stderr non-buffering (for running under, say, daemontools) */ setbuf(stderr, NULL); /* process arguments */ while ((c = getopt(argc, argv, "a:U:p:s:c:hivl:dru:P:t")) != -1) { switch (c) { case 'a': /* access for unix domain socket, as octal mask (like chmod)*/ settings.access = strtol(optarg, NULL, 8); break; case 'p': settings.port = atoi(optarg); break; case 's': settings.socketpath = optarg; break; case 'c': settings.maxconns = atoi(optarg); break; case 'h': usage(); exit(EXIT_SUCCESS); case 'i': usage_license(); exit(EXIT_SUCCESS); case 'v': settings.verbose++; break; case 'l': settings.inter = strdup(optarg); break; case 'd': do_daemonize = true; break; case 'r': maxcore = 1; break; case 'u': username = optarg; break; case 'P': pid_file = optarg; break; #ifdef USE_THREADS case 't': settings.num_threads = atoi(optarg); if (0 == settings.num_threads) { fprintf(stderr, "Number of threads must be greater than 0\n"); exit(EXIT_FAILURE); } break; #endif default: fprintf(stderr, "Illegal argument \"%c\"\n", c); exit(EXIT_FAILURE); } } /* * If needed, increase rlimits to allow as many connections * as needed. */ if (getrlimit(RLIMIT_NOFILE, &rlim) != 0) { fprintf(stderr, "failed to getrlimit number of files\n"); exit(EXIT_FAILURE); } else { int maxfiles = settings.maxconns; if (rlim.rlim_cur < maxfiles) { rlim.rlim_cur = maxfiles + 3; } if (rlim.rlim_max < rlim.rlim_cur) { rlim.rlim_max = rlim.rlim_cur; } if (setrlimit(RLIMIT_NOFILE, &rlim) != 0) { fprintf(stderr, "failed to set rlimit for open files. Try " "running as root or requesting smaller maxconns value.\n"); exit(EXIT_FAILURE); } } /* do_daemonize if requested */ /* if we want to ensure our ability to dump core, don't chdir to / */ if (do_daemonize) { int res = 0; res = daemon_init(); if (res != 0) { fprintf(stderr, "failed to daemon() in order to do_daemonize\n"); return -1; } } /* lose root privileges if we have them */ if (0 == getuid() || 0 == geteuid()) { if (NULL == username || '\0' == *username) { fprintf(stderr, "can't run as root without the -u switch\n"); return -1; } if ((pw = getpwnam(username)) == NULL) { fprintf(stderr, "can't find the user %s to switch to\n", username); return 1; } if (setgid(pw->pw_gid) < 0 || setuid(pw->pw_uid) < 0) { fprintf(stderr, "failed to assume identity of user %s\n", username); return 1; } } /* initialize main thread libevent instance */ main_base = event_init(); /* initialize other stuff */ hashlist_init(); conn_init(); stats.started = time(NULL); /* start up worker threads if MT mode */ //thread_init(settings.num_threads, main_base); if (do_daemonize) { if (daemon_already_running(pid_file) < 0) { fprintf(stderr, "server is already running.\n"); exit(EXIT_FAILURE); } } INIT_LIST_HEAD(&listen_conn); /* create unix mode sockets after dropping privileges */ if (settings.socketpath != NULL) { if (socket_unix_init(settings.socketpath, settings.access)) { fprintf(stderr, "failed to listen\n"); exit(EXIT_FAILURE); } } /* create the listening socket, bind it, and init */ if (settings.socketpath == NULL) { if (socket_init(settings.port) < 0) { fprintf(stderr, "failed to listen\n"); exit(EXIT_FAILURE); } } /* start checkpoint and deadlock detect thread */ /* enter the event loop */ event_base_loop(main_base, 0); hashlist_close(); if (do_daemonize) { unlink(pid_file); } return 0; }
int main(int argc, char *argv[]) { int c; int do_daemonize= 0; int maxcore = 0; struct rlimit rlim; char unit = '\0'; int size_max = 0; int protocol_specified = 0; int tcp_specified = 0; int udp_specified = 0; char *subopts; char *subopts_value; enum { MAXCONNS_FAST = 0, HASHPOWER_INIT, SLAB_REASSIGN, SLAB_AUTOMOVE }; char *const subopts_tokens[] = { [MAXCONNS_FAST] = "maxconns_fast", [HASHPOWER_INIT]= "hashpower", [SLAB_REASSIGN] = "slab_reassign", [SLAB_AUTOMOVE] = "slab_automove", NULL }; /* init settings */ settings_init(); /* set stderr non-buffering (for running under, say, daemontools) */ setbuf(stderr, NULL); /* process arguments */ while (-1 != (c = getopt(argc, argv, "a:" /* access mask for unix socket */ "A" /* enable admin shutdown commannd */ "p:" /* TCP port number to listen on */ "s:" /* unix socket path to listen on */ "U:" /* UDP port number to listen on */ "m:" /* max memory to use for items in megabytes */ "M" /* return error on memory exhausted */ "c:" /* max simultaneous connections */ "hi" /* help, licence info */ "r" /* maximize core file limit */ "v" /* verbose */ "d" /* daemon mode */ "l:" /* interface to listen on */ "f:" /* factor? */ "n:" /* minimum space allocated for key+value+flags */ "D:" /* prefix delimiter? */ "L" /* Large memory pages */ "R:" /* max requests per event */ "C" /* Disable use of CAS */ "b:" /* backlog queue limit */ "B:" /* Binding protocol */ "I:" /* Max item size */ "S" /* Sasl ON */ "o:" /* Extended generic options */ ))) { switch (c) { case 'A': /* enables "shutdown" command */ settings.shutdown_command = 1; break; case 'a': /* access for unix domain socket, as octal mask (like chmod)*/ settings.access= strtol(optarg,NULL,8); break; case 'U': settings.udpport = atoi(optarg); udp_specified = 1; break; case 'p': settings.port = atoi(optarg); tcp_specified = 1; break; case 's': settings.socketpath = optarg; break; case 'm': settings.maxbytes = ((size_t)atoi(optarg)) * 1024 * 1024; break; case 'M': settings.evict_to_free = 0; break; case 'c': settings.maxconns = atoi(optarg); break; case 'h': usage(); exit(EXIT_SUCCESS); case 'i': usage_license(); exit(EXIT_SUCCESS); case 'v': settings.verbose++; break; case 'l': if (settings.inter != NULL) { size_t len = strlen(settings.inter) + strlen(optarg) + 2; char *p = malloc(len); if (p == NULL) { fprintf(stderr, "Failed to allocate memory\n"); return 1; } snprintf(p, len, "%s,%s", settings.inter, optarg); free(settings.inter); settings.inter = p; } else { settings.inter= strdup(optarg); } break; case 'd': do_daemonize = 1; break; case 'r': maxcore = 1; break; case 'R': settings.reqs_per_event = atoi(optarg); if (settings.reqs_per_event == 0) { fprintf(stderr, "Number of requests per event must be greater than 0\n"); return 1; } break; case 'f': if (atof(optarg) <= 1.0) { fprintf(stderr, "Factor must be greater than 1\n"); return 1; } double_int(optarg, &settings.factor_numerator, &settings.factor_denominator); break; case 'n': settings.chunk_size = atoi(optarg); if (settings.chunk_size == 0) { fprintf(stderr, "Chunk size must be greater than 0\n"); return 1; } break; case 'D': if (! optarg || ! optarg[0]) { fprintf(stderr, "No delimiter specified\n"); return 1; } settings.prefix_delimiter = optarg[0]; settings.detail_enabled = 1; break; case 'L' : if (enable_large_pages() == 0) { settings.preallocate = 1; } else { fprintf(stderr, "Cannot enable large pages on this system\n" "(There is no Linux support as of this version)\n"); return 1; } break; case 'C' : settings.use_cas = 0; break; case 'b' : settings.backlog = atoi(optarg); break; case 'B': protocol_specified = 1; if (strcmp(optarg, "auto") == 0) { settings.binding_protocol = negotiating_prot; } else if (strcmp(optarg, "binary") == 0) { settings.binding_protocol = binary_prot; } else if (strcmp(optarg, "ascii") == 0) { settings.binding_protocol = ascii_prot; } else { fprintf(stderr, "Invalid value for binding protocol: %s\n" " -- should be one of auto, binary, or ascii\n", optarg); exit(EX_USAGE); } break; case 'I': unit = optarg[strlen(optarg)-1]; if (unit == 'k' || unit == 'm' || unit == 'K' || unit == 'M') { optarg[strlen(optarg)-1] = '\0'; size_max = atoi(optarg); if (unit == 'k' || unit == 'K') size_max *= 1024; if (unit == 'm' || unit == 'M') size_max *= 1024 * 1024; settings.item_size_max = size_max; } else { settings.item_size_max = atoi(optarg); } if (settings.item_size_max < 1024) { fprintf(stderr, "Item max size cannot be less than 1024 bytes.\n"); return 1; } if (settings.item_size_max > 1024 * 1024 * 128) { fprintf(stderr, "Cannot set item size limit higher than 128 mb.\n"); return 1; } if (settings.item_size_max > 1024 * 1024) { fprintf(stderr, "WARNING: Setting item max size above 1MB is not" " recommended!\n" " Raising this limit increases the minimum memory requirements\n" " and will decrease your memory efficiency.\n" ); } break; case 'S': /* set Sasl authentication to 1. Default is 0 */ #ifndef ENABLE_SASL fprintf(stderr, "This server is not built with SASL support.\n"); exit(EX_USAGE); #endif settings.sasl = 1; break; case 'o': /* It's sub-opts time! */ subopts = optarg; while (*subopts != '\0') { switch (getsubopt(&subopts, subopts_tokens, &subopts_value)) { case MAXCONNS_FAST: settings.maxconns_fast = 1; break; case HASHPOWER_INIT: if (subopts_value == NULL) { fprintf(stderr, "Missing numeric argument for hashpower\n"); return 1; } settings.hashpower_init = atoi(subopts_value); if (settings.hashpower_init < 12) { fprintf(stderr, "Initial hashtable multiplier of %d is too low\n", settings.hashpower_init); return 1; } else if (settings.hashpower_init > 64) { fprintf(stderr, "Initial hashtable multiplier of %d is too high\n" "Choose a value based on \"STAT hash_power_level\" from a running instance\n", settings.hashpower_init); return 1; } break; case SLAB_REASSIGN: settings.slab_reassign = 1; break; case SLAB_AUTOMOVE: if (subopts_value == NULL) { settings.slab_automove = 1; break; } settings.slab_automove = atoi(subopts_value); if (settings.slab_automove < 0 || settings.slab_automove > 2) { fprintf(stderr, "slab_automove must be between 0 and 2\n"); return 1; } break; default: printf("Illegal suboption \"%s\"\n", subopts_value); return 1; } } break; default: fprintf(stderr, "Illegal argument \"%c\"\n", c); return 1; } } /* * Use one workerthread to serve each UDP port if the user specified * multiple ports */ if (settings.inter != NULL && strchr(settings.inter, ',')) { settings.num_threads_per_udp = 1; } else { settings.num_threads_per_udp = 0x7fffffff; } if (settings.sasl) { if (!protocol_specified) { settings.binding_protocol = binary_prot; } else { if (settings.binding_protocol != binary_prot) { fprintf(stderr, "ERROR: You cannot allow the ASCII protocol while using SASL.\n"); exit(EX_USAGE); } } } if (tcp_specified && !udp_specified) { settings.udpport = settings.port; } else if (udp_specified && !tcp_specified) { settings.port = settings.udpport; } if (maxcore != 0) { struct rlimit rlim_new; /* * First try raising to infinity; if that fails, try bringing * the soft limit to the hard. */ if (getrlimit(RLIMIT_CORE, &rlim) == 0) { rlim_new.rlim_cur = rlim_new.rlim_max = RLIM_INFINITY; if (setrlimit(RLIMIT_CORE, &rlim_new)!= 0) { /* failed. try raising just to the old max */ rlim_new.rlim_cur = rlim_new.rlim_max = rlim.rlim_max; (void)setrlimit(RLIMIT_CORE, &rlim_new); } } /* * getrlimit again to see what we ended up with. Only fail if * the soft limit ends up 0, because then no core files will be * created at all. */ if ((getrlimit(RLIMIT_CORE, &rlim) != 0) || rlim.rlim_cur == 0) { fprintf(stderr, "failed to ensure corefile creation\n"); exit(EX_OSERR); } } /* * If needed, increase rlimits to allow as many connections * as needed. */ if (getrlimit(RLIMIT_NOFILE, &rlim) != 0) { fprintf(stderr, "failed to getrlimit number of files\n"); exit(EX_OSERR); } else { rlim.rlim_cur = settings.maxconns; rlim.rlim_max = settings.maxconns; if (setrlimit(RLIMIT_NOFILE, &rlim) != 0) { fprintf(stderr, "failed to set rlimit for open files. Try starting as root or requesting smaller maxconns value.\n"); exit(EX_OSERR); } } /* lose root privileges if we have them */ if (getuid() != 0 || geteuid() != 0) { fprintf(stderr, "run as root\n"); exit(EX_USAGE); } /* Initialize Sasl if -S was specified */ if (settings.sasl) { // init_sasl(); } /* daemonize if requested */ /* if we want to ensure our ability to dump core, don't chdir to / */ if (do_daemonize) { if (sigignore(SIGHUP) == -1) { perror("Failed to ignore SIGHUP"); } if (daemonize(maxcore, settings.verbose) == -1) { fprintf(stderr, "failed to daemon() in order to daemonize\n"); exit(EXIT_FAILURE); } } main_loop(); return 0; }
int main (int argc, char **argv) { int c; conn *l_conn; struct in_addr addr; int lock_memory = 0; int daemonize = 0; int maxcore = 0; char *username = 0; struct passwd *pw; struct sigaction sa; struct rlimit rlim; char *pid_file = NULL; /* init settings */ settings_init(); /* process arguments */ while ((c = getopt(argc, argv, "p:m:Mc:khirvdl:u:P:")) != -1) { switch (c) { case 'p': settings.port = atoi(optarg); break; case 'm': settings.maxbytes = atoi(optarg)*1024*1024; break; case 'M': settings.evict_to_free = 0; break; case 'c': settings.maxconns = atoi(optarg); break; case 'h': usage(); exit(0); case 'i': usage_license(); exit(0); case 'k': lock_memory = 1; break; case 'v': settings.verbose++; break; case 'l': if (!inet_aton(optarg, &addr)) { fprintf(stderr, "Illegal address: %s\n", optarg); return 1; } else { settings.interface = addr; } break; case 'd': daemonize = 1; break; case 'r': maxcore = 1; break; case 'u': username = optarg; break; case 'P': pid_file = optarg; break; default: fprintf(stderr, "Illegal argument \"%c\"\n", c); return 1; } } if (maxcore) { struct rlimit rlim_new; /* * First try raising to infinity; if that fails, try bringing * the soft limit to the hard. */ if (getrlimit(RLIMIT_CORE, &rlim)==0) { rlim_new.rlim_cur = rlim_new.rlim_max = RLIM_INFINITY; if (setrlimit(RLIMIT_CORE, &rlim_new)!=0) { /* failed. try raising just to the old max */ rlim_new.rlim_cur = rlim_new.rlim_max = rlim.rlim_max; (void) setrlimit(RLIMIT_CORE, &rlim_new); } } /* * getrlimit again to see what we ended up with. Only fail if * the soft limit ends up 0, because then no core files will be * created at all. */ if ((getrlimit(RLIMIT_CORE, &rlim)!=0) || rlim.rlim_cur==0) { fprintf(stderr, "failed to ensure corefile creation\n"); exit(1); } } /* * If needed, increase rlimits to allow as many connections * as needed. */ if (getrlimit(RLIMIT_NOFILE, &rlim) != 0) { fprintf(stderr, "failed to getrlimit number of files\n"); exit(1); } else { int maxfiles = settings.maxconns; if (rlim.rlim_cur < maxfiles) rlim.rlim_cur = maxfiles + 3; if (rlim.rlim_max < rlim.rlim_cur) rlim.rlim_max = rlim.rlim_cur; if (setrlimit(RLIMIT_NOFILE, &rlim) != 0) { fprintf(stderr, "failed to set rlimit for open files. Try running as root or requesting smaller maxconns value.\n"); exit(1); } } /* * initialization order: first create the listening socket * (may need root on low ports), then drop root if needed, * then daemonise if needed, then init libevent (in some cases * descriptors created by libevent wouldn't survive forking). */ /* create the listening socket and bind it */ l_socket = server_socket(settings.port); if (l_socket == -1) { fprintf(stderr, "failed to listen\n"); exit(1); } /* lose root privileges if we have them */ if (getuid()== 0 || geteuid()==0) { if (username==0 || *username=='\0') { fprintf(stderr, "can't run as root without the -u switch\n"); return 1; } if ((pw = getpwnam(username)) == 0) { fprintf(stderr, "can't find the user %s to switch to\n", username); return 1; } if (setgid(pw->pw_gid)<0 || setuid(pw->pw_uid)<0) { fprintf(stderr, "failed to assume identity of user %s\n", username); return 1; } } /* daemonize if requested */ /* if we want to ensure our ability to dump core, don't chdir to / */ if (daemonize) { int res; res = daemon(maxcore, settings.verbose); if (res == -1) { fprintf(stderr, "failed to daemon() in order to daemonize\n"); return 1; } } /* initialize other stuff */ item_init(); event_init(); stats_init(); assoc_init(); conn_init(); slabs_init(settings.maxbytes); /* lock paged memory if needed */ if (lock_memory) { #ifdef HAVE_MLOCKALL mlockall(MCL_CURRENT | MCL_FUTURE); #else fprintf(stderr, "warning: mlockall() not supported on this platform. proceeding without.\n"); #endif } /* * ignore SIGPIPE signals; we can use errno==EPIPE if we * need that information */ sa.sa_handler = SIG_IGN; sa.sa_flags = 0; if (sigemptyset(&sa.sa_mask) == -1 || sigaction(SIGPIPE, &sa, 0) == -1) { perror("failed to ignore SIGPIPE; sigaction"); exit(1); } /* create the initial listening connection */ if (!(l_conn = conn_new(l_socket, conn_listening, EV_READ | EV_PERSIST))) { fprintf(stderr, "failed to create listening connection"); exit(1); } /* initialise deletion array and timer event */ deltotal = 200; delcurr = 0; todelete = malloc(sizeof(item *)*deltotal); delete_handler(0,0,0); /* sets up the event */ /* save the PID in if we're a daemon */ if (daemonize) save_pid(getpid(),pid_file); /* enter the loop */ event_loop(0); /* remove the PID file if we're a daemon */ if (daemonize) remove_pidfile(pid_file); return 0; }