Branch data Line data Source code
1 : : #ifndef _GNU_SOURCE
2 : : #define _GNU_SOURCE
3 : : #endif
4 : :
5 : : #include <unistd.h>
6 : : #include <stdio.h>
7 : : #include <stdlib.h>
8 : : #include <errno.h>
9 : : #include <string.h>
10 : : #include <sys/types.h>
11 : : #include <sys/socket.h>
12 : : #include <sys/un.h>
13 : : #include <sys/wait.h>
14 : : #include <sys/stat.h>
15 : :
16 : : #include "crtools.h"
17 : : #include "cr_options.h"
18 : : #include "util.h"
19 : : #include "log.h"
20 : : #include "pstree.h"
21 : : #include "cr-service.h"
22 : : #include "cr-service-const.h"
23 : : #include "sd-daemon.h"
24 : : #include "page-xfer.h"
25 : : #include "net.h"
26 : :
27 : : unsigned int service_sk_ino = -1;
28 : :
29 : 0 : static int recv_criu_msg(int socket_fd, CriuReq **msg)
30 : : {
31 : : unsigned char buf[CR_MAX_MSG_SIZE];
32 : : int len;
33 : :
34 : 0 : len = read(socket_fd, buf, CR_MAX_MSG_SIZE);
35 [ # # ]: 0 : if (len == -1) {
36 : 0 : pr_perror("Can't read request");
37 : 0 : return -1;
38 : : }
39 : :
40 [ # # ]: 0 : if (len == 0) {
41 : 0 : pr_info("Client exited unexpectedly\n");
42 : 0 : errno = ECONNRESET;
43 : 0 : return -1;
44 : : }
45 : :
46 : 0 : *msg = criu_req__unpack(NULL, len, buf);
47 [ # # ]: 0 : if (!*msg) {
48 : 0 : pr_perror("Failed unpacking request");
49 : 0 : return -1;
50 : : }
51 : :
52 : : return 0;
53 : : }
54 : :
55 : 0 : static int send_criu_msg(int socket_fd, CriuResp *msg)
56 : : {
57 : : unsigned char buf[CR_MAX_MSG_SIZE];
58 : : int len;
59 : :
60 : 0 : len = criu_resp__get_packed_size(msg);
61 : :
62 [ # # ]: 0 : if (criu_resp__pack(msg, buf) != len) {
63 : 0 : pr_perror("Failed packing response");
64 : 0 : return -1;
65 : : }
66 : :
67 [ # # ]: 0 : if (write(socket_fd, buf, len) == -1) {
68 : 0 : pr_perror("Can't send response");
69 : 0 : return -1;
70 : : }
71 : :
72 : : return 0;
73 : : }
74 : :
75 : 0 : static void send_criu_err(int sk, char *msg)
76 : : {
77 : 0 : CriuResp resp = CRIU_RESP__INIT;
78 : :
79 : 0 : pr_perror("RPC error: %s", msg);
80 : :
81 : 0 : resp.type = CRIU_REQ_TYPE__EMPTY;
82 : 0 : resp.success = false;
83 : : /* XXX -- add optional error code to CriuResp */
84 : :
85 : 0 : send_criu_msg(sk, &resp);
86 : 0 : }
87 : :
88 : 0 : int send_criu_dump_resp(int socket_fd, bool success, bool restored)
89 : : {
90 : 0 : CriuResp msg = CRIU_RESP__INIT;
91 : 0 : CriuDumpResp resp = CRIU_DUMP_RESP__INIT;
92 : :
93 : 0 : msg.type = CRIU_REQ_TYPE__DUMP;
94 : 0 : msg.success = success;
95 : 0 : msg.dump = &resp;
96 : :
97 : 0 : resp.has_restored = true;
98 : 0 : resp.restored = restored;
99 : :
100 : 0 : return send_criu_msg(socket_fd, &msg);
101 : : }
102 : :
103 : 0 : static int send_criu_pre_dump_resp(int socket_fd, bool success)
104 : : {
105 : 0 : CriuResp msg = CRIU_RESP__INIT;
106 : :
107 : 0 : msg.type = CRIU_REQ_TYPE__PRE_DUMP;
108 : 0 : msg.success = success;
109 : :
110 : 0 : return send_criu_msg(socket_fd, &msg);
111 : : }
112 : :
113 : 0 : int send_criu_restore_resp(int socket_fd, bool success, int pid)
114 : : {
115 : 0 : CriuResp msg = CRIU_RESP__INIT;
116 : 0 : CriuRestoreResp resp = CRIU_RESTORE_RESP__INIT;
117 : :
118 : 0 : msg.type = CRIU_REQ_TYPE__RESTORE;
119 : 0 : msg.success = success;
120 : 0 : msg.restore = &resp;
121 : :
122 : 0 : resp.pid = pid;
123 : :
124 : 0 : return send_criu_msg(socket_fd, &msg);
125 : : }
126 : :
127 : 0 : int send_criu_rpc_script(char *script, int fd)
128 : : {
129 : : int ret;
130 : 0 : CriuResp msg = CRIU_RESP__INIT;
131 : : CriuReq *req;
132 : 0 : CriuNotify cn = CRIU_NOTIFY__INIT;
133 : :
134 : 0 : msg.type = CRIU_REQ_TYPE__NOTIFY;
135 : 0 : msg.success = true;
136 : 0 : msg.notify = &cn;
137 : 0 : cn.script = script;
138 : :
139 [ # # ]: 0 : if (!strcmp(script, "setup-namespaces")) {
140 : : /*
141 : : * FIXME pid is required only once on
142 : : * restore. Need some more sane way of
143 : : * checking this.
144 : : */
145 : 0 : cn.has_pid = true;
146 : 0 : cn.pid = root_item->pid.real;
147 : : }
148 : :
149 : 0 : ret = send_criu_msg(fd, &msg);
150 [ # # ]: 0 : if (ret < 0)
151 : : return ret;
152 : :
153 : 0 : ret = recv_criu_msg(fd, &req);
154 [ # # ]: 0 : if (ret < 0)
155 : : return ret;
156 : :
157 [ # # ][ # # ]: 0 : if (req->type != CRIU_REQ_TYPE__NOTIFY || !req->notify_success) {
158 : 0 : pr_err("RPC client reported script error\n");
159 : 0 : return -1;
160 : : }
161 : :
162 : 0 : criu_req__free_unpacked(req, NULL);
163 : 0 : return 0;
164 : : }
165 : :
166 : 0 : static int setup_opts_from_req(int sk, CriuOpts *req)
167 : : {
168 : : struct ucred ids;
169 : : struct stat st;
170 : 0 : socklen_t ids_len = sizeof(struct ucred);
171 : : char images_dir_path[PATH_MAX];
172 : : char work_dir_path[PATH_MAX];
173 : : int i;
174 : :
175 [ # # ]: 0 : if (getsockopt(sk, SOL_SOCKET, SO_PEERCRED, &ids, &ids_len)) {
176 : 0 : pr_perror("Can't get socket options");
177 : 0 : return -1;
178 : : }
179 : :
180 : 0 : restrict_uid(ids.uid, ids.gid);
181 : :
182 [ # # ]: 0 : if (fstat(sk, &st)) {
183 : 0 : pr_perror("Can't get socket stat");
184 : 0 : return -1;
185 : : }
186 : :
187 [ # # ]: 0 : BUG_ON(st.st_ino == -1);
188 : 0 : service_sk_ino = st.st_ino;
189 : :
190 : : /* open images_dir */
191 : 0 : sprintf(images_dir_path, "/proc/%d/fd/%d", ids.pid, req->images_dir_fd);
192 : :
193 [ # # ]: 0 : if (req->parent_img)
194 : 0 : opts.img_parent = req->parent_img;
195 : :
196 [ # # ]: 0 : if (open_image_dir(images_dir_path) < 0) {
197 : 0 : pr_perror("Can't open images directory");
198 : 0 : return -1;
199 : : }
200 : :
201 : : /* chdir to work dir */
202 [ # # ]: 0 : if (req->has_work_dir_fd)
203 : 0 : sprintf(work_dir_path, "/proc/%d/fd/%d", ids.pid, req->work_dir_fd);
204 : : else
205 : : strcpy(work_dir_path, images_dir_path);
206 : :
207 [ # # ]: 0 : if (chdir(work_dir_path)) {
208 : 0 : pr_perror("Can't chdir to work_dir");
209 : 0 : return -1;
210 : : }
211 : :
212 : : /* initiate log file in work dir */
213 [ # # ]: 0 : if (req->log_file) {
214 [ # # ]: 0 : if (strchr(req->log_file, '/')) {
215 : 0 : pr_perror("No subdirs are allowed in log_file name");
216 : 0 : return -1;
217 : : }
218 : :
219 : 0 : opts.output = req->log_file;
220 : : } else
221 : 0 : opts.output = DEFAULT_LOG_FILENAME;
222 : :
223 : 0 : log_set_loglevel(req->log_level);
224 [ # # ]: 0 : if (log_init(opts.output) == -1) {
225 : 0 : pr_perror("Can't initiate log");
226 : 0 : return -1;
227 : : }
228 : :
229 : : /* checking flags from client */
230 [ # # ][ # # ]: 0 : if (req->has_leave_running && req->leave_running)
231 : 0 : opts.final_state = TASK_ALIVE;
232 : :
233 [ # # ]: 0 : if (!req->has_pid) {
234 : 0 : req->has_pid = true;
235 : 0 : req->pid = ids.pid;
236 : : }
237 : :
238 [ # # ]: 0 : if (req->has_ext_unix_sk)
239 : 0 : opts.ext_unix_sk = req->ext_unix_sk;
240 : :
241 [ # # ]: 0 : if (req->root)
242 : 0 : opts.root = req->root;
243 : :
244 [ # # ]: 0 : if (req->has_tcp_established)
245 : 0 : opts.tcp_established_ok = req->tcp_established;
246 : :
247 [ # # ]: 0 : if (req->has_evasive_devices)
248 : 0 : opts.evasive_devices = req->evasive_devices;
249 : :
250 [ # # ]: 0 : if (req->has_shell_job)
251 : 0 : opts.shell_job = req->shell_job;
252 : :
253 [ # # ]: 0 : if (req->has_file_locks)
254 : 0 : opts.handle_file_locks = req->file_locks;
255 : :
256 [ # # ]: 0 : if (req->has_track_mem)
257 : 0 : opts.track_mem = req->track_mem;
258 : :
259 [ # # ]: 0 : if (req->has_link_remap)
260 : 0 : opts.link_remap_ok = req->link_remap;
261 : :
262 [ # # ]: 0 : if (req->has_auto_dedup)
263 : 0 : opts.auto_dedup = req->auto_dedup;
264 : :
265 [ # # ]: 0 : if (req->has_force_irmap)
266 : 0 : opts.force_irmap = req->force_irmap;
267 : :
268 [ # # ]: 0 : if (req->n_exec_cmd > 0) {
269 [ # # ]: 0 : opts.exec_cmd = xmalloc((req->n_exec_cmd + 1) * sizeof(char *));
270 : 0 : memcpy(opts.exec_cmd, req->exec_cmd, req->n_exec_cmd * sizeof(char *));
271 : 0 : opts.exec_cmd[req->n_exec_cmd] = NULL;
272 : : }
273 : :
274 [ # # ]: 0 : if (req->ps) {
275 : 0 : opts.use_page_server = true;
276 : 0 : opts.addr = req->ps->address;
277 [ # # ]: 0 : opts.ps_port = htons((short)req->ps->port);
278 : : }
279 : :
280 [ # # ]: 0 : if (req->notify_scripts) {
281 : : struct script *script;
282 : :
283 [ # # ]: 0 : script = xmalloc(sizeof(struct script));
284 [ # # ]: 0 : if (script == NULL)
285 : : return -1;
286 : :
287 : 0 : script->path = SCRIPT_RPC_NOTIFY;
288 : 0 : script->arg = sk;
289 : 0 : list_add(&script->node, &opts.scripts);
290 : : }
291 : :
292 [ # # ]: 0 : for (i = 0; i < req->n_veths; i++) {
293 [ # # ]: 0 : if (veth_pair_add(req->veths[i]->if_in, req->veths[i]->if_out))
294 : : return -1;
295 : : }
296 : :
297 [ # # ]: 0 : if (req->has_cpu_cap)
298 : 0 : opts.cpu_cap = req->cpu_cap;
299 : :
300 : : return 0;
301 : : }
302 : :
303 : 0 : static int dump_using_req(int sk, CriuOpts *req)
304 : : {
305 : : bool success = false;
306 : 0 : bool self_dump = !req->pid;
307 : :
308 [ # # ]: 0 : if (setup_opts_from_req(sk, req))
309 : : goto exit;
310 : :
311 : : /*
312 : : * FIXME -- cr_dump_tasks() may return code from custom
313 : : * scripts, that can be positive. However, right now we
314 : : * don't have ability to push scripts via RPC, so psitive
315 : : * ret values are impossible here.
316 : : */
317 [ # # ]: 0 : if (cr_dump_tasks(req->pid))
318 : : goto exit;
319 : :
320 : : success = true;
321 : : exit:
322 [ # # ][ # # ]: 0 : if (req->leave_running || !self_dump || !success) {
323 [ # # ]: 0 : if (send_criu_dump_resp(sk, success, false) == -1) {
324 : 0 : pr_perror("Can't send response");
325 : : success = false;
326 : : }
327 : : }
328 : :
329 [ # # ]: 0 : return success ? 0 : 1;
330 : : }
331 : :
332 : 0 : static int restore_using_req(int sk, CriuOpts *req)
333 : : {
334 : : bool success = false;
335 : :
336 : : /*
337 : : * We can't restore processes under arbitrary task yet.
338 : : * Thus for now we force the detached restore under the
339 : : * cr service task.
340 : : */
341 : :
342 : 0 : opts.restore_detach = true;
343 : :
344 [ # # ]: 0 : if (setup_opts_from_req(sk, req))
345 : : goto exit;
346 : :
347 [ # # ]: 0 : if (cr_restore_tasks())
348 : : goto exit;
349 : :
350 : : success = true;
351 : : exit:
352 [ # # ][ # # ]: 0 : if (send_criu_restore_resp(sk, success,
353 : 0 : root_item ? root_item->pid.real : -1) == -1) {
354 : 0 : pr_perror("Can't send response");
355 : : success = false;
356 : : }
357 : :
358 [ # # ][ # # ]: 0 : if (success && opts.exec_cmd) {
359 : : int logfd;
360 : :
361 : 0 : logfd = log_get_fd();
362 [ # # ][ # # ]: 0 : if (dup2(logfd, STDOUT_FILENO) == -1 || dup2(logfd, STDERR_FILENO) == -1) {
363 : 0 : pr_perror("Failed to redirect stdout and stderr to the logfile");
364 : 0 : return 1;
365 : : }
366 : :
367 : 0 : close_pid_proc();
368 : 0 : close(sk);
369 : :
370 : 0 : execvp(opts.exec_cmd[0], opts.exec_cmd);
371 : 0 : pr_perror("Failed to exec cmd %s", opts.exec_cmd[0]);
372 : : success = false;
373 : : }
374 : :
375 [ # # ]: 0 : return success ? 0 : 1;
376 : : }
377 : :
378 : 0 : static int check(int sk)
379 : : {
380 : 0 : CriuResp resp = CRIU_RESP__INIT;
381 : :
382 : 0 : resp.type = CRIU_REQ_TYPE__CHECK;
383 : :
384 : : /* Check only minimal kernel support */
385 : 0 : opts.check_ms_kernel = true;
386 : :
387 [ # # ]: 0 : if (!cr_check())
388 : 0 : resp.success = true;
389 : :
390 : 0 : return send_criu_msg(sk, &resp);
391 : : }
392 : :
393 : 0 : static int pre_dump_using_req(int sk, CriuOpts *req)
394 : : {
395 : : int pid, status;
396 : : bool success = false;
397 : :
398 : 0 : pid = fork();
399 [ # # ]: 0 : if (pid < 0) {
400 : 0 : pr_perror("Can't fork");
401 : 0 : goto out;
402 : : }
403 : :
404 [ # # ]: 0 : if (pid == 0) {
405 : : int ret = 1;
406 : :
407 [ # # ]: 0 : if (setup_opts_from_req(sk, req))
408 : : goto cout;
409 : :
410 [ # # ]: 0 : if (cr_pre_dump_tasks(req->pid))
411 : : goto cout;
412 : :
413 : : ret = 0;
414 : : cout:
415 : 0 : exit(ret);
416 : : }
417 : :
418 : 0 : wait(&status);
419 [ # # ]: 0 : if (!WIFEXITED(status))
420 : : goto out;
421 [ # # ]: 0 : if (WEXITSTATUS(status) != 0)
422 : : goto out;
423 : :
424 : : success = true;
425 : : out:
426 [ # # ]: 0 : if (send_criu_pre_dump_resp(sk, success) == -1) {
427 : 0 : pr_perror("Can't send pre-dump resp");
428 : : success = false;
429 : : }
430 : :
431 [ # # ]: 0 : return success ? 0 : -1;
432 : : }
433 : :
434 : 0 : static int pre_dump_loop(int sk, CriuReq *msg)
435 : : {
436 : : int ret;
437 : :
438 : : do {
439 : 0 : ret = pre_dump_using_req(sk, msg->opts);
440 [ # # ]: 0 : if (ret < 0)
441 : : return ret;
442 : :
443 : 0 : criu_req__free_unpacked(msg, NULL);
444 [ # # ]: 0 : if (recv_criu_msg(sk, &msg) == -1) {
445 : 0 : pr_perror("Can't recv request");
446 : 0 : return -1;
447 : : }
448 [ # # ]: 0 : } while (msg->type == CRIU_REQ_TYPE__PRE_DUMP);
449 : :
450 [ # # ]: 0 : if (msg->type != CRIU_REQ_TYPE__DUMP) {
451 : 0 : send_criu_err(sk, "Bad req seq");
452 : 0 : return -1;
453 : : }
454 : :
455 : 0 : return dump_using_req(sk, msg->opts);
456 : : }
457 : :
458 : 0 : static int start_page_server_req(int sk, CriuOpts *req)
459 : : {
460 : : int ret;
461 : : bool success = false;
462 : 0 : CriuResp resp = CRIU_RESP__INIT;
463 : 0 : CriuPageServerInfo ps = CRIU_PAGE_SERVER_INFO__INIT;
464 : :
465 [ # # ]: 0 : if (!req->ps) {
466 : 0 : pr_err("No page server info in message\n");
467 : 0 : goto out;
468 : : }
469 : :
470 [ # # ]: 0 : if (setup_opts_from_req(sk, req))
471 : : goto out;
472 : :
473 : 0 : pr_debug("Starting page server\n");
474 : :
475 : 0 : ret = cr_page_server(true);
476 [ # # ]: 0 : if (ret > 0) {
477 : : success = true;
478 : 0 : ps.has_pid = true;
479 : 0 : ps.pid = ret;
480 : 0 : resp.ps = &ps;
481 : : }
482 : :
483 : 0 : pr_debug("Page server started\n");
484 : : out:
485 : 0 : resp.type = CRIU_REQ_TYPE__PAGE_SERVER;
486 : 0 : resp.success = success;
487 : 0 : return send_criu_msg(sk, &resp);
488 : : }
489 : :
490 : 0 : static int cr_service_work(int sk)
491 : : {
492 : 0 : CriuReq *msg = 0;
493 : :
494 : 0 : init_opts();
495 : :
496 [ # # ]: 0 : if (recv_criu_msg(sk, &msg) == -1) {
497 : 0 : pr_perror("Can't recv request");
498 : 0 : goto err;
499 : : }
500 : :
501 [ # # # # : 0 : switch (msg->type) {
# # ]
502 : : case CRIU_REQ_TYPE__DUMP:
503 : 0 : return dump_using_req(sk, msg->opts);
504 : : case CRIU_REQ_TYPE__RESTORE:
505 : 0 : return restore_using_req(sk, msg->opts);
506 : : case CRIU_REQ_TYPE__CHECK:
507 : 0 : return check(sk);
508 : : case CRIU_REQ_TYPE__PRE_DUMP:
509 : 0 : return pre_dump_loop(sk, msg);
510 : : case CRIU_REQ_TYPE__PAGE_SERVER:
511 : 0 : return start_page_server_req(sk, msg->opts);
512 : :
513 : : default:
514 : 0 : send_criu_err(sk, "Invalid req");
515 : 0 : goto err;
516 : : }
517 : :
518 : : err:
519 : : return -1;
520 : : }
521 : :
522 : 0 : static void reap_worker(int signo)
523 : : {
524 : : int saved_errno;
525 : : int status;
526 : : pid_t pid;
527 : :
528 : 0 : saved_errno = errno;
529 : :
530 : : /*
531 : : * As we block SIGCHLD, lets wait for every child that has
532 : : * already changed state.
533 : : */
534 : : while (1) {
535 : 0 : pid = waitpid(-1, &status, WNOHANG);
536 : :
537 [ # # ]: 0 : if (pid <= 0) {
538 : 0 : errno = saved_errno;
539 : 0 : return;
540 : : }
541 : :
542 [ # # ]: 0 : if (WIFEXITED(status))
543 : 0 : pr_info("Worker(pid %d) exited with %d\n",
544 : : pid, WEXITSTATUS(status));
545 [ # # ]: 0 : else if (WIFSIGNALED(status))
546 : 0 : pr_info("Worker(pid %d) was killed by %d\n",
547 : : pid, WTERMSIG(status));
548 : : }
549 : : }
550 : :
551 : 0 : static int setup_sigchld_handler()
552 : : {
553 : : struct sigaction action;
554 : :
555 : 0 : sigemptyset(&action.sa_mask);
556 : 0 : sigaddset(&action.sa_mask, SIGCHLD);
557 : 0 : action.sa_handler = reap_worker;
558 : 0 : action.sa_flags = SA_RESTART;
559 : :
560 [ # # ]: 0 : if (sigaction(SIGCHLD, &action, NULL)) {
561 : 0 : pr_perror("Can't setup SIGCHLD handler");
562 : 0 : return -1;
563 : : }
564 : :
565 : : return 0;
566 : : }
567 : :
568 : 0 : static int restore_sigchld_handler()
569 : : {
570 : : struct sigaction action;
571 : :
572 : 0 : sigemptyset(&action.sa_mask);
573 : 0 : sigaddset(&action.sa_mask, SIGCHLD);
574 : 0 : action.sa_handler = SIG_DFL;
575 : 0 : action.sa_flags = SA_RESTART;
576 : :
577 [ # # ]: 0 : if (sigaction(SIGCHLD, &action, NULL)) {
578 : 0 : pr_perror("Can't restore SIGCHLD handler");
579 : 0 : return -1;
580 : : }
581 : :
582 : : return 0;
583 : : }
584 : :
585 : 0 : int cr_service(bool daemon_mode)
586 : : {
587 : 0 : int server_fd = -1, n;
588 : : int child_pid;
589 : :
590 : : struct sockaddr_un client_addr;
591 : : socklen_t client_addr_len;
592 : :
593 : 0 : n = sd_listen_fds(0);
594 [ # # ]: 0 : if (n > 1) {
595 : 0 : pr_err("Too many file descriptors (%d) recieved", n);
596 : 0 : goto err;
597 [ # # ]: 0 : } else if (n == 1)
598 : 0 : server_fd = SD_LISTEN_FDS_START + 0;
599 : : else {
600 : : struct sockaddr_un server_addr;
601 : : socklen_t server_addr_len;
602 : :
603 : 0 : server_fd = socket(AF_LOCAL, SOCK_SEQPACKET, 0);
604 [ # # ]: 0 : if (server_fd == -1) {
605 : 0 : pr_perror("Can't initialize service socket");
606 : 0 : goto err;
607 : : }
608 : :
609 : : memset(&server_addr, 0, sizeof(server_addr));
610 : : memset(&client_addr, 0, sizeof(client_addr));
611 : 0 : server_addr.sun_family = AF_LOCAL;
612 : :
613 [ # # ]: 0 : if (opts.addr == NULL)
614 : 0 : opts.addr = CR_DEFAULT_SERVICE_ADDRESS;
615 : :
616 : 0 : strcpy(server_addr.sun_path, opts.addr);
617 : :
618 : 0 : server_addr_len = strlen(server_addr.sun_path)
619 : : + sizeof(server_addr.sun_family);
620 : 0 : client_addr_len = sizeof(client_addr);
621 : :
622 : 0 : unlink(server_addr.sun_path);
623 : :
624 [ # # ]: 0 : if (bind(server_fd, (struct sockaddr *) &server_addr,
625 : : server_addr_len) == -1) {
626 : 0 : pr_perror("Can't bind");
627 : 0 : goto err;
628 : : }
629 : :
630 : 0 : pr_info("The service socket is bound to %s\n", server_addr.sun_path);
631 : :
632 : : /* change service socket permissions, so anyone can connect to it */
633 [ # # ]: 0 : if (chmod(server_addr.sun_path, 0666)) {
634 : 0 : pr_perror("Can't change permissions of the service socket");
635 : 0 : goto err;
636 : : }
637 : :
638 [ # # ]: 0 : if (listen(server_fd, 16) == -1) {
639 : 0 : pr_perror("Can't listen for socket connections");
640 : 0 : goto err;
641 : : }
642 : : }
643 : :
644 [ # # ]: 0 : if (daemon_mode) {
645 [ # # ]: 0 : if (daemon(1, 0) == -1) {
646 : 0 : pr_perror("Can't run service server in the background");
647 : 0 : goto err;
648 : : }
649 : : }
650 : :
651 [ # # ]: 0 : if (opts.pidfile) {
652 [ # # ]: 0 : if (write_pidfile(getpid()) == -1) {
653 : 0 : pr_perror("Can't write pidfile");
654 : 0 : goto err;
655 : : }
656 : : }
657 : :
658 [ # # ]: 0 : if (setup_sigchld_handler())
659 : : goto err;
660 : :
661 : : while (1) {
662 : : int sk;
663 : :
664 : 0 : pr_info("Waiting for connection...\n");
665 : :
666 : 0 : sk = accept(server_fd, &client_addr, &client_addr_len);
667 [ # # ]: 0 : if (sk == -1) {
668 : 0 : pr_perror("Can't accept connection");
669 : 0 : goto err;
670 : : }
671 : :
672 : 0 : pr_info("Connected.\n");
673 : 0 : child_pid = fork();
674 [ # # ]: 0 : if (child_pid == 0) {
675 : : int ret;
676 : :
677 [ # # ]: 0 : if (restore_sigchld_handler())
678 : 0 : exit(1);
679 : :
680 : 0 : close(server_fd);
681 : 0 : ret = cr_service_work(sk);
682 : 0 : close(sk);
683 : 0 : exit(ret != 0);
684 : : }
685 : :
686 [ # # ]: 0 : if (child_pid < 0)
687 : 0 : pr_perror("Can't fork a child");
688 : :
689 : 0 : close(sk);
690 : 0 : }
691 : :
692 : : err:
693 : 0 : close_safe(&server_fd);
694 : :
695 : 0 : return 1;
696 : : }
|