document the new binlog stats
[beanstalkd.git] / main.c
blobeffc9c6a27cf8ee9463ccfd62ac58ae4189b296f
1 #include <signal.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <errno.h>
5 #include <sys/stat.h>
6 #include <unistd.h>
7 #include <pwd.h>
8 #include <fcntl.h>
9 #include "sd-daemon.h"
10 #include "dat.h"
12 static char *user = NULL;
13 static char *port = "11300";
14 static char *host_addr;
16 static void
17 su(const char *user) {
18 int r;
19 struct passwd *pwent;
21 errno = 0;
22 pwent = getpwnam(user);
23 if (errno) twarn("getpwnam(\"%s\")", user), exit(32);
24 if (!pwent) twarnx("getpwnam(\"%s\"): no such user", user), exit(33);
26 r = setgid(pwent->pw_gid);
27 if (r == -1) twarn("setgid(%d \"%s\")", pwent->pw_gid, user), exit(34);
29 r = setuid(pwent->pw_uid);
30 if (r == -1) twarn("setuid(%d \"%s\")", pwent->pw_uid, user), exit(34);
34 static void
35 set_sig_handlers()
37 int r;
38 struct sigaction sa;
40 sa.sa_handler = SIG_IGN;
41 sa.sa_flags = 0;
42 r = sigemptyset(&sa.sa_mask);
43 if (r == -1) twarn("sigemptyset()"), exit(111);
45 r = sigaction(SIGPIPE, &sa, 0);
46 if (r == -1) twarn("sigaction(SIGPIPE)"), exit(111);
48 sa.sa_handler = enter_drain_mode;
49 r = sigaction(SIGUSR1, &sa, 0);
50 if (r == -1) twarn("sigaction(SIGUSR1)"), exit(111);
53 static void
54 usage(char *msg, char *arg)
56 if (arg) warnx("%s: %s", msg, arg);
57 fprintf(stderr, "Use: %s [OPTIONS]\n"
58 "\n"
59 "Options:\n"
60 " -b DIR wal directory (must be absolute path if used with -d)\n"
61 " -f MS fsync at most once every MS milliseconds"
62 " (use -f 0 for \"always fsync\")\n"
63 " -F never fsync (default)\n"
64 " -l ADDR listen on address (default is 0.0.0.0)\n"
65 " -p PORT listen on port (default is 11300)\n"
66 " -u USER become user and group\n"
67 " -z BYTES set the maximum job size in bytes (default is %d)\n"
68 " -s BYTES set the size of each wal file (default is %d)\n"
69 " (will be rounded up to a multiple of 512 bytes)\n"
70 " -c compact the binlog (default)\n"
71 " -n do not compact the binlog\n"
72 " -v show version information\n"
73 " -h show this help\n",
74 progname, JOB_DATA_SIZE_LIMIT_DEFAULT, Filesizedef);
75 exit(arg ? 5 : 0);
78 static size_t
79 parse_size_t(char *str)
81 char r, x;
82 size_t size;
84 r = sscanf(str, "%zu%c", &size, &x);
85 if (1 != r) usage("invalid size", str);
86 return size;
89 static char *
90 require_arg(char *opt, char *arg)
92 if (!arg) usage("option requires an argument", opt);
93 return arg;
96 static void
97 warn_systemd_ignored_option(char *opt, char *arg)
99 if (sd_listen_fds(0) > 0) {
100 warnx("inherited listen fd; ignoring option: %s %s", opt, arg);
104 static void
105 opts(int argc, char **argv, Wal *w)
107 int i;
108 int64 ms;
110 for (i = 1; i < argc; ++i) {
111 if (argv[i][0] != '-') usage("unknown option", argv[i]);
112 if (argv[i][1] == 0 || argv[i][2] != 0) usage("unknown option",argv[i]);
113 switch (argv[i][1]) {
114 case 'p':
115 port = require_arg("-p", argv[++i]);
116 warn_systemd_ignored_option("-p", argv[i]);
117 break;
118 case 'l':
119 host_addr = require_arg("-l", argv[++i]);
120 warn_systemd_ignored_option("-l", argv[i]);
121 break;
122 case 'z':
123 job_data_size_limit = parse_size_t(require_arg("-z",
124 argv[++i]));
125 break;
126 case 's':
127 w->filesz = parse_size_t(require_arg("-s", argv[++i]));
128 break;
129 case 'c':
130 w->nocomp = 0;
131 break;
132 case 'n':
133 w->nocomp = 1;
134 break;
135 case 'f':
136 ms = (int64)parse_size_t(require_arg("-f", argv[++i]));
137 w->syncrate = ms * 1000000;
138 w->wantsync = 1;
139 break;
140 case 'F':
141 w->wantsync = 0;
142 break;
143 case 'u':
144 user = require_arg("-u", argv[++i]);
145 break;
146 case 'b':
147 w->dir = require_arg("-b", argv[++i]);
148 w->use = 1;
149 break;
150 case 'h':
151 usage(NULL, NULL);
152 case 'v':
153 printf("beanstalkd %s\n", version);
154 exit(0);
155 default:
156 usage("unknown option", argv[i]);
162 main(int argc, char **argv)
164 int r;
165 Srv s = {};
166 s.wal.filesz = Filesizedef;
167 struct job list = {};
169 progname = argv[0];
170 opts(argc, argv, &s.wal);
172 r = make_server_socket(host_addr, port);
173 if (r == -1) twarnx("make_server_socket()"), exit(111);
174 s.sock.fd = r;
176 prot_init();
178 if (user) su(user);
179 set_sig_handlers();
181 if (s.wal.use) {
182 // We want to make sure that only one beanstalkd tries
183 // to use the wal directory at a time. So acquire a lock
184 // now and never release it.
185 if (!waldirlock(&s.wal)) {
186 twarnx("failed to lock wal dir %s", s.wal.dir);
187 exit(10);
190 list.prev = list.next = &list;
191 walinit(&s.wal, &list);
192 prot_replay(&s, &list);
195 srv(&s);
196 return 0;