update redame
[beanstalkd.git] / main.c
blob3f64727d5631e5aaa080bbddaaa2f939f0a810e1
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 " -v show version information\n"
71 " -h show this help\n",
72 progname, JOB_DATA_SIZE_LIMIT_DEFAULT, Filesizedef);
73 exit(arg ? 5 : 0);
76 static size_t
77 parse_size_t(char *str)
79 char r, x;
80 size_t size;
82 r = sscanf(str, "%zu%c", &size, &x);
83 if (1 != r) usage("invalid size", str);
84 return size;
87 static char *
88 require_arg(char *opt, char *arg)
90 if (!arg) usage("option requires an argument", opt);
91 return arg;
94 static void
95 warn_systemd_ignored_option(char *opt, char *arg)
97 if (sd_listen_fds(0) > 0) {
98 warnx("inherited listen fd; ignoring option: %s %s", opt, arg);
102 static void
103 opts(int argc, char **argv, Wal *w)
105 int i;
106 int64 ms;
108 for (i = 1; i < argc; ++i) {
109 if (argv[i][0] != '-') usage("unknown option", argv[i]);
110 if (argv[i][1] == 0 || argv[i][2] != 0) usage("unknown option",argv[i]);
111 switch (argv[i][1]) {
112 case 'p':
113 port = require_arg("-p", argv[++i]);
114 warn_systemd_ignored_option("-p", argv[i]);
115 break;
116 case 'l':
117 host_addr = require_arg("-l", argv[++i]);
118 warn_systemd_ignored_option("-l", argv[i]);
119 break;
120 case 'z':
121 job_data_size_limit = parse_size_t(require_arg("-z",
122 argv[++i]));
123 break;
124 case 's':
125 w->filesz = parse_size_t(require_arg("-s", argv[++i]));
126 break;
127 case 'f':
128 ms = (int64)parse_size_t(require_arg("-f", argv[++i]));
129 w->syncrate = ms * 1000000;
130 w->wantsync = 1;
131 break;
132 case 'F':
133 w->wantsync = 0;
134 break;
135 case 'u':
136 user = require_arg("-u", argv[++i]);
137 break;
138 case 'b':
139 w->dir = require_arg("-b", argv[++i]);
140 w->use = 1;
141 break;
142 case 'h':
143 usage(NULL, NULL);
144 case 'v':
145 printf("beanstalkd %s\n", version);
146 exit(0);
147 default:
148 usage("unknown option", argv[i]);
154 main(int argc, char **argv)
156 int r;
157 Srv s = {};
158 s.wal.filesz = Filesizedef;
159 struct job list = {};
161 progname = argv[0];
162 opts(argc, argv, &s.wal);
164 r = make_server_socket(host_addr, port);
165 if (r == -1) twarnx("make_server_socket()"), exit(111);
166 s.sock.fd = r;
168 prot_init();
170 if (user) su(user);
171 set_sig_handlers();
173 if (s.wal.use) {
174 // We want to make sure that only one beanstalkd tries
175 // to use the wal directory at a time. So acquire a lock
176 // now and never release it.
177 if (!waldirlock(&s.wal)) {
178 twarnx("failed to lock wal dir %s", s.wal.dir);
179 exit(10);
182 list.prev = list.next = &list;
183 walinit(&s.wal, &list);
184 prot_replay(&s, &list);
187 srv(&s);
188 return 0;