1 /*-
2 * Copyright (c) 1999-2004 Andrey Simonenko
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27 #include "config.h"
28
29 #ifndef lint
30 static const char rcsid[] ATTR_UNUSED =
31 "@(#)$Id: ipa.c,v 1.4.2.1 2011/11/15 18:12:29 simon Exp $";
32 #endif /* !lint */
33
34 #include <sys/types.h>
35 #include <sys/file.h>
36 #include <sys/stat.h>
37 #include <sys/time.h>
38
39 #include <ctype.h>
40 #include <errno.h>
41 #include <fcntl.h>
42 #include <grp.h>
43 #include <locale.h>
44 #include <pwd.h>
45 #include <signal.h>
46 #include <stdlib.h>
47 #include <stdio.h>
48 #include <string.h>
49 #include <stdarg.h>
50 #include <time.h>
51 #include <unistd.h>
52
53 #ifdef HAVE_PATHS_H
54 # include <paths.h>
55 #endif
56 #ifndef _PATH_DEVNULL
57 # ifdef __GNUC__
58 # warning "defining _PATH_DEVNULL to \"/dev/null\""
59 # endif
60 # define _PATH_DEVNULL "/dev/null"
61 #endif
62
63 #ifdef WITH_PTHREAD
64 # include <pthread.h>
65 #endif
66
67 #include "ipa_mod.h"
68
69 #include "queue.h"
70
71 #include "dlapi.h"
72 #include "confcommon.h"
73 #include "memfunc.h"
74 #include "pathnames.h"
75
76 #include "ipa_ac.h"
77 #include "ipa_db.h"
78 #include "ipa_ctl.h"
79 #include "ipa_cmd.h"
80 #include "ipa_time.h"
81
82 #include "ipa_conf.h"
83 #include "ipa_ctl.h"
84 #include "ipa_log.h"
85 #include "ipa_main.h"
86 #include "ipa_rules.h"
87 #include "ipa_autorules.h"
88
89 #if defined(HAVE_CLOSEFROM) && \
90 (STDIN_FILENO > 2 || STDOUT_FILENO > 2 || STDERR_FILENO > 2)
91 # undef HAVE_CLOSEFROM
92 #endif
93
94 static const char *envprogname;
95
96 static const char *pid_file_name = IPA_PID_FILE; /* -p pid_file */
97 static int pid_file_fd; /* File descriptor of PID-file. */
98
99 static int nofile_max; /* Maximum number of opened files. */
100
101 struct sig_descr {
102 const char *signame; /* Command name. */
103 int signo; /* Signal number. */
104 };
105
106 static const struct sig_descr sig_descr_tbl[] = {
107 { "shutdown", SIGTERM },
108 { "reconfigure", SIGHUP },
109 { "kill", SIGKILL },
110 { "test", 0 },
111 { NULL, 0 }
112 };
113
114 #define PID_FILE_PERM (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) /* 0644 */
115
116 static void exit_err(const char *, ...) ATTR_NORETURN
117 ATTR_FORMAT(printf, 1, 2);
118 static void exit_errx(const char *, ...) ATTR_NORETURN
119 ATTR_FORMAT(printf, 1, 2);
120
121 /*
122 * Close and unlink PID-file.
123 */
124 static void
unlink_pid_file(void)125 unlink_pid_file(void)
126 {
127 if (close(pid_file_fd) < 0)
128 logmsg(IPA_LOG_ERR, "unlink_pid_file: close(%s)",
129 pid_file_name);
130 if (unlink(pid_file_name) < 0)
131 logmsg(IPA_LOG_ERR, "unlink_pid_file: unlink(%s)",
132 pid_file_name);
133 }
134
135 /*
136 * Output the program name, a message, an error message and exit.
137 */
138 static void
exit_err(const char * format,...)139 exit_err(const char *format, ...)
140 {
141 va_list ap;
142 int errno_save;
143
144 errno_save = errno;
145 fflush(stdout);
146 fprintf(stderr, "%s: ", envprogname);
147 va_start(ap, format);
148 vfprintf(stderr, format, ap);
149 va_end(ap);
150 if (errno_save != 0)
151 fprintf(stderr, ": %s", strerror(errno_save));
152 fprintf(stderr, "\n");
153 exit(EXIT_FAILURE);
154 }
155
156 /*
157 * Output the program name, a message and exit.
158 */
159 static void
exit_errx(const char * format,...)160 exit_errx(const char *format, ...)
161 {
162 va_list ap;
163
164 fflush(stdout);
165 fprintf(stderr, "%s: ", envprogname);
166 va_start(ap, format);
167 vfprintf(stderr, format, ap);
168 va_end(ap);
169 fprintf(stderr, "\n");
170 exit(EXIT_FAILURE);
171 }
172
173 /*
174 * Output version number and settings (-v and -h switches).
175 */
176 static void
show_version(void)177 show_version(void)
178 {
179 printf(IPA_NAME ", version " PACKAGE_VERSION "\nRuntime settings: "
180 #ifdef SYM_PREFIX
181 "symbol prefix \"" SYM_PREFIX "\", "
182 #else
183 "symbol prefix is not used, "
184 #endif
185 #ifdef WITH_PTHREAD
186 "thread-safe mode, "
187 #else
188 "single-threaded mode, "
189 #endif
190 #ifdef USE_LIBLTDL
191 "using libtool's ltdl library, "
192 #else
193 "using dlopen interface, "
194 #endif
195 #ifdef WITH_MEMFUNC_DEBUG
196 "memfunc debugging is enabled, "
197 #else
198 "memfunc debugging is disabled, "
199 #endif
200 "using shell %s, using null device %s.\nSupports:"
201 #ifdef WITH_AUTORULES
202 " autorules"
203 #endif
204 #ifdef WITH_RULES
205 # ifdef WITH_AUTORULES
206 ","
207 # endif
208 " rules"
209 #endif
210 #ifdef WITH_LIMITS
211 ", limits"
212 #endif
213 #ifdef WITH_SUBLIMITS
214 ", sublimits"
215 #endif
216 #ifdef WITH_THRESHOLDS
217 ", thresholds"
218 #endif
219 #ifdef CTL_CHECK_CREDS
220 "; checking ipactl's messages credentials is enabled"
221 #else
222 "; checking ipactl's messages credentials is disabled"
223 #endif
224 ".\n", shell_path_default, _PATH_DEVNULL);
225 }
226
227 /*
228 * Output the help message (-h switch).
229 */
230 static void
usage(void)231 usage(void)
232 {
233 show_version();
234 printf("\
235 Usage: %s [options]\n\
236 Utility for accounting\n\
237 Options are:\n\
238 -c dir\t\tSet the directory " IPA_NAME " should chroot(2) into\n\
239 \t\t\timmediately, working directory is not changed\n\
240 -d\t\t\tDo not run in the background (debug mode)\n\
241 -f conf_file\t\tUse given config-file instead of using default\n\
242 \t\t\tconfiguration file %s\n", envprogname, IPA_CONF_FILE);
243 printf("\
244 -i log_ident\t\tUse given log-ident (the default log-ident is \
245 \"" IPA_LOG_IDENT "\")\n\
246 -k signal\t\tSend signal to the running copy of ipa, signal\n\
247 \t\t\tcan be: reconfigure, shutdown, test or kill\n\
248 -o log_file\t\tUse given log-file instead of using syslog\n\
249 -p pid_file\t\tUse given PID-file instead of using default\n\
250 \t\t\tPID-file %s\n\
251 -t\t\t\tCheck the configuration file (two switches mimic\n\
252 \t\t\treal configuration regime) and exit\n", IPA_PID_FILE);
253 printf("\
254 -u user\t\tChange UID of the running copy of " IPA_NAME " to user\n\
255 -g group\t\tChange GID of the running copy of " IPA_NAME " to group\n\
256 -x"
257 #ifdef WITH_RULES
258 " [-r rule"
259 # ifdef WITH_LIMITS
260 " [-l limit"
261 # ifdef WITH_SUBLIMITS
262 " [-s sublimit]"
263 # endif
264 "]"
265 # endif
266 # ifdef WITH_THRESHOLDS
267 " [-t threshold]"
268 # endif
269 "]\n section"
270 # ifdef WITH_ANY_LIMITS
271 " [subsection]\n\t"
272 # endif
273 #else
274 " section"
275 #endif /* WITH_RULES */
276 "\t\tRun commands from the given section and exit\n\
277 -h\t\t\tOutput this help message and exit\n\
278 -v\t\t\tShow version number and exit\n");
279 }
280
281 /*
282 * Ignore SIGTTOU, SIGTTIN, SIGTSTP and SIGPIPE and install sigmask
283 * to block signals which can be received. By default SIGCHLD is ignored.
284 */
285 static int
sig_init_1(void)286 sig_init_1(void)
287 {
288 struct sigaction sigact;
289
290 sigact.sa_handler = SIG_IGN;
291 sigemptyset(&sigact.sa_mask);
292 sigact.sa_flags = 0;
293
294 if (sigaction(SIGTTOU, &sigact, (struct sigaction *)NULL) < 0) {
295 logmsg(IPA_LOG_ERR, "sig_init_1: sigaction(SIGTTOU)");
296 return (-1);
297 }
298 if (sigaction(SIGTTIN, &sigact, (struct sigaction *)NULL) < 0) {
299 logmsg(IPA_LOG_ERR, "sig_init_1: sigaction(SIGTTIN)");
300 return (-1);
301 }
302 if (sigaction(SIGTSTP, &sigact, (struct sigaction *)NULL) < 0) {
303 logmsg(IPA_LOG_ERR, "sig_init_1: sigaction(SIGTSTP)");
304 return (-1);
305 }
306
307 /*
308 * Need this for control socket and for asynchronous running
309 * commands (in case when ipa exits before asynchronous
310 * running commands).
311 */
312 if (sigaction(SIGPIPE, &sigact, (struct sigaction *)NULL) < 0) {
313 logmsg(IPA_LOG_ERR, "sig_init_1: sigaction(SIGPIPE)");
314 return (-1);
315 }
316
317 /* Set sigmask. */
318 sigemptyset(&sigmask);
319 if (debug)
320 sigaddset(&sigmask, SIGINT);
321 sigaddset(&sigmask, SIGHUP);
322 sigaddset(&sigmask, SIGTERM);
323
324 /*
325 * Signals SIGTERM (and SIGINT) and SIGHUP
326 * before next function are not handled properly.
327 */
328 if (Sigprocmask(SIG_SETMASK, &sigmask, (sigset_t *)NULL) < 0) {
329 logmsg(IPA_LOG_ERR, "sig_init_1: "
330 SIGPROCMASK_NAME "(SIG_SETMASK)");
331 return (-1);
332 }
333
334 return (0);
335 }
336
337 /*
338 * Add SIGCHLD to sigmask, initialize zeromask and set signal handlers.
339 */
340 static int
sig_init_2(void)341 sig_init_2(void)
342 {
343 struct sigaction sigact;
344
345 /* Add SIGCHLD to sigmask. */
346 sigaddset(&sigmask, SIGCHLD);
347 if (Sigprocmask(SIG_SETMASK, &sigmask, (sigset_t *)NULL) < 0) {
348 logmsg(IPA_LOG_ERR, "sig_init_2: "
349 SIGPROCMASK_NAME "(SIG_SETMASK)");
350 return (-1);
351 }
352
353 /* Empty zeromask. */
354 sigemptyset(&zeromask);
355
356 /* Install signal handlers. */
357 sigact.sa_flags = 0;
358 sigact.sa_mask = sigmask;
359
360 /* Set SIGTERM (and SIGINT) handlers. */
361 sigact.sa_handler = sig_term;
362 if (debug)
363 if (sigaction(SIGINT, &sigact, (struct sigaction *)NULL) < 0) {
364 logmsg(IPA_LOG_ERR, "sig_init_2: sigaction(SIGINT)");
365 return (-1);
366 }
367 if (sigaction(SIGTERM, &sigact, (struct sigaction *)NULL) < 0) {
368 logmsg(IPA_LOG_ERR, "sig_init_2: sigaction(SIGTERM)");
369 return (-1);
370 }
371
372 /* Set SIGHUP handler. */
373 sigact.sa_handler = sig_hup;
374 if (sigaction(SIGHUP, &sigact, (struct sigaction *)NULL) < 0) {
375 logmsg(IPA_LOG_ERR, "sig_init_2: sigaction(SIGHUP)");
376 return (-1);
377 }
378
379 /* Set SIGCHLD handler. */
380 sigact.sa_handler = sig_chld;
381 sigact.sa_flags = SA_NOCLDSTOP;
382 if (sigaction(SIGCHLD, &sigact, (struct sigaction *)NULL) < 0) {
383 logmsg(IPA_LOG_ERR, "sig_init_2: sigaction(SIGCHLD)");
384 return (-1);
385 }
386
387 return (0);
388 }
389
390 /*
391 * Send a signal signo to the running copy of ipa(8).
392 * Check if the file pid_file_name is locked and if it is locked,
393 * then send a signal to the PID returned in l_pid field of
394 * struct flock{}.
395 */
396 static void
sendsig(int signo)397 sendsig(int signo)
398 {
399 struct flock lock;
400 int fd;
401
402 fd = open(pid_file_name, O_RDONLY);
403 if (fd < 0)
404 exit_err("sendsig: open(%s, O_RDONLY)", pid_file_name);
405
406 lock.l_start = 0; /* Zero offset from... */
407 lock.l_len = 0; /* Entire file. */
408 lock.l_type = F_WRLCK; /* Should be valid value. */
409 lock.l_whence = SEEK_SET; /* ... the start of the file. */
410
411 if (fcntl(fd, F_GETLK, &lock) < 0) {
412 #ifdef __CYGWIN__
413 if (errno == ENOSYS)
414 exit_errx("on Cygwin the -k option cannot be "
415 "implemented in a safe way");
416 #endif
417 exit_err("sendsig: fcntl(%s, F_GETLK)", pid_file_name);
418 }
419
420 if (signo != 0) {
421 switch (lock.l_type) {
422 case F_UNLCK:
423 exit_errx("sendsig: file %s is not locked, do not "
424 "send any signal", pid_file_name);
425 /* NOTREACHED */
426 case F_RDLCK:
427 exit_errx("sendsig: file %s is lock, but lock is "
428 "shared, do not send any signal", pid_file_name);
429 }
430 printf("Sending signal %d to PID %ld...", signo,
431 (long)lock.l_pid);
432 if (kill(lock.l_pid, signo) < 0) {
433 printf("\n");
434 exit_err("sendsig: kill(PID %ld, %d)",
435 (long)lock.l_pid, signo);
436 }
437 printf(" done\n");
438 } else {
439 if (lock.l_type == F_UNLCK)
440 exit_err("file %s exists, but is not locked",
441 pid_file_name);
442 printf("File %s is locked (%s) by PID %ld\n",
443 pid_file_name, lock.l_type == F_WRLCK ?
444 "exclusive" : "shared", (long)lock.l_pid);
445 }
446 }
447
448 /*
449 * Run in the background.
450 */
451 static int
bg_init(void)452 bg_init(void)
453 {
454 pid_t pid;
455
456 pid = fork();
457 if (pid == (pid_t)-1) {
458 logmsg(IPA_LOG_ERR, "bg_init: fork");
459 return (-1);
460 }
461
462 if (pid != 0) {
463 /* Parent exits. */
464 exit(EXIT_SUCCESS);
465 }
466
467 /* Child continues. */
468 if (setsid() == (pid_t)-1)
469 logmsg(IPA_LOG_ERR, "bg_init: setsid");
470 return (0);
471 }
472
473 /*
474 * Create pipe, if any of pipe's ends is stdin, stdout or stderr,
475 * then create another pipe and so on. Then mark the read-end of
476 * a pipe as non-blocking, dup2() the write-end of a pipe to fd_write
477 * and mark fd_write as non-blocking, also mark the read-end of
478 * a pipe as non-blocking and return its value in *fd_read. Read
479 * also comment for fd_init().
480 */
481 static int
pipe_stream(int fd_write,int * fd_read)482 pipe_stream(int fd_write, int *fd_read)
483 {
484 unsigned int i, j;
485 int fd0, fd1, fd[6];
486
487 /*
488 * Pipe's ends should not be equal to file descriptor of stdin,
489 * stdout or stderr. SUSv3 claims that pipe(2) returns lowest
490 * available descriptors, so three (each with two descriptors)
491 * attempts are enough to get desired descriptor.
492 */
493 for (i = j = 0;; j += 2, ++i) {
494 if (pipe(fd + j) < 0) {
495 logmsg(IPA_LOG_ERR, "pipe_stream: pipe");
496 return (-1);
497 }
498 fd0 = fd[j];
499 fd1 = fd[j + 1];
500 if (fd0 != STDIN_FILENO && fd0 != STDOUT_FILENO &&
501 fd0 != STDERR_FILENO && fd1 != STDIN_FILENO &&
502 fd1 != STDOUT_FILENO && fd1 != STDERR_FILENO)
503 break;
504 if (i == 2) {
505 logmsgx(IPA_LOG_ERR, "pipe_stream: something is wrong "
506 "in algorithm");
507 return (-1);
508 }
509 }
510
511 /* Close "incorrectly" opened file descriptors. */
512 while (j > 0) {
513 --j;
514 if (close(fd[j]) < 0) {
515 logmsg(IPA_LOG_ERR, "pipe_stream: close(%d)", fd[j]);
516 return (-1);
517 }
518 }
519
520 if (dup2(fd1, fd_write) < 0) {
521 logmsg(IPA_LOG_ERR, "pipe_stream: dup2(%d, %d)", fd1, fd_write);
522 return (-1);
523 }
524 if (close(fd1) < 0) {
525 logmsg(IPA_LOG_ERR, "pipe_stream: close(%d)", fd1);
526 return (-1);
527 }
528 if (fd_set_nonblock(fd0) < 0 || fd_set_nonblock(fd_write) < 0) {
529 logbt("pipe_stream");
530 return (-1);
531 }
532
533 *fd_read = fd0;
534 return (0);
535 }
536
537 /*
538 * Close not used file descriptors and create pipes for standard
539 * streams stdout and stderr (if needed). If this function returns -1,
540 * then function which called fd_init() should not call log_stdxxx()
541 * functions since syslog() or log file could use one of STDxxx_FILENO
542 * descriptors. Also any log message should not be sent before this
543 * function invocation.
544 */
545 static int
fd_init(void)546 fd_init(void)
547 {
548 long val;
549 int fd;
550
551 errno = 0;
552 val = sysconf(_SC_OPEN_MAX);
553 if (val < 0) {
554 if (errno != 0) {
555 logmsg(IPA_LOG_ERR, "fd_init: sysconf(_SC_OPEN_MAX)");
556 return (-1);
557 }
558 #ifndef HAVE_CLOSEFROM
559 logmsgx(IPA_LOG_ERR, "fd_init: infinite limit for "
560 "_SC_OPEN_MAX is not supported");
561 return (-1);
562 #endif
563 }
564 nofile_max = (int)val;
565
566 #ifdef HAVE_CLOSEFROM
567 if (!debug) {
568 (void)close(STDIN_FILENO);
569 (void)close(STDERR_FILENO);
570 }
571 (void)close(STDOUT_FILENO);
572 for (fd = 3; fd < pid_file_fd; ++fd)
573 (void)close(fd);
574 (void)closefrom(fd + 1);
575 #else
576 # if LONG_MAX > INT_MAX
577 if (val > INT_MAX) {
578 logmsgx(IPA_LOG_ERR, "fd_init: too big value %ld for 'int' "
579 "type from sysconf(_SC_OPEN_MAX)", val);
580 return (-1);
581 }
582 # endif
583 for (fd = 0; fd < (int)val; ++fd)
584 if (fd != pid_file_fd &&
585 !(debug && (fd == STDIN_FILENO || fd == STDERR_FILENO)))
586 (void)close(fd);
587 #endif /* HAVE_CLOSEFROM */
588
589 if (!debug) {
590 fd = open(_PATH_DEVNULL, O_RDWR);
591 if (fd < 0) {
592 logmsg(IPA_LOG_ERR, "fd_init: open(%s, O_RDWR)",
593 _PATH_DEVNULL);
594 return (-1);
595 }
596 if (fd != STDIN_FILENO) {
597 /* stdin -> /dev/null */
598 if (dup2(fd, STDIN_FILENO) < 0) {
599 logmsg(IPA_LOG_ERR, "fd_init: dup2(%d, %d)",
600 fd, STDIN_FILENO);
601 return (-1);
602 }
603 if (close(fd) < 0) {
604 logmsg(IPA_LOG_ERR, "fd_init: close(%d)", fd);
605 return (-1);
606 }
607 }
608 if (pipe_stream(STDERR_FILENO, &stderr_read) < 0) {
609 logmsgx(IPA_LOG_ERR, "fd_init: pipe_stream for "
610 "STDERR_FILENO failed");
611 return (-1);
612 }
613 }
614
615 if (pipe_stream(STDOUT_FILENO, &stdout_read) < 0) {
616 logmsgx(IPA_LOG_ERR, "fd_init: pipe_stream for "
617 "STDOUT_FILENO failed");
618 return (-1);
619 }
620
621 return (0);
622 }
623
624 /*
625 * Create/open PID-file and check if it is already locked, since it is
626 * better to create PID-file before writing something to the log, we need
627 * to choose file descriptor for PID-file not equal to stdxxx.
628 */
629 static void
create_pid_file(void)630 create_pid_file(void)
631 {
632 struct flock lock;
633 int fd[4];
634 unsigned int i;
635
636 /*
637 * pid_file_fd should not be equal to file descriptor of stdin,
638 * stdout or stderr. SUSv3 claims that open(2) returns lowest
639 * available descriptor, so four attempts are enough to get
640 * desired file descriptor.
641 */
642 for (i = 0;; ++i) {
643 fd[i] = open(pid_file_name, O_RDWR|O_CREAT, PID_FILE_PERM);
644 if (fd[i] < 0)
645 exit_err("create_pid_file: cannot create or open "
646 "PID-file: open(%s, O_RDWR|O_CREAT, 0%03o)",
647 pid_file_name, PID_FILE_PERM);
648 if (fd[i] != STDIN_FILENO && fd[i] != STDOUT_FILENO &&
649 fd[i] != STDERR_FILENO) {
650 pid_file_fd = fd[i];
651 break;
652 }
653 if (i == 3)
654 exit_err("create_pid_file: something is wrong "
655 "in algorithm");
656 }
657
658 /* Close "incorrectly" opened file descriptors. */
659 while (i > 0) {
660 --i;
661 if (close(fd[i]) < 0)
662 exit_err("create_pid_file: close(%d)", fd[i]);
663 }
664
665 lock.l_start = 0; /* Zero offset from ... */
666 lock.l_len = 0; /* Entire file. */
667 lock.l_type = F_WRLCK; /* Should be a valid value. */
668 lock.l_whence = SEEK_SET; /* ... the start of the file. */
669
670 if (fcntl(pid_file_fd, F_GETLK, &lock) < 0) {
671 #ifdef __CYGWIN__
672 if (errno == ENOSYS)
673 return;
674 #endif
675 exit_err("create_pid_file: fcntl(%s, F_GETLK)",
676 pid_file_name);
677 }
678
679 switch (lock.l_type) {
680 case F_UNLCK:
681 break;
682 case F_WRLCK:
683 case F_RDLCK:
684 exit_errx("create_pid_file: file %s is already locked (%s) by "
685 "PID %ld", pid_file_name, lock.l_type == F_WRLCK ?
686 "exclusive" : "shared", (long)lock.l_pid);
687 /* NOTREACHED */
688 default:
689 exit_errx("create_pid_file: unknown lock type %d for file %s",
690 lock.l_type, pid_file_name);
691 }
692 }
693
694 /*
695 * Lock the file pid_file_name to prevent multiple copies of itself
696 * from running and store PID in this file.
697 */
698 static int
lock_pid_file(void)699 lock_pid_file(void)
700 {
701 struct flock lock;
702 ssize_t n;
703 int len;
704 char num_str[22];
705
706 lock.l_start = 0; /* Zero offset from... */
707 lock.l_len = 0; /* Entire file. */
708 lock.l_type = F_WRLCK; /* Write lock. */
709 lock.l_whence = SEEK_SET; /* ... the start of the file. */
710
711 if (fcntl(pid_file_fd, F_SETLK, &lock) < 0) {
712 switch (errno) {
713 case EACCES:
714 case EAGAIN:
715 logmsg(IPA_LOG_ERR, "lock_pid_file: cannot acquire "
716 "exclusive lock on file %s", pid_file_name);
717 break;
718 default:
719 logmsg(IPA_LOG_ERR, "lock_pid_file: fcntl(%s, F_SETLK)",
720 pid_file_name);
721 }
722 return (-1);
723 }
724
725 if (ftruncate(pid_file_fd, (off_t)0) < 0) {
726 logmsg(IPA_LOG_ERR, "lock_pid_file: ftruncate(%s, 0)",
727 pid_file_name);
728 goto failed;
729 }
730
731 len = snprintf(num_str, sizeof(num_str), "%ld\n", (long)getpid());
732 if (len < 0) {
733 logmsg(IPA_LOG_ERR, "lock_pid_file: snprintf");
734 goto failed;
735 }
736 if (len >= sizeof(num_str)) {
737 logmsgx(IPA_LOG_ERR, "lock_pid_file: not enough space in "
738 "snprintf");
739 goto failed;
740 }
741
742 n = write(pid_file_fd, num_str, len);
743 if (n < 0) {
744 logmsg(IPA_LOG_ERR, "lock_pid_file: write(%s)", pid_file_name);
745 goto failed;
746 }
747 if (n != len) {
748 logmsgx(IPA_LOG_ERR, "lock_pid_file: write(%s): short write, "
749 "%ld of %lu bytes", pid_file_name, (long)n,
750 (unsigned long)len);
751 goto failed;
752 }
753
754 return (0);
755
756 failed:
757 unlink_pid_file();
758 return (-1);
759 }
760
761 #ifdef WITH_RULES
762
763 # define X_OPTSTRING_RULE "r:"
764
765 # ifdef WITH_LIMITS
766 # define X_OPTSTRING_LIMIT "l:"
767 # else
768 # define X_OPTSTRING_LIMIT ""
769 # endif
770
771 # ifdef WITH_SUBLIMITS
772 # define X_OPTSTRING_SUBLIMIT "s:"
773 # else
774 # define X_OPTSTRING_SUBLIMIT ""
775 # endif
776
777 # ifdef WITH_THRESHOLDS
778 # define X_OPTSTRING_THRESHOLD "t:"
779 # else
780 # define X_OPTSTRING_THRESHOLD ""
781 # endif
782
783 # define X_OPTSTRING ":" \
784 X_OPTSTRING_RULE X_OPTSTRING_LIMIT X_OPTSTRING_SUBLIMIT \
785 X_OPTSTRING_THRESHOLD
786
787 #else /* !WITH_RULES */
788
789 # define X_OPTSTRING ""
790
791 #endif /* WITH_RULES */
792
793 /*
794 * Implement "-x ..." option.
795 */
796 static int
run_opt_cmds(int argc,char * argv[])797 run_opt_cmds(int argc, char *argv[])
798 {
799 enum {
800 SECT_STARTUP = 0,
801 SECT_SHUTDOWN, /* 1 */
802 #if defined(WITH_RULES) && defined(WITH_LIMITS)
803 SECT_REACH, /* 2 */
804 SECT_IF_REACHED, /* 3 */
805 SECT_IF_NOT_REACHED, /* 4 */
806 #endif
807 SECT_NOTSET
808 };
809 const char *section;
810 const struct cmds *cmds;
811 #ifdef WITH_RULES
812 const char *rule_name = NULL;
813 const struct rule *rule;
814 const struct cmds_rule *cmds_rule;
815 # ifdef WITH_LIMITS
816 const char *subsection = NULL;
817 const char *limit_name = NULL;
818 const struct limit *limit;
819 const struct cmds_limit *cmds_limit;
820 unsigned int subsection_code;
821 # endif
822 # ifdef WITH_SUBLIMITS
823 const char *sublimit_name = NULL;
824 const struct sublimit *sublimit;
825 # endif
826 # ifdef WITH_THRESHOLDS
827 const char *threshold_name = NULL;
828 const struct threshold *threshold;
829 # endif
830 #endif /* WITH_RULES */
831 unsigned int section_code;
832 int opt;
833
834 xvlogmsgx = vlogmsgx_stderr;
835
836 while ((opt = getopt(argc, argv, X_OPTSTRING)) != -1)
837 switch (opt) {
838 #ifdef WITH_RULES
839 case ':':
840 exit_errx("-x: option requires an argument -- %c",
841 optopt);
842 /* NOTREACHED */
843 # ifdef WITH_LIMITS
844 case 'l':
845 if (limit_name != NULL)
846 goto failed_duped;
847 limit_name = optarg;
848 if (validate_name(limit_name) < 0)
849 exit_errx("-x: illegal %s name \"%s\"",
850 "limit", limit_name);
851 break;
852 # endif
853 case 'r':
854 if (rule_name != NULL)
855 goto failed_duped;
856 rule_name = optarg;
857 if (validate_name(rule_name) < 0)
858 exit_errx("-x: illegal %s name \"%s\"",
859 "rule", rule_name);
860 break;
861 # ifdef WITH_SUBLIMITS
862 case 's':
863 if (sublimit_name != NULL)
864 goto failed_duped;
865 sublimit_name = optarg;
866 if (validate_name(sublimit_name) < 0)
867 exit_errx("-x: illegal %s name \"%s\"",
868 "sublimit", sublimit_name);
869 break;
870 # endif
871 # ifdef WITH_THRESHOLDS
872 case 't':
873 if (threshold_name != NULL)
874 goto failed_duped;
875 threshold_name = optarg;
876 if (validate_name(threshold_name) < 0)
877 exit_errx("-x: illegal %s name \"%s\"",
878 "threshold", threshold_name);
879 break;
880 # endif
881 #endif /* WITH_RULES */
882 case '?':
883 exit_errx("-x: illegal option -- %c", optopt);
884 /* NOTREACHED */
885 default:
886 exit_errx("-x: unexpected option -- %c", optopt);
887 }
888
889 if (optind == argc)
890 exit_errx("-x: section name is absent");
891
892 section = argv[optind++];
893
894 #ifdef WITH_RULES
895 # if defined(WITH_LIMITS) && defined(WITH_THRESHOLDS)
896 if (limit_name != NULL && threshold_name != NULL)
897 exit_errx("-x: -l and -t options cannot be used together");
898 # endif
899 # if defined(WITH_SUBLIMITS) && defined(WITH_THRESHOLDS)
900 if (sublimit_name != NULL && threshold_name != NULL)
901 exit_errx("-x: -s and -t options cannot be used together");
902 # endif
903 if (rule_name != NULL) {
904 rule = rule_by_name(rule_name);
905 if (rule == NULL)
906 exit_errx("-x: cannot find rule %s in "
907 "the configuration file", rule_name);
908 }
909 # ifdef WITH_LIMITS
910 if (limit_name != NULL) {
911 if (rule_name == NULL)
912 exit_errx("-x: the -l option should be used "
913 "with the -r option");
914 limit = limit_by_name(rule, limit_name);
915 if (limit == NULL)
916 exit_errx("-x: cannot find limit %s for rule %s in "
917 "the configuration file", limit_name, rule_name);
918 }
919 # endif /* WITH_LIMITS */
920 # ifdef WITH_SUBLIMITS
921 if (sublimit_name != NULL) {
922 if (limit_name == NULL)
923 exit_errx("-x: the -s option should be used "
924 "with the -l option");
925 sublimit = sublimit_by_name(limit, sublimit_name);
926 if (sublimit == NULL)
927 exit_errx("-x: cannot find sublimit %s for "
928 "limit %s in rule %s in the configuration file",
929 sublimit_name, limit_name, rule_name);
930 }
931 # endif /* WITH_SUBLIMITS */
932 # ifdef WITH_THRESHOLDS
933 if (threshold_name != NULL) {
934 if (rule_name == NULL)
935 exit_errx("-x: the -t option should be used "
936 "with the -r option");
937 threshold = threshold_by_name(rule, threshold_name);
938 if (threshold == NULL)
939 exit_errx("-x: cannot find threshold %s for "
940 "rule %s in the configuration file",
941 threshold_name, rule_name);
942 }
943 # endif /* WITH_THRESHOLDS */
944 #endif /* WITH_RULES */
945
946 if (strcmp(section, "startup") == 0)
947 section_code = SECT_STARTUP;
948 else if (strcmp(section, "shutdown") == 0)
949 section_code = SECT_SHUTDOWN;
950 else
951 section_code = SECT_NOTSET;
952
953 #ifdef WITH_RULES
954 # ifdef WITH_LIMITS
955 subsection_code = SECT_NOTSET;
956 # endif
957 if (optind != argc) {
958 # ifdef WITH_LIMITS
959 if (optind + 1 != argc)
960 goto failed_many;
961 subsection = argv[optind];
962 if (limit_name != NULL) {
963 if (strcmp(subsection, "if_reached") == 0)
964 subsection_code = SECT_IF_REACHED;
965 else if (strcmp(subsection, "if_not_reached") == 0)
966 subsection_code = SECT_IF_NOT_REACHED;
967 else
968 goto failed_subs;
969 }
970 # ifdef WITH_THRESHOLDS
971 else if (threshold_name != NULL)
972 goto failed_many;
973 # endif
974 # else
975 goto failed_many;
976 # endif /* WITH_LIMITS */
977 }
978 # ifdef WITH_LIMITS
979 if (section_code == SECT_NOTSET)
980 if (strcmp(section, "reach") == 0)
981 section_code = SECT_REACH;
982 # endif
983 # ifdef WITH_SUBLIMITS
984 if (sublimit_name != NULL) {
985 switch (section_code) {
986 case SECT_STARTUP:
987 cmds_limit = &sublimit->rc[RC_STARTUP];
988 break;
989 case SECT_SHUTDOWN:
990 cmds_limit = &sublimit->rc[RC_SHUTDOWN];
991 break;
992 case SECT_REACH:
993 if (subsection != NULL)
994 goto failed_many;
995 return (run_cmds_cons(&sublimit->reach,
996 "rule %s { limit %s { sublimit %s { reach {}}}}",
997 rule_name, limit_name, sublimit_name));
998 default: /* SECT_NOTSET */
999 goto failed_sect;
1000 }
1001 switch (subsection_code) {
1002 case SECT_IF_REACHED:
1003 cmds = &cmds_limit->cmds_reached;
1004 break;
1005 case SECT_IF_NOT_REACHED:
1006 cmds = &cmds_limit->cmds_not_reached;
1007 break;
1008 default: /* SECT_NOTSET */
1009 return (run_cmds_cons(&cmds_limit->cmds,
1010 "rule %s { limit %s { sublimit %s { %s {}}}}",
1011 rule_name, limit_name, sublimit_name, section));
1012 }
1013 return (run_cmds_cons(cmds,
1014 "rule %s { limit %s { sublimit %s { %s { %s {}}}}}",
1015 rule_name, limit_name, sublimit_name, section, subsection));
1016 }
1017 # endif /* WITH_SUBLIMITS */
1018 # ifdef WITH_LIMITS
1019 if (limit_name != NULL) {
1020 switch (section_code) {
1021 case SECT_STARTUP:
1022 cmds_limit = &limit->rc[RC_STARTUP];
1023 break;
1024 case SECT_SHUTDOWN:
1025 cmds_limit = &limit->rc[RC_SHUTDOWN];
1026 break;
1027 default:
1028 if (subsection != NULL)
1029 goto failed_many;
1030 if (section_code == SECT_REACH)
1031 cmds = &limit->reach;
1032 else if (strcmp(section, "expire") == 0)
1033 cmds = &limit->expire.cmds;
1034 else if (strcmp(section, "restart") == 0)
1035 cmds = &limit->restart.cmds;
1036 else
1037 goto failed_sect;
1038 return (run_cmds_cons(cmds,
1039 "rule %s { limit %s { %s {}}}",
1040 rule_name, limit_name, section));
1041 }
1042 switch (subsection_code) {
1043 case SECT_IF_REACHED:
1044 cmds = &cmds_limit->cmds_reached;
1045 break;
1046 case SECT_IF_NOT_REACHED:
1047 cmds = &cmds_limit->cmds_not_reached;
1048 break;
1049 default: /* SECT_NOTSET */
1050 return (run_cmds_cons(&cmds_limit->cmds,
1051 "rule %s { limit %s { %s {}}}",
1052 rule_name, limit_name, section));
1053 }
1054 return (run_cmds_cons(cmds,
1055 "rule %s { limit %s { %s { %s {}}}}",
1056 rule_name, limit_name, section, subsection));
1057 }
1058 # endif /* WITH_LIMITS */
1059 # ifdef WITH_THRESHOLDS
1060 if (threshold_name != NULL) {
1061 switch (section_code) {
1062 case SECT_STARTUP:
1063 cmds = &threshold->rc[RC_STARTUP];
1064 break;
1065 case SECT_SHUTDOWN:
1066 cmds = &threshold->rc[RC_SHUTDOWN];
1067 break;
1068 default:
1069 if (strcmp(section, "below_threshold") == 0)
1070 cmds = &threshold->below_thr;
1071 else if (strcmp(section, "equal_threshold") == 0)
1072 cmds = &threshold->equal_thr;
1073 else if (strcmp(section, "above_threshold") == 0)
1074 cmds = &threshold->above_thr;
1075 else
1076 goto failed_sect;
1077 }
1078 return (run_cmds_cons(cmds,
1079 "rule %s { threshold %s { %s {}}}",
1080 rule_name, threshold_name, section));
1081 }
1082 # endif /* WITH_THRESHOLDS */
1083 if (rule_name != NULL) {
1084 switch (section_code) {
1085 case SECT_STARTUP:
1086 cmds_rule = &rule->rc[RC_STARTUP];
1087 break;
1088 case SECT_SHUTDOWN:
1089 cmds_rule = &rule->rc[RC_SHUTDOWN];
1090 break;
1091 default:
1092 goto failed_sect;
1093 }
1094 # ifdef WITH_LIMITS
1095 if (subsection != NULL) {
1096 if (strcmp(subsection, "if_any_reached") == 0)
1097 cmds = &cmds_rule->cmds_any_reached;
1098 else if (strcmp(subsection, "if_any_not_reached") == 0)
1099 cmds = &cmds_rule->cmds_any_not_reached;
1100 else if (strcmp(subsection, "if_all_reached") == 0)
1101 cmds = &cmds_rule->cmds_all_reached;
1102 else if (strcmp(subsection, "if_all_not_reached") == 0)
1103 cmds = &cmds_rule->cmds_all_not_reached;
1104 else
1105 goto failed_subs;
1106 return (run_cmds_cons(cmds,
1107 "rule %s { %s { %s {}}}",
1108 rule_name, section, subsection));
1109 }
1110 # endif /* WITH_LIMITS */
1111 return (run_cmds_cons(&cmds_rule->cmds,
1112 "rule %s { %s {}}", rule_name, section));
1113 }
1114 #endif /* WITH_RULES */
1115
1116 if (optind != argc)
1117 goto failed_many;
1118
1119 switch (section_code) {
1120 case SECT_STARTUP:
1121 cmds = &cmds_global[RC_STARTUP];
1122 break;
1123 case SECT_SHUTDOWN:
1124 cmds = &cmds_global[RC_SHUTDOWN];
1125 break;
1126 default:
1127 goto failed_sect;
1128 }
1129 return (run_cmds_cons(cmds, "%s {}", section));
1130
1131 #ifdef WITH_RULES
1132 failed_duped:
1133 exit_errx("-x: duplicated option -- %c", optopt);
1134 #endif
1135
1136 failed_many:
1137 exit_errx("-x: too many sections for the given options");
1138
1139 failed_sect:
1140 exit_errx("-x: unknown section \"%s\" for the given options", section);
1141
1142 #if defined(WITH_RULES) && defined(WITH_LIMITS)
1143 failed_subs:
1144 exit_errx("-x: unknown subsection \"%s\" for the given options",
1145 subsection);
1146 #endif
1147 }
1148
1149 /*
1150 * Implement "-u user" and "-g group" options.
1151 */
1152 static void
change_user(const char * u_name,const char * g_name)1153 change_user(const char *u_name, const char *g_name)
1154 {
1155 const struct passwd *pwd;
1156 const struct group *grp;
1157 char *endptr;
1158 uid_t uid;
1159 gid_t gid;
1160
1161 if (u_name == NULL && g_name == NULL)
1162 return;
1163
1164 xvlogmsgx = vlogmsgx_stderr;
1165
1166 if (g_name != NULL) {
1167 /* -g group */
1168 errno = 0;
1169 grp = getgrnam(g_name);
1170 if (grp == NULL) {
1171 if (errno != 0)
1172 exit_err("change_user: getgrnam(%s)", g_name);
1173 if (!isdigit((unsigned char)*g_name))
1174 exit_errx("cannot find group %s", g_name);
1175 errno = 0;
1176 gid = (gid_t)strtoul(g_name, &endptr, 10);
1177 if (errno != 0)
1178 exit_err("change_user: strtoul");
1179 if (g_name == endptr || *endptr != '\0')
1180 exit_errx("cannot find group %s", g_name);
1181 } else
1182 gid = grp->gr_gid;
1183 if (setgroups(1, &gid) < 0)
1184 exit_err("change_user: setgroups(1, [%lu])",
1185 (unsigned long)gid);
1186 }
1187
1188 if (u_name != NULL) {
1189 /* -u user */
1190 errno = 0;
1191 pwd = getpwnam(u_name);
1192 if (pwd == NULL) {
1193 if (errno != 0)
1194 exit_err("change_user: getpwnam(%s)", u_name);
1195 if (!isdigit((unsigned char)*u_name))
1196 exit_errx("cannot find user %s", u_name);
1197 if (g_name == NULL)
1198 exit_errx("argument in the -u option is not "
1199 "a valid user name");
1200 errno = 0;
1201 uid = (uid_t)strtoul(u_name, &endptr, 10);
1202 if (errno != 0)
1203 exit_err("change_user: strtoul");
1204 if (u_name == endptr || *endptr != '\0')
1205 exit_errx("cannot find user %s", u_name);
1206 } else {
1207 uid = pwd->pw_uid;
1208 if (g_name == NULL) {
1209 gid = pwd->pw_gid;
1210 if (setsuppgids(pwd->pw_name, gid) < 0)
1211 exit_errx("change_user: cannot set "
1212 "all groups for user %s", u_name);
1213 }
1214 }
1215 }
1216
1217 if (setgid(gid) < 0)
1218 exit_err("change_user: setgid(%lu)", (unsigned long)gid);
1219
1220 if (u_name != NULL && setuid(uid) < 0)
1221 exit_err("change_user: setuid(%lu)", (unsigned long)uid);
1222
1223 /*
1224 * To be sure, that descriptors used by getpw*() and getgr*()
1225 * functions are closed.
1226 */
1227 endpwent();
1228 endgrent();
1229 }
1230
1231 int
main(int argc,char * argv[])1232 main(int argc, char *argv[])
1233 {
1234 const char *k_optarg; /* -k signal */
1235 const char *u_name; /* -u user */
1236 const char *g_name; /* -g group */
1237 int opt; /* Current option. */
1238 int rv; /* Return value. */
1239 int action; /* Return code from ipa_main(). */
1240 char t_flag; /* Set if -t. */
1241 char x_flag; /* Set if -x. */
1242
1243 /* Save the program name. */
1244 envprogname = strrchr(argv[0], '/');
1245 if (envprogname != NULL)
1246 ++envprogname;
1247 else
1248 envprogname = argv[0];
1249
1250 k_optarg = u_name = g_name = NULL;
1251 t_flag = x_flag = 0;
1252 opterr = 0;
1253 while ((opt = getopt(argc, argv, ":c:df:g:hi:k:o:p:tu:vx")) != -1)
1254 switch (opt) {
1255 case ':':
1256 exit_errx("option requires an argument -- %c", optopt);
1257 /* NOTREACHED */
1258 case '?':
1259 exit_errx("illegal option -- %c", optopt);
1260 /* NOTREACHED */
1261 case 'c':
1262 if (*optarg != '/')
1263 exit_errx("path in the -%c option should be "
1264 "absolute", 'c');
1265 if (chroot(optarg) < 0)
1266 exit_err("main: chroot(%s)", optarg);
1267 break;
1268 case 'd':
1269 debug = 1;
1270 break;
1271 case 'f':
1272 ipa_conf_file = optarg;
1273 break;
1274 case 'g':
1275 g_name = optarg;
1276 break;
1277 case 'h':
1278 usage();
1279 return (EXIT_SUCCESS);
1280 case 'i':
1281 log_ident = optarg;
1282 break;
1283 case 'k':
1284 k_optarg = optarg;
1285 break;
1286 case 'o':
1287 log_file = optarg;
1288 if (*log_file != '/')
1289 exit_errx("path in the -%c option should be "
1290 "absolute", 'o');
1291 break;
1292 case 'p':
1293 pid_file_name = optarg;
1294 if (*pid_file_name != '/')
1295 exit_errx("path in the -%c option should be "
1296 "absolute", 'c');
1297 break;
1298 case 't':
1299 if (t_flag)
1300 mimic_real_config = 1;
1301 else
1302 t_flag = 1;
1303 break;
1304 case 'u':
1305 u_name = optarg;
1306 break;
1307 case 'v':
1308 show_version();
1309 return (EXIT_SUCCESS);
1310 case 'x':
1311 x_flag = 1;
1312 goto getopt_done;
1313 default:
1314 exit_errx("unexpected option -- %c", optopt);
1315 }
1316
1317 if (optind < argc)
1318 exit_errx("non-switch argument \"%s\"", argv[optind]);
1319
1320 getopt_done:
1321 change_user(u_name, g_name);
1322
1323 if (k_optarg != NULL) {
1324 const struct sig_descr *sig;
1325
1326 for (sig = sig_descr_tbl; sig->signame != NULL; ++sig)
1327 if (strcmp(k_optarg, sig->signame) == 0) {
1328 sendsig(sig->signo);
1329 return (EXIT_SUCCESS);
1330 }
1331 exit_errx("illegal argument \"%s\" for the -k option",
1332 k_optarg);
1333 }
1334
1335 #ifdef HAVE_DL_INIT
1336 if (dl_init() != 0)
1337 exit_errx("main: dl_init failed");
1338 #endif
1339
1340 if (setlocale(LC_ALL, "") == NULL)
1341 exit_err("setlocale");
1342
1343 memfunc_pre_init();
1344
1345 myuid = getuid();
1346 mygid = getgid();
1347
1348 if (t_flag) {
1349 if (configure(TEST_PARSING) < 0)
1350 return (EXIT_FAILURE);
1351 show_config();
1352 return (EXIT_SUCCESS);
1353 }
1354
1355 if (x_flag) {
1356 if (configure(CMD_PARSING) < 0)
1357 return (EXIT_FAILURE);
1358 return (run_opt_cmds(argc, argv) < 0 ?
1359 EXIT_FAILURE : EXIT_SUCCESS);
1360 }
1361
1362 create_pid_file();
1363
1364 tzset();
1365
1366 init_log();
1367 open_log();
1368
1369 if (fd_init() < 0) {
1370 logbt("main");
1371 return (EXIT_FAILURE);
1372 }
1373
1374 logmsgx(IPA_LOG_INFO, IPA_NAME " (version " PACKAGE_VERSION ") "
1375 "started by UID %lu, GID %lu", (unsigned long)myuid,
1376 (unsigned long)mygid);
1377 #ifdef WITH_PTHREAD
1378 logmsgx(IPA_LOG_INFO, "thread-safe mode");
1379 #endif
1380 #ifdef WITH_MEMFUNC_DEBUG
1381 logmsgx(IPA_LOG_INFO, "memfunc debugging is enabled");
1382 #endif
1383
1384 rv = EXIT_FAILURE;
1385
1386 if (!debug) {
1387 if (bg_init() < 0) {
1388 logmsgx(IPA_LOG_ERR, "cannot run in the background");
1389 goto out_exit;
1390 }
1391 logmsgx(IPA_LOG_INFO, "started in background mode");
1392 } else
1393 logmsgx(IPA_LOG_INFO, "started in foreground mode");
1394
1395 if (lock_pid_file() < 0) {
1396 logmsgx(IPA_LOG_ERR, "cannot lock PID-file");
1397 goto out_exit;
1398 }
1399
1400 logmsgx(IPA_LOG_INFO, "maximum number of open descriptors is %d%s",
1401 nofile_max, nofile_max >= 0 ? "" : " (no limit)");
1402
1403 if (configure(CONFIG_PARSING) < 0) {
1404 logmsgx(IPA_LOG_ERR, "main: configure failed");
1405 goto out_exit_unlink;
1406 }
1407
1408 /* Startup. */
1409 if (sig_init_1() < 0)
1410 goto out_deinit;
1411
1412 logmsgx(IPA_LOG_INFO, "startup... all signals are blocked");
1413
1414 if (init_all() < 0)
1415 goto out_deinit;
1416
1417 if (run_all_cmds(RC_STARTUP) < 0)
1418 goto out_deinit;
1419
1420 /*
1421 * If second stage of signal initialization succeeded,
1422 * then begin to work.
1423 */
1424 if (sig_init_2() == 0) {
1425 /* Working... */
1426 for (;;) {
1427 action = ipa_main();
1428 if (action < 0) {
1429 /* Some error occurred. */
1430 break;
1431 }
1432 if (action == 0) {
1433 /* Normal exit. */
1434 rv = EXIT_SUCCESS;
1435 break;
1436 }
1437
1438 /* Reconfiguration. */
1439 rv = EXIT_SUCCESS;
1440 if (deinit_all() < 0)
1441 rv = EXIT_FAILURE;
1442 if (free_all() < 0)
1443 rv = EXIT_FAILURE;
1444 if (rv != EXIT_SUCCESS)
1445 goto out_exit_unlink;
1446 rv = EXIT_FAILURE;
1447 if (configure(RECONFIG_PARSING) < 0)
1448 goto out_exit_unlink;
1449
1450 /*
1451 * Now initialize everything and start to work
1452 * with new configuration.
1453 */
1454 logmsgx(IPA_LOG_INFO, "using new configuration");
1455 if (init_all() < 0)
1456 goto out_deinit;
1457 }
1458 }
1459
1460 /* Shutdown. */
1461 logmsgx(IPA_LOG_INFO, "shutdown... all signals are ignored");
1462 if (run_all_cmds(RC_SHUTDOWN) < 0)
1463 rv = EXIT_FAILURE;
1464
1465 out_deinit:
1466 /* Deiniting. */
1467 if (deinit_all() < 0)
1468 rv = EXIT_FAILURE;
1469 if (free_all() < 0)
1470 rv = EXIT_FAILURE;
1471
1472 out_exit_unlink:
1473 /* Unlink PID file, since it is locked by this process. */
1474 unlink_pid_file();
1475
1476 out_exit:
1477 /* Exiting. */
1478 #ifdef HAVE_DL_EXIT
1479 if (dl_exit() != 0) {
1480 logmsgx(IPA_LOG_ERR, "main: dl_exit failed");
1481 rv = EXIT_FAILURE;
1482 }
1483 #endif
1484 log_stdall();
1485 logmsgx(IPA_LOG_INFO, IPA_NAME " (version " PACKAGE_VERSION ") "
1486 "exited, return code is %d", rv);
1487
1488 close_log();
1489 return (rv);
1490 }
1491