waffle

user and group backend daemon
git clone git://git.2f30.org/waffle.git
Log | Files | Refs | LICENSE

waffle.c (3519B)


      1 /* See LICENSE file for copyright and license details. */
      2 #include <sys/select.h>
      3 #include <sys/signalfd.h>
      4 #include <sys/socket.h>
      5 #include <sys/stat.h>
      6 #include <sys/types.h>
      7 #include <sys/un.h>
      8 #include <errno.h>
      9 #include <signal.h>
     10 #include <stdio.h>
     11 #include <stdlib.h>
     12 #include <string.h>
     13 #include <syslog.h>
     14 #include <unistd.h>
     15 #include "arg.h"
     16 #include "waffle.h"
     17 
     18 int daemonize = 1;
     19 int verbose = 0;
     20 char *argv0;
     21 static fd_set master;
     22 static int fdmax;
     23 
     24 static int
     25 serv_listen(const char *name)
     26 {
     27 	struct sockaddr_un sun;
     28 	int    fd, r;
     29 	socklen_t len;
     30 
     31 	fd = socket(AF_UNIX, SOCK_STREAM, 0);
     32 	if (fd < 0)
     33 		logerr("socket: %s\n", strerror(errno));
     34 
     35 	unlink(name);
     36 
     37 	memset(&sun, 0, sizeof(sun));
     38 	sun.sun_family = AF_UNIX;
     39 	strlcpy(sun.sun_path, name, sizeof(sun.sun_path));
     40 
     41 	len = sizeof(sun);
     42 	r = bind(fd, (struct sockaddr *)&sun, len);
     43 	if (r < 0)
     44 		logerr("bind %s: %s\n", name, strerror(errno));
     45 
     46 	if (chmod(name, 0666) < 0)
     47 		logerr("chmod %s: %s\n", name, strerror(errno));
     48 
     49 	r = listen(fd, 5);
     50 	if (r < 0)
     51 		logerr("listen: %s\n", strerror(errno));
     52 
     53 	return fd;
     54 }
     55 
     56 static int
     57 serv_accept(int listenfd)
     58 {
     59 	struct sockaddr_un sun;
     60 	int    clifd;
     61 	socklen_t len;
     62 
     63 	len = sizeof(sun);
     64 	clifd = accept(listenfd, (struct sockaddr *)&sun, &len);
     65 	if (clifd < 0)
     66 		logerr("accept: %s\n", strerror(errno));
     67 	return clifd;
     68 }
     69 
     70 static int
     71 add_cli(int clifd)
     72 {
     73 	struct timeval tv;
     74 
     75 	tv.tv_sec = 0;
     76 	tv.tv_usec = NSCDTIMEOUT * 1000;
     77 	if (setsockopt(clifd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) {
     78 		close(clifd);
     79 		return -1;
     80 	}
     81 	FD_SET(clifd, &master);
     82 	if (clifd > fdmax)
     83 		fdmax = clifd;
     84 	return 0;
     85 }
     86 
     87 static void
     88 del_cli(int clifd)
     89 {
     90 	FD_CLR(clifd, &master);
     91 	close(clifd);
     92 }
     93 
     94 static void
     95 usage(void)
     96 {
     97 	fprintf(stderr, "usage: %s [-dv]\n", argv0);
     98 	exit(1);
     99 }
    100 
    101 int
    102 main(int argc, char *argv[])
    103 {
    104 	FILE *fp;
    105 	sigset_t mask;
    106 	struct signalfd_siginfo si;
    107 	fd_set rfds;
    108 	int listenfd, clifd, sfd;
    109 	int i, n;
    110 	ssize_t r;
    111 
    112 	ARGBEGIN {
    113 	case 'd':
    114 		daemonize = 0;
    115 		break;
    116 	case 'v':
    117 		verbose++;
    118 		break;
    119 	default:
    120 		usage();
    121 	} ARGEND;
    122 
    123 	signal(SIGPIPE, SIG_IGN);
    124 	sigemptyset(&mask);
    125 	sigaddset(&mask, SIGTERM);
    126 	sigaddset(&mask, SIGINT);
    127 	sigprocmask(SIG_BLOCK, &mask, NULL);
    128 
    129 	if (daemonize) {
    130 		openlog(argv[0], LOG_CONS | LOG_PID, LOG_DAEMON);
    131 		if (daemon(0, 0) < 0)
    132 			logerr("daemon: %s\n", strerror(errno));
    133 		if ((fp = fopen(PIDFILE, "w"))) {
    134 			fprintf(fp, "%d\n", getpid());
    135 			fclose(fp);
    136 		}
    137 	}
    138 
    139 	listenfd = serv_listen(SOCKPATH);
    140 	FD_ZERO(&master);
    141 	FD_ZERO(&rfds);
    142 	FD_SET(listenfd, &master);
    143 	fdmax = listenfd;
    144 
    145 	sfd = signalfd(-1, &mask, 0);
    146 	if (sfd < 0)
    147 		logerr("signalfd: %s\n", strerror(errno));
    148 	FD_SET(sfd, &master);
    149 	if (sfd > fdmax)
    150 		fdmax = sfd;
    151 
    152 	if (backends_init() < 0)
    153 		logerr("no available backends\n");
    154 
    155 	while (1) {
    156 		rfds = master;
    157 		n = select(fdmax + 1, &rfds, NULL, NULL, NULL);
    158 		if (n < 0) {
    159 			if (errno == EINTR)
    160 				continue;
    161 			logerr("select: %s\n", strerror(errno));
    162 		}
    163 		for (i = 0; i <= fdmax; i++) {
    164 			if (!FD_ISSET(i, &rfds))
    165 				continue;
    166 			if (i == sfd) {
    167 				r = read(sfd, &si, sizeof(si));
    168 				if ((size_t)r != sizeof(si))
    169 					continue;
    170 				switch (si.ssi_signo) {
    171 				case SIGTERM:
    172 				case SIGINT:
    173 					goto out;
    174 				}
    175 			} else if (i == listenfd) {
    176 				clifd = serv_accept(listenfd);
    177 				if (add_cli(clifd) < 0)
    178 					continue;
    179 			} else {
    180 				if (handle_req(i) < 0)
    181 					logwarn("failed to handle request from fd %d\n", i);
    182 				del_cli(i);
    183 			}
    184 		}
    185 	}
    186 out:
    187 	backends_term();
    188 	if (daemonize) {
    189 		unlink(PIDFILE);
    190 		closelog();
    191 	}
    192 	exit(0);
    193 }