birq.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. /*
  2. * birq
  3. *
  4. * Balance IRQ
  5. *
  6. */
  7. #ifdef HAVE_CONFIG_H
  8. #include "config.h"
  9. #endif /* HAVE_CONFIG_H */
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <unistd.h>
  13. #include <sys/types.h>
  14. #include <errno.h>
  15. #include <assert.h>
  16. #include <string.h>
  17. #include <signal.h>
  18. #include <syslog.h>
  19. #include <fcntl.h>
  20. #ifdef HAVE_GETOPT_H
  21. #include <getopt.h>
  22. #endif
  23. #include "log.h"
  24. #ifndef VERSION
  25. #define VERSION 1.0.0
  26. #endif
  27. #define QUOTE(t) #t
  28. #define version(v) printf("%s\n", v)
  29. #define BIRQ_PIDFILE "/var/run/birq.pid"
  30. /* Global signal vars */
  31. static volatile int sigterm = 0;
  32. static void sighandler(int signo);
  33. static void help(int status, const char *argv0);
  34. int daemonize(int nochdir, int noclose);
  35. struct options *opts_init(void);
  36. void opts_free(struct options *opts);
  37. static int opts_parse(int argc, char *argv[], struct options *opts);
  38. /* Command line options */
  39. struct options {
  40. char *pidfile;
  41. char *chroot;
  42. int debug; /* Don't daemonize in debug mode */
  43. int log_facility;
  44. };
  45. /*--------------------------------------------------------- */
  46. int main(int argc, char **argv)
  47. {
  48. int retval = -1;
  49. struct options *opts = NULL;
  50. int pidfd = -1;
  51. /* Signal vars */
  52. struct sigaction sig_act, sigpipe_act;
  53. sigset_t sig_set, sigpipe_set;
  54. /* Parse command line options */
  55. opts = opts_init();
  56. if (opts_parse(argc, argv, opts))
  57. goto err;
  58. /* Initialize syslog */
  59. openlog(argv[0], LOG_CONS, opts->log_facility);
  60. syslog(LOG_ERR, "Start daemon.\n");
  61. /* Fork the daemon */
  62. if (!opts->debug) {
  63. /* Daemonize */
  64. if (daemonize(0, 0) < 0) {
  65. syslog(LOG_ERR, "Can't daemonize\n");
  66. goto err;
  67. }
  68. /* Write pidfile */
  69. if ((pidfd = open(opts->pidfile,
  70. O_WRONLY | O_CREAT | O_EXCL | O_TRUNC,
  71. S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0) {
  72. syslog(LOG_WARNING, "Can't open pidfile %s: %s",
  73. opts->pidfile, strerror(errno));
  74. } else {
  75. char str[20];
  76. snprintf(str, sizeof(str), "%u\n", getpid());
  77. if (write(pidfd, str, strlen(str)) < 0)
  78. syslog(LOG_WARNING, "Can't write to %s: %s",
  79. opts->pidfile, strerror(errno));
  80. close(pidfd);
  81. }
  82. }
  83. #ifdef HAVE_CHROOT
  84. /* Chroot */
  85. if (opts->chroot) {
  86. if (chroot(opts->chroot) < 0) {
  87. syslog(LOG_ERR, "Can't chroot to %s: %s",
  88. opts->chroot, strerror(errno));
  89. goto err;
  90. }
  91. }
  92. #endif
  93. /* Set signal handler */
  94. sigemptyset(&sig_set);
  95. sigaddset(&sig_set, SIGTERM);
  96. sigaddset(&sig_set, SIGINT);
  97. sigaddset(&sig_set, SIGQUIT);
  98. sig_act.sa_flags = 0;
  99. sig_act.sa_mask = sig_set;
  100. sig_act.sa_handler = &sighandler;
  101. sigaction(SIGTERM, &sig_act, NULL);
  102. sigaction(SIGINT, &sig_act, NULL);
  103. sigaction(SIGQUIT, &sig_act, NULL);
  104. /* Ignore SIGPIPE */
  105. sigemptyset(&sigpipe_set);
  106. sigaddset(&sigpipe_set, SIGPIPE);
  107. sigpipe_act.sa_flags = 0;
  108. sigpipe_act.sa_mask = sigpipe_set;
  109. sigpipe_act.sa_handler = SIG_IGN;
  110. sigaction(SIGPIPE, &sigpipe_act, NULL);
  111. retval = 0;
  112. err:
  113. /* Remove pidfile */
  114. if (pidfd >= 0) {
  115. if (unlink(opts->pidfile) < 0) {
  116. syslog(LOG_ERR, "Can't remove pid-file %s: %s\n",
  117. opts->pidfile, strerror(errno));
  118. }
  119. }
  120. /* Free command line options */
  121. opts_free(opts);
  122. syslog(LOG_ERR, "Stop daemon.\n");
  123. return retval;
  124. }
  125. /*--------------------------------------------------------- */
  126. /*
  127. * Signal handler for temination signals (like SIGTERM, SIGINT, ...)
  128. */
  129. static void sighandler(int signo)
  130. {
  131. sigterm = 1;
  132. }
  133. /*--------------------------------------------------------- */
  134. /* Implement own simple daemon() to don't use Non-POSIX */
  135. int daemonize(int nochdir, int noclose)
  136. {
  137. int fd;
  138. int pid;
  139. pid = fork();
  140. if (-1 == pid)
  141. return -1;
  142. if (pid > 0)
  143. _exit(0); /* Exit parent */
  144. if (setsid() == -1)
  145. return -1;
  146. if (!nochdir) {
  147. if (chdir("/"))
  148. return -1;
  149. }
  150. if (!noclose) {
  151. fd = open("/dev/null", O_RDWR, 0);
  152. if (fd < 0)
  153. return -1;
  154. dup2(fd, STDIN_FILENO);
  155. dup2(fd, STDOUT_FILENO);
  156. dup2(fd, STDERR_FILENO);
  157. if (fd > 2)
  158. close(fd);
  159. }
  160. return 0;
  161. }
  162. /*--------------------------------------------------------- */
  163. /* Initialize option structure by defaults */
  164. struct options *opts_init(void)
  165. {
  166. struct options *opts = NULL;
  167. opts = malloc(sizeof(*opts));
  168. assert(opts);
  169. opts->debug = 0; /* daemonize by default */
  170. opts->pidfile = strdup(BIRQ_PIDFILE);
  171. opts->chroot = NULL;
  172. opts->log_facility = LOG_DAEMON;
  173. return opts;
  174. }
  175. /*--------------------------------------------------------- */
  176. /* Free option structure */
  177. void opts_free(struct options *opts)
  178. {
  179. if (opts->pidfile)
  180. free(opts->pidfile);
  181. if (opts->chroot)
  182. free(opts->chroot);
  183. free(opts);
  184. }
  185. /*--------------------------------------------------------- */
  186. /* Parse command line options */
  187. static int opts_parse(int argc, char *argv[], struct options *opts)
  188. {
  189. static const char *shortopts = "hvp:dr:O:";
  190. #ifdef HAVE_GETOPT_H
  191. static const struct option longopts[] = {
  192. {"help", 0, NULL, 'h'},
  193. {"version", 0, NULL, 'v'},
  194. {"pid", 1, NULL, 'p'},
  195. {"debug", 0, NULL, 'd'},
  196. {"chroot", 1, NULL, 'r'},
  197. {"facility", 1, NULL, 'O'},
  198. {NULL, 0, NULL, 0}
  199. };
  200. #endif
  201. optind = 1;
  202. while(1) {
  203. int opt;
  204. #ifdef HAVE_GETOPT_H
  205. opt = getopt_long(argc, argv, shortopts, longopts, NULL);
  206. #else
  207. opt = getopt(argc, argv, shortopts);
  208. #endif
  209. if (-1 == opt)
  210. break;
  211. switch (opt) {
  212. case 'p':
  213. if (opts->pidfile)
  214. free(opts->pidfile);
  215. opts->pidfile = strdup(optarg);
  216. break;
  217. case 'r':
  218. #ifdef HAVE_CHROOT
  219. if (opts->chroot)
  220. free(opts->chroot);
  221. opts->chroot = strdup(optarg);
  222. #else
  223. fprintf(stderr, "Error: The --chroot option is not supported.\n");
  224. return -1;
  225. #endif
  226. break;
  227. case 'd':
  228. opts->debug = 1;
  229. break;
  230. case 'O':
  231. if (parse_log_facility(optarg, &(opts->log_facility))) {
  232. fprintf(stderr, "Error: Illegal syslog facility %s.\n", optarg);
  233. help(-1, argv[0]);
  234. exit(-1);
  235. }
  236. break;
  237. case 'h':
  238. help(0, argv[0]);
  239. exit(0);
  240. break;
  241. case 'v':
  242. version(VERSION);
  243. exit(0);
  244. break;
  245. default:
  246. help(-1, argv[0]);
  247. exit(-1);
  248. break;
  249. }
  250. }
  251. return 0;
  252. }
  253. /*--------------------------------------------------------- */
  254. /* Print help message */
  255. static void help(int status, const char *argv0)
  256. {
  257. const char *name = NULL;
  258. if (!argv0)
  259. return;
  260. /* Find the basename */
  261. name = strrchr(argv0, '/');
  262. if (name)
  263. name++;
  264. else
  265. name = argv0;
  266. if (status != 0) {
  267. fprintf(stderr, "Try `%s -h' for more information.\n",
  268. name);
  269. } else {
  270. printf("Usage: %s [options]\n", name);
  271. printf("Daemon to store user configuration (i.e. commands). "
  272. "The part of the klish project.\n");
  273. printf("Options:\n");
  274. printf("\t-v, --version\tPrint version.\n");
  275. printf("\t-h, --help\tPrint this help.\n");
  276. printf("\t-d, --debug\tDebug mode. Don't daemonize.\n");
  277. printf("\t-p <path>, --pid=<path>\tFile to save daemon's PID to.\n");
  278. printf("\t-r <path>, --chroot=<path>\tDirectory to chroot.\n");
  279. printf("\t-O, --facility\tSyslog facility. Default is DAEMON.\n");
  280. }
  281. }