Esempio n. 1
0
static int open_ioctl_fd(int dev_autofs_fd, const char *where, dev_t devid) {
        struct autofs_dev_ioctl *param;
        size_t l;

        assert(dev_autofs_fd >= 0);
        assert(where);

        l = sizeof(struct autofs_dev_ioctl) + strlen(where) + 1;
        param = alloca(l);

        init_autofs_dev_ioctl(param);
        param->size = l;
        param->ioctlfd = -1;
        param->openmount.devid = devid;
        strcpy(param->path, where);

        if (ioctl(dev_autofs_fd, AUTOFS_DEV_IOCTL_OPENMOUNT, param) < 0)
                return -errno;

        if (param->ioctlfd < 0)
                return -EIO;

        (void) fd_cloexec(param->ioctlfd, true);
        return param->ioctlfd;
}
Esempio n. 2
0
File: util.c Progetto: aperezdc/dmon
void
become_daemon (void)
{
    pid_t pid;
    int nullfd = open ("/dev/null", O_RDWR, 0);

    if (nullfd < 0)
        w_die ("cannot daemonize, unable to open '/dev/null': $E\n");

    fd_cloexec (nullfd);

    if (dup2 (nullfd, STDIN_FILENO) < 0)
        w_die ("cannot daemonize, unable to redirect stdin: $E\n");
    if (dup2 (nullfd, STDOUT_FILENO) < 0)
        w_die ("cannot daemonize, unable to redirect stdout: $E\n");
    if (dup2 (nullfd, STDERR_FILENO) < 0)
        w_die ("cannot daemonize, unable to redirect stderr: $E\n");

    pid = fork ();

    if (pid < 0) w_die ("cannot daemonize: $E\n");
    if (pid > 0) _exit (EXIT_SUCCESS);

    if (setsid () == -1)
        _exit (111);
}
Esempio n. 3
0
int fdset_cloexec(FDSet *fds, bool b) {
        Iterator i;
        void *p;
        int r;

        assert(fds);

        SET_FOREACH(p, MAKE_SET(fds), i) {
                r = fd_cloexec(PTR_TO_FD(p), b);
                if (r < 0)
                        return r;
        }
Esempio n. 4
0
static int open_sockets(int *epoll_fd, bool accept) {
        char **address;
        int n, fd, r;
        int count = 0;

        n = sd_listen_fds(true);
        if (n < 0) {
                log_error("Failed to read listening file descriptors from environment: %s",
                          strerror(-n));
                return n;
        }
        if (n > 0) {
                log_info("Received %i descriptors via the environment.", n);

                for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) {
                        r = fd_cloexec(fd, arg_accept);
                        if (r < 0)
                                return r;

                        count ++;
                }
        }

        /* Close logging and all other descriptors */
        if (arg_listen) {
                int except[3 + n];

                for (fd = 0; fd < SD_LISTEN_FDS_START + n; fd++)
                        except[fd] = fd;

                log_close();
                close_all_fds(except, 3 + n);
        }

        /** Note: we leak some fd's on error here. I doesn't matter
         *  much, since the program will exit immediately anyway, but
         *  would be a pain to fix.
         */

        STRV_FOREACH(address, arg_listen) {

                fd = make_socket_fd(*address, SOCK_STREAM | (arg_accept*SOCK_CLOEXEC));
                if (fd < 0) {
                        log_open();
                        log_error("Failed to open '%s': %s", *address, strerror(-fd));
                        return fd;
                }

                assert(fd == SD_LISTEN_FDS_START + count);
                count ++;
        }
Esempio n. 5
0
/* do_choom()
**   if opt_e: abort on fail
**   no chdir(), no effect to cwd
*/
static
void
do_choom(void)
{
  int          fd;

  /* comment:
  ** normally we would first create/write a tmpfile
  ** then atomically rename() tmpfile into procfile
  ** but open(...,O_CREAT,...) of a new tmpfile on /proc fails (EEXIST)
  ** leaving no choice but to write into the procfile directly
  */

  if((fd = open(pathbuf, O_WRONLY | O_TRUNC, 0)) == -1){
      if(opt_e){
          fatal_syserr("failure on open() for path: ", pathbuf);
      }
      /* else: */
      if(opt_v){
          syserr_warn("ignoring failure on open() for path: ", pathbuf);
      }
      return;
  }
  fd_cloexec(fd);

  if(write_all(fd, setbuf, cstr_len(setbuf)) == -1){
      if(opt_e){
          fatal_syserr("failure on write() to path: ", pathbuf);
      }
      /* else: */
      if(opt_v){
          syserr_warn("ignoring failure on write() to path: ", pathbuf);
      }
      return;
  }

  /* comment:
  ** fsync() on /proc fails (EINVAL)
  ** so we simply ignore any following errors
  */
  fsync(fd);
  close(fd);

  /* success: */
  if(opt_v){
      eputs(progname, ": successfully configured ", pathbuf);
  } 

  return;
}
Esempio n. 6
0
int make_stdio(int fd) {
        int r, s, t;

        assert(fd >= 0);

        r = dup2(fd, STDIN_FILENO);
        s = dup2(fd, STDOUT_FILENO);
        t = dup2(fd, STDERR_FILENO);

        if (fd >= 3)
                safe_close(fd);

        if (r < 0 || s < 0 || t < 0)
                return -errno;

        /* Explicitly unset O_CLOEXEC, since if fd was < 3, then
         * dup2() was a NOP and the bit hence possibly set. */
        fd_cloexec(STDIN_FILENO, false);
        fd_cloexec(STDOUT_FILENO, false);
        fd_cloexec(STDERR_FILENO, false);

        return 0;
}
Esempio n. 7
0
static
void
setup(void)
{
  int  i = 0;

  if(pipe(my_sigpipe) == -1){
      fatal_syserr("failure setting up selfpipe");
  }

  for(i = 0; i < 2; ++i){
      fd_cloexec(my_sigpipe[i]);
      fd_nonblock(my_sigpipe[i]);
  }

  if(pipe(my_logpipe) == -1){
      fatal_syserr("failure creating logpipe");
  }

  sigset_fill(&my_sigset);
  sigset_block(&my_sigset);

  sig_catch(SIGTERM, &sigtrap);
  sig_catch(SIGINT, &sigtrap);
  sig_catch(SIGCHLD, &sigtrap);

  /* catching these signals to pass to program: */
  sig_catch(SIGALRM, &sigtrap);
  sig_catch(SIGCONT, &sigtrap);
  sig_catch(SIGHUP, &sigtrap);
  sig_catch(SIGQUIT, &sigtrap);
  sig_catch(SIGTSTP, &sigtrap);
  sig_catch(SIGUSR1, &sigtrap);
  sig_catch(SIGUSR2, &sigtrap);

  sig_ignore(SIGPIPE);
  return;
}    
Esempio n. 8
0
void *epoll_init(EL_P loop) {
    EEPOLL_P ept = (EEPOLL_P)mm_malloc(sizeof(struct evt_epoll));
    memset(ept, 0, sizeof(struct evt_epoll));

    /* use epoll_create1 first */
#ifdef EPOLL_CLOEXEC
    ept->fd = epoll_create1(EPOLL_CLOEXEC);
#else
    ept->fd = epoll_create(1);
    if (ept->fd >= 0) 
        fd_cloexec(ept->fd);
#endif

    if (ept->fd < 0) {
        goto epoll_init_failed;
    }
    ept->feature = loop->poll_feature;
    ept->nevent = EPOLL_INIT_NEVENT;
    ept->event = (EP_EVT*)mm_malloc(sizeof(EP_EVT) * EPOLL_INIT_NEVENT);

    /* init fucntion pointer with loop*/
    loop->poll_destroy = epoll_destroy;
    loop->poll_dispatch = epoll_dispatch;
    loop->poll_update = epoll_update;

    log_inner("epoll(%d) init complete!", ept->fd);
    return ept;

epoll_init_failed:
    log_error("epoll init failed!");
    if (ept->fd > 0)
        close (ept->fd);
    if (ept->event)
        mm_free(ept->event);
    mm_free(ept);
    return NULL;
}
Esempio n. 9
0
void stdio_unset_cloexec(void) {
        fd_cloexec(STDIN_FILENO, false);
        fd_cloexec(STDOUT_FILENO, false);
        fd_cloexec(STDERR_FILENO, false);
}
Esempio n. 10
0
static int add_epoll(int epoll_fd, int fd) {
        struct epoll_event ev = {
                .events = EPOLLIN,
                .data.fd = fd,
        };

        assert(epoll_fd >= 0);
        assert(fd >= 0);

        if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0)
                return log_error_errno(errno, "Failed to add event on epoll fd:%d for fd:%d: %m", epoll_fd, fd);

        return 0;
}

static int open_sockets(int *epoll_fd, bool accept) {
        char **address;
        int n, fd, r;
        int count = 0;

        n = sd_listen_fds(true);
        if (n < 0)
                return log_error_errno(n, "Failed to read listening file descriptors from environment: %m");
        if (n > 0) {
                log_info("Received %i descriptors via the environment.", n);

                for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) {
                        r = fd_cloexec(fd, arg_accept);
                        if (r < 0)
                                return r;

                        count++;
                }
        }

        /* Close logging and all other descriptors */
        if (arg_listen) {
                int except[3 + n];

                for (fd = 0; fd < SD_LISTEN_FDS_START + n; fd++)
                        except[fd] = fd;

                log_close();
                close_all_fds(except, 3 + n);
        }

        /** Note: we leak some fd's on error here. I doesn't matter
         *  much, since the program will exit immediately anyway, but
         *  would be a pain to fix.
         */

        STRV_FOREACH(address, arg_listen) {
                fd = make_socket_fd(LOG_DEBUG, *address, arg_socket_type, (arg_accept*SOCK_CLOEXEC));
                if (fd < 0) {
                        log_open();
                        return log_error_errno(fd, "Failed to open '%s': %m", *address);
                }

                assert(fd == SD_LISTEN_FDS_START + count);
                count++;
        }
Esempio n. 11
0
/* perpd_svdef_activate()
**   activate service definition
**   called by perpd_scan()
**
**   return:
**     0: success
**    -1: failure
**
**   notes:
**     failures include:
**       - service definition directory name too long
**         (must me less than, say, 240 characters)
**       - open() on service definition directory
**       - pipe() for logpipe
**     service is activated only on success
*/
int
perpd_svdef_activate(struct svdef *svdef, const char *svdir, const struct stat *st_dir)
{
  struct stat  st;
  char         path_buf[256];
  int          fd;

  perpd_svdef_clear(svdef);

  if(cstr_len(svdir) > 240){
      errno = ENAMETOOLONG;
      warn_syserr("service definition directory name error: ", svdir);
      return -1;
  }

  svdef->dev = st_dir->st_dev;
  svdef->ino = st_dir->st_ino;
  cstr_lcpy(svdef->name, svdir, sizeof svdef->name);
  tain_now(&svdef->when);
  svdef->bitflags |= SVDEF_FLAG_ACTIVE;

  /* open an fd to use for fchdir() in perpd_svrun(): */
  cstr_vcopy(path_buf, "./", svdir);
  if((fd = open(path_buf, O_RDONLY)) == -1){
      warn_syserr("failure open() on service definition directory ", svdir);
      return -1;
  }
  fd_cloexec(fd);
  svdef->fd_dir = fd;

  /* inspect service definition directory: */
  cstr_vcopy(path_buf, "./", svdir, "/flag.down");
  if(stat(path_buf, &st) != -1){
      svdef->bitflags |= SVDEF_FLAG_DOWN;
  }
  cstr_vcopy(path_buf, "./", svdir, "/flag.once");
  if(stat(path_buf, &st) != -1){
      svdef->bitflags |= SVDEF_FLAG_ONCE;
  }

  /* logging? */
  cstr_vcopy(path_buf, "./", svdir, "/rc.log");
  if(stat(path_buf, &st) != -1){
      if(st.st_mode & S_IXUSR){
          svdef->bitflags |= SVDEF_FLAG_HASLOG;
          log_debug("rc.log exists and is executable for ", svdir);
      }else{
          log_warning("rc.log exists but is not set executable for ", svdir);
      }
  }

  /* setup logpipe: */
  if(svdef->bitflags & SVDEF_FLAG_HASLOG){
      if(pipe(svdef->logpipe) == -1){
          warn_syserr("failure pipe() on logpipe for ", svdir);
          close(fd);
          return -1;
      }
      fd_cloexec(svdef->logpipe[0]);
      fd_cloexec(svdef->logpipe[1]);
  } 

  /*
  ** from here on, the service is considered activated
  */

  /* first time startup: */
  /* log: if FLAG_HASLOG, start irrespective of any other svdef->bitflags: */
  if(svdef->bitflags & SVDEF_FLAG_HASLOG){
      svdef->svpair[SUBSV_LOG].bitflags |= SUBSV_FLAG_ISLOG;
      perpd_svdef_run(svdef, SUBSV_LOG, SVRUN_START);
  }

  /* XXX, bail here if log startup fails on fork() ?  */

  /* main: */
  if(!(svdef->bitflags & SVDEF_FLAG_DOWN)){
      /* setup for running once? */
      if(svdef->bitflags & SVDEF_FLAG_ONCE){
          svdef->svpair[SUBSV_MAIN].bitflags |= SUBSV_FLAG_ISONCE;
      }
      perpd_svdef_run(svdef, SUBSV_MAIN, SVRUN_START);
  } else {
      svdef->svpair[SUBSV_MAIN].bitflags |= SUBSV_FLAG_WANTDOWN;
  }
 
  return 0;
}
Esempio n. 12
0
int main (int argc, char **argv)
{
#ifdef HAVE_LUA
	/* Lua runtime */
	lua_State *L = NULL;
#endif

	/* master file descriptor list */
	fd_set used_fds, serv_fds, read_fds;

	/* working structs */
	struct addrinfo hints;
	struct http_request *req;
	struct path_info *pin;
	struct client *cl;
	struct sigaction sa;
	struct config conf;

	/* signal mask */
	sigset_t ss;

	/* maximum file descriptor number */
	int new_fd, cur_fd, max_fd = 0;

	int tls = 0;
	int keys = 0;
	int bound = 0;
	int nofork = 0;

	/* args */
	int opt;
	char bind[128];
	char *port = NULL;

	/* library handles */
	void *tls_lib;
	void *lua_lib;

	/* clear the master and temp sets */
	FD_ZERO(&used_fds);
	FD_ZERO(&serv_fds);
	FD_ZERO(&read_fds);

	/* handle SIGPIPE, SIGINT, SIGTERM, SIGCHLD */
	sa.sa_flags = 0;
	sigemptyset(&sa.sa_mask);

	sa.sa_handler = SIG_IGN;
	sigaction(SIGPIPE, &sa, NULL);

	sa.sa_handler = uh_sigchld;
	sigaction(SIGCHLD, &sa, NULL);

	sa.sa_handler = uh_sigterm;
	sigaction(SIGINT,  &sa, NULL);
	sigaction(SIGTERM, &sa, NULL);

	/* defer SIGCHLD */
	sigemptyset(&ss);
	sigaddset(&ss, SIGCHLD);
	sigprocmask(SIG_BLOCK, &ss, NULL);

	/* prepare addrinfo hints */
	memset(&hints, 0, sizeof(hints));
	hints.ai_family   = AF_UNSPEC;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_flags    = AI_PASSIVE;

	/* parse args */
	memset(&conf, 0, sizeof(conf));
	memset(bind, 0, sizeof(bind));

#ifdef HAVE_TLS
	/* load TLS plugin */
	if( ! (tls_lib = dlopen("uhttpd_tls.so", RTLD_LAZY | RTLD_GLOBAL)) )
	{
		fprintf(stderr,
			"Notice: Unable to load TLS plugin - disabling SSL support! "
			"(Reason: %s)\n", dlerror()
		);
	}
	else
	{
		/* resolve functions */
		if( !(conf.tls_init   = dlsym(tls_lib, "uh_tls_ctx_init"))      ||
		    !(conf.tls_cert   = dlsym(tls_lib, "uh_tls_ctx_cert"))      ||
		    !(conf.tls_key    = dlsym(tls_lib, "uh_tls_ctx_key"))       ||
		    !(conf.tls_free   = dlsym(tls_lib, "uh_tls_ctx_free"))      ||
			!(conf.tls_accept = dlsym(tls_lib, "uh_tls_client_accept")) ||
			!(conf.tls_close  = dlsym(tls_lib, "uh_tls_client_close"))  ||
			!(conf.tls_recv   = dlsym(tls_lib, "uh_tls_client_recv"))   ||
			!(conf.tls_send   = dlsym(tls_lib, "uh_tls_client_send"))
		) {
			fprintf(stderr,
				"Error: Failed to lookup required symbols "
				"in TLS plugin: %s\n", dlerror()
			);
			exit(1);
		}

		/* init SSL context */
		if( ! (conf.tls = conf.tls_init()) )
		{
			fprintf(stderr, "Error: Failed to initalize SSL context\n");
			exit(1);
		}
	}
#endif

	while( (opt = getopt(argc, argv, "fC:K:p:s:h:c:l:L:d:r:m:x:t:")) > 0 )
	{
		switch(opt)
		{
			/* [addr:]port */
			case 'p':
			case 's':
				if( (port = strrchr(optarg, ':')) != NULL )
				{
					if( (optarg[0] == '[') && (port > optarg) && (port[-1] == ']') )
						memcpy(bind, optarg + 1,
							min(sizeof(bind), (int)(port - optarg) - 2));
					else
						memcpy(bind, optarg,
							min(sizeof(bind), (int)(port - optarg)));

					port++;
				}
				else
				{
					port = optarg;
				}

#ifdef HAVE_TLS
				if( opt == 's' )
				{
					if( !conf.tls )
					{
						fprintf(stderr,
							"Notice: TLS support is disabled, "
							"ignoring '-s %s'\n", optarg
						);
						continue;
					}

					tls = 1;
				}
#endif

				/* bind sockets */
				bound += uh_socket_bind(
					&serv_fds, &max_fd, bind[0] ? bind : NULL, port,
					&hints,	(opt == 's'), &conf
				);

				break;

#ifdef HAVE_TLS
			/* certificate */
			case 'C':
				if( conf.tls )
				{
					if( conf.tls_cert(conf.tls, optarg) < 1 )
					{
						fprintf(stderr,
							"Error: Invalid certificate file given\n");
						exit(1);
					}

					keys++;
				}

				break;

			/* key */
			case 'K':
				if( conf.tls )
				{
					if( conf.tls_key(conf.tls, optarg) < 1 )
					{
						fprintf(stderr,
							"Error: Invalid private key file given\n");
						exit(1);
					}

					keys++;
				}

				break;
#endif

			/* docroot */
			case 'h':
				if( ! realpath(optarg, conf.docroot) )
				{
					fprintf(stderr, "Error: Invalid directory %s: %s\n",
						optarg, strerror(errno));
					exit(1);
				}
				break;

#ifdef HAVE_CGI
			/* cgi prefix */
			case 'x':
				conf.cgi_prefix = optarg;
				break;
#endif

#ifdef HAVE_LUA
			/* lua prefix */
			case 'l':
				conf.lua_prefix = optarg;
				break;

			/* lua handler */
			case 'L':
				conf.lua_handler = optarg;
				break;
#endif

#if defined(HAVE_CGI) || defined(HAVE_LUA)
			/* script timeout */
			case 't':
				conf.script_timeout = atoi(optarg);
				break;
#endif

			/* no fork */
			case 'f':
				nofork = 1;
				break;

			/* urldecode */
			case 'd':
				if( (port = malloc(strlen(optarg)+1)) != NULL )
				{
					memset(port, 0, strlen(optarg)+1);
					uh_urldecode(port, strlen(optarg), optarg, strlen(optarg));
					printf("%s", port);
					free(port);
					exit(0);
				}
				break;

			/* basic auth realm */
			case 'r':
				conf.realm = optarg;
				break;

			/* md5 crypt */
			case 'm':
				printf("%s\n", crypt(optarg, "$1$"));
				exit(0);
				break;

			/* config file */
			case 'c':
				conf.file = optarg;
				break;

			default:
				fprintf(stderr,
					"Usage: %s -p [addr:]port [-h docroot]\n"
					"	-f              Do not fork to background\n"
					"	-c file         Configuration file, default is '/etc/httpd.conf'\n"
					"	-p [addr:]port  Bind to specified address and port, multiple allowed\n"
#ifdef HAVE_TLS
					"	-s [addr:]port  Like -p but provide HTTPS on this port\n"
					"	-C file         ASN.1 server certificate file\n"
					"	-K file         ASN.1 server private key file\n"
#endif
					"	-h directory    Specify the document root, default is '.'\n"
#ifdef HAVE_LUA
					"	-l string       URL prefix for Lua handler, default is '/lua'\n"
					"	-L file         Lua handler script, omit to disable Lua\n"
#endif
#ifdef HAVE_CGI
					"	-x string       URL prefix for CGI handler, default is '/cgi-bin'\n"
#endif
#if defined(HAVE_CGI) || defined(HAVE_LUA)
					"	-t seconds      CGI and Lua script timeout in seconds, default is 60\n"
#endif
					"	-d string       URL decode given string\n"
					"	-r string       Specify basic auth realm\n"
					"	-m string       MD5 crypt given string\n"
					"\n", argv[0]
				);

				exit(1);
		}
	}

#ifdef HAVE_TLS
	if( (tls == 1) && (keys < 2) )
	{
		fprintf(stderr, "Error: Missing private key or certificate file\n");
		exit(1);
	}
#endif

	if( bound < 1 )
	{
		fprintf(stderr, "Error: No sockets bound, unable to continue\n");
		exit(1);
	}

	/* default docroot */
	if( !conf.docroot[0] && !realpath(".", conf.docroot) )
	{
		fprintf(stderr, "Error: Can not determine default document root: %s\n",
			strerror(errno));
		exit(1);
	}

	/* default realm */
	if( ! conf.realm )
		conf.realm = "Protected Area";

	/* config file */
	uh_config_parse(conf.file);

#if defined(HAVE_CGI) || defined(HAVE_LUA)
	/* default script timeout */
	if( conf.script_timeout <= 0 )
		conf.script_timeout = 60;
#endif

#ifdef HAVE_CGI
	/* default cgi prefix */
	if( ! conf.cgi_prefix )
		conf.cgi_prefix = "/cgi-bin";
#endif

#ifdef HAVE_LUA
	/* load Lua plugin */
	if( ! (lua_lib = dlopen("uhttpd_lua.so", RTLD_LAZY | RTLD_GLOBAL)) )
	{
		fprintf(stderr,
			"Notice: Unable to load Lua plugin - disabling Lua support! "
			"(Reason: %s)\n", dlerror()
		);
	}
	else
	{
		/* resolve functions */
		if( !(conf.lua_init    = dlsym(lua_lib, "uh_lua_init"))    ||
		    !(conf.lua_close   = dlsym(lua_lib, "uh_lua_close"))   ||
		    !(conf.lua_request = dlsym(lua_lib, "uh_lua_request"))
		) {
			fprintf(stderr,
				"Error: Failed to lookup required symbols "
				"in Lua plugin: %s\n", dlerror()
			);
			exit(1);
		}

		/* init Lua runtime if handler is specified */
		if( conf.lua_handler )
		{
			/* default lua prefix */
			if( ! conf.lua_prefix )
				conf.lua_prefix = "/lua";

			L = conf.lua_init(conf.lua_handler);
		}
	}
#endif

	/* fork (if not disabled) */
	if( ! nofork )
	{
		switch( fork() )
		{
			case -1:
				perror("fork()");
				exit(1);

			case 0:
				/* daemon setup */
				if( chdir("/") )
					perror("chdir()");

				if( (cur_fd = open("/dev/null", O_WRONLY)) > -1 )
					dup2(cur_fd, 0);

				if( (cur_fd = open("/dev/null", O_RDONLY)) > -1 )
					dup2(cur_fd, 1);

				if( (cur_fd = open("/dev/null", O_RDONLY)) > -1 )
					dup2(cur_fd, 2);

				break;

			default:
				exit(0);
		}
	}

	/* backup server descriptor set */
	used_fds = serv_fds;

	/* loop */
	while(run)
	{
		/* create a working copy of the used fd set */
		read_fds = used_fds;

		/* sleep until socket activity */
		if( select(max_fd + 1, &read_fds, NULL, NULL, NULL) == -1 )
		{
			perror("select()");
			exit(1);
		}

		/* run through the existing connections looking for data to be read */
		for( cur_fd = 0; cur_fd <= max_fd; cur_fd++ )
		{
			/* is a socket managed by us */
			if( FD_ISSET(cur_fd, &read_fds) )
			{
				/* is one of our listen sockets */
				if( FD_ISSET(cur_fd, &serv_fds) )
				{
					/* handle new connections */
					if( (new_fd = accept(cur_fd, NULL, 0)) != -1 )
					{
						/* add to global client list */
						if( (cl = uh_client_add(new_fd, uh_listener_lookup(cur_fd))) != NULL )
						{
#ifdef HAVE_TLS
							/* setup client tls context */
							if( conf.tls )
								conf.tls_accept(cl);
#endif

							/* add client socket to global fdset */
							FD_SET(new_fd, &used_fds);
							fd_cloexec(new_fd);
							max_fd = max(max_fd, new_fd);
						}

						/* insufficient resources */
						else
						{
							fprintf(stderr,
								"uh_client_add(): Can not manage more than "
								"%i client sockets, connection dropped\n",
								UH_LIMIT_CLIENTS
							);

							close(new_fd);
						}
					}
				}

				/* is a client socket */
				else
				{
					if( ! (cl = uh_client_lookup(cur_fd)) )
					{
						/* this should not happen! */
						fprintf(stderr,
							"uh_client_lookup(): No entry for fd %i!\n",
							cur_fd);

						goto cleanup;
					}

					/* parse message header */
					if( (req = uh_http_header_recv(cl)) != NULL )
					{
#ifdef HAVE_LUA
						/* Lua request? */
						if( L && uh_path_match(conf.lua_prefix, req->url) )
						{
							conf.lua_request(cl, req, L);
						}
						else
#endif
						/* dispatch request */
						if( (pin = uh_path_lookup(cl, req->url)) != NULL )
						{
							/* auth ok? */
							if( uh_auth_check(cl, req, pin) )
							{
#ifdef HAVE_CGI
								if( uh_path_match(conf.cgi_prefix, pin->name) )
								{
									uh_cgi_request(cl, req, pin);
								}
								else
#endif
								{
									uh_file_request(cl, req, pin);
								}
							}
						}

						/* 404 */
						else
						{
							uh_http_sendhf(cl, 404, "Not Found",
								"No such file or directory");
						}
					}

					/* 400 */
					else
					{
						uh_http_sendhf(cl, 400, "Bad Request",
							"Malformed request received");
					}

#ifdef HAVE_TLS
					/* free client tls context */
					if( conf.tls )
						conf.tls_close(cl);
#endif

					cleanup:

					/* close client socket */
					close(cur_fd);
					FD_CLR(cur_fd, &used_fds);

					/* remove from global client list */
					uh_client_remove(cur_fd);
				}
			}
		}
	}

#ifdef HAVE_LUA
	/* destroy the Lua state */
	if( L != NULL )
		conf.lua_close(L);
#endif

	return 0;
}
Esempio n. 13
0
static int uh_socket_bind(
	fd_set *serv_fds, int *max_fd, const char *host, const char *port,
	struct addrinfo *hints, int do_tls, struct config *conf
) {
	int sock = -1;
	int yes = 1;
	int status;
	int bound = 0;

	struct listener *l = NULL;
	struct addrinfo *addrs = NULL, *p = NULL;

	if( (status = getaddrinfo(host, port, hints, &addrs)) != 0 )
	{
		fprintf(stderr, "getaddrinfo(): %s\n", gai_strerror(status));
	}

	/* try to bind a new socket to each found address */
	for( p = addrs; p; p = p->ai_next )
	{
		/* get the socket */
		if( (sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1 )
		{
			perror("socket()");
			goto error;
		}

		/* "address already in use" */
		if( setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) == -1 )
		{
			perror("setsockopt()");
			goto error;
		}

		/* required to get parallel v4 + v6 working */
		if( p->ai_family == AF_INET6 )
		{
			if( setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(yes)) == -1 )
			{
				perror("setsockopt()");
				goto error;
			}
		}

		/* bind */
		if( bind(sock, p->ai_addr, p->ai_addrlen) == -1 )
		{
			perror("bind()");
			goto error;
		}

		/* listen */
		if( listen(sock, UH_LIMIT_CLIENTS) == -1 )
		{
			perror("listen()");
			goto error;
		}

		/* add listener to global list */
		if( ! (l = uh_listener_add(sock, conf)) )
		{
			fprintf(stderr,
				"uh_listener_add(): Can not create more than "
				"%i listen sockets\n", UH_LIMIT_LISTENERS
			);

			goto error;
		}

#ifdef HAVE_TLS
		/* init TLS */
		l->tls = do_tls ? conf->tls : NULL;
#endif

		/* add socket to server fd set */
		FD_SET(sock, serv_fds);
		fd_cloexec(sock);
		*max_fd = max(*max_fd, sock);

		bound++;
		continue;

		error:
		if( sock > 0 )
			close(sock);
	}

	freeaddrinfo(addrs);

	return bound;
}
Esempio n. 14
0
static int uh_socket_bind(
	fd_set *serv_fds, int *max_fd, const char *host, const char *port,
	struct addrinfo *hints, int do_tls, struct config *conf
) {
	int sock = -1;
	int yes = 1;
	int status;
	int bound = 0;

	int tcp_ka_idl, tcp_ka_int, tcp_ka_cnt;

	struct listener *l = NULL;
	struct addrinfo *addrs = NULL, *p = NULL;

	if( (status = getaddrinfo(host, port, hints, &addrs)) != 0 )
	{
		fprintf(stderr, "getaddrinfo(): %s\n", gai_strerror(status));
	}

	/* try to bind a new socket to each found address */
	for( p = addrs; p; p = p->ai_next )
	{
		/* get the socket */
		if( (sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1 )
		{
			perror("socket()");
			goto error;
		}

		/* "address already in use" */
		if( setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) )
		{
			perror("setsockopt()");
			goto error;
		}

		/* TCP keep-alive */
		if( conf->tcp_keepalive > 0 )
		{
			tcp_ka_idl = 1;
			tcp_ka_cnt = 3;
			tcp_ka_int = conf->tcp_keepalive;

			if( setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof(yes)) ||
			    setsockopt(sock, SOL_TCP, TCP_KEEPIDLE,  &tcp_ka_idl, sizeof(tcp_ka_idl)) ||
			    setsockopt(sock, SOL_TCP, TCP_KEEPINTVL, &tcp_ka_int, sizeof(tcp_ka_int)) ||
			    setsockopt(sock, SOL_TCP, TCP_KEEPCNT,   &tcp_ka_cnt, sizeof(tcp_ka_cnt)) )
			{
			    fprintf(stderr, "Notice: Unable to enable TCP keep-alive: %s\n",
			    	strerror(errno));
			}
		}

		/* required to get parallel v4 + v6 working */
		if( p->ai_family == AF_INET6 )
		{
			if( setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(yes)) == -1 )
			{
				perror("setsockopt()");
				goto error;
			}
		}

		/* bind */
		if( bind(sock, p->ai_addr, p->ai_addrlen) == -1 )
		{
			perror("bind()");
			goto error;
		}

		/* listen */
		if( listen(sock, UH_LIMIT_CLIENTS) == -1 )
		{
			perror("listen()");
			goto error;
		}

		/* add listener to global list */
		if( ! (l = uh_listener_add(sock, conf)) )
		{
			fprintf(stderr, "uh_listener_add(): Failed to allocate memory\n");
			goto error;
		}

#ifdef HAVE_TLS
		/* init TLS */
		l->tls = do_tls ? conf->tls : NULL;
#endif

		/* add socket to server fd set */
		FD_SET(sock, serv_fds);
		fd_cloexec(sock);
		*max_fd = max(*max_fd, sock);

		bound++;
		continue;

		error:
		if( sock > 0 )
			close(sock);
	}

	freeaddrinfo(addrs);

	return bound;
}
Esempio n. 15
0
int import_fork_tar_x(const char *path, pid_t *ret) {
        _cleanup_close_pair_ int pipefd[2] = { -1, -1 };
        pid_t pid;
        int r;

        assert(path);
        assert(ret);

        if (pipe2(pipefd, O_CLOEXEC) < 0)
                return log_error_errno(errno, "Failed to create pipe for tar: %m");

        pid = fork();
        if (pid < 0)
                return log_error_errno(errno, "Failed to fork off tar: %m");

        if (pid == 0) {
                int null_fd;
                uint64_t retain =
                        (1ULL << CAP_CHOWN) |
                        (1ULL << CAP_FOWNER) |
                        (1ULL << CAP_FSETID) |
                        (1ULL << CAP_MKNOD) |
                        (1ULL << CAP_SETFCAP) |
                        (1ULL << CAP_DAC_OVERRIDE);

                /* Child */

                reset_all_signal_handlers();
                reset_signal_mask();
                assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);

                pipefd[1] = safe_close(pipefd[1]);

                if (dup2(pipefd[0], STDIN_FILENO) != STDIN_FILENO) {
                        log_error_errno(errno, "Failed to dup2() fd: %m");
                        _exit(EXIT_FAILURE);
                }

                if (pipefd[0] != STDIN_FILENO)
                        pipefd[0] = safe_close(pipefd[0]);

                null_fd = open("/dev/null", O_WRONLY|O_NOCTTY);
                if (null_fd < 0) {
                        log_error_errno(errno, "Failed to open /dev/null: %m");
                        _exit(EXIT_FAILURE);
                }

                if (dup2(null_fd, STDOUT_FILENO) != STDOUT_FILENO) {
                        log_error_errno(errno, "Failed to dup2() fd: %m");
                        _exit(EXIT_FAILURE);
                }

                if (null_fd != STDOUT_FILENO)
                        null_fd = safe_close(null_fd);

                fd_cloexec(STDIN_FILENO, false);
                fd_cloexec(STDOUT_FILENO, false);
                fd_cloexec(STDERR_FILENO, false);

                if (unshare(CLONE_NEWNET) < 0)
                        log_error_errno(errno, "Failed to lock tar into network namespace, ignoring: %m");

                r = capability_bounding_set_drop(~retain, true);
                if (r < 0)
                        log_error_errno(r, "Failed to drop capabilities, ignoring: %m");

                execlp("tar", "tar", "--numeric-owner", "-C", path, "-px", NULL);
                log_error_errno(errno, "Failed to execute tar: %m");
                _exit(EXIT_FAILURE);
        }

        pipefd[0] = safe_close(pipefd[0]);
        r = pipefd[1];
        pipefd[1] = -1;

        *ret = pid;

        return r;
}
Esempio n. 16
0
static void uh_mainloop(struct config *conf, fd_set serv_fds, int max_fd)
{
	/* master file descriptor list */
	fd_set used_fds, read_fds;

	/* working structs */
	struct http_request *req;
	struct path_info *pin;
	struct client *cl;

	/* maximum file descriptor number */
	int new_fd, cur_fd = 0;

	/* clear the master and temp sets */
	FD_ZERO(&used_fds);
	FD_ZERO(&read_fds);

	/* backup server descriptor set */
	used_fds = serv_fds;

	/* loop */
	while(run)
	{
		/* create a working copy of the used fd set */
		read_fds = used_fds;

		/* sleep until socket activity */
		if( select(max_fd + 1, &read_fds, NULL, NULL, NULL) == -1 )
		{
			perror("select()");
			exit(1);
		}

		/* run through the existing connections looking for data to be read */
		for( cur_fd = 0; cur_fd <= max_fd; cur_fd++ )
		{
			/* is a socket managed by us */
			if( FD_ISSET(cur_fd, &read_fds) )
			{
				/* is one of our listen sockets */
				if( FD_ISSET(cur_fd, &serv_fds) )
				{
					/* handle new connections */
					if( (new_fd = accept(cur_fd, NULL, 0)) != -1 )
					{
						/* add to global client list */
						if( (cl = uh_client_add(new_fd, uh_listener_lookup(cur_fd))) != NULL )
						{
#ifdef HAVE_TLS
							/* setup client tls context */
							if( conf->tls )
							{
								if( conf->tls_accept(cl) < 1 )
								{
									fprintf(stderr,
										"tls_accept failed, "
										"connection dropped\n");

									/* close client socket */
									close(new_fd);

									/* remove from global client list */
									uh_client_remove(new_fd);

									continue;
								}
							}
#endif

							/* add client socket to global fdset */
							FD_SET(new_fd, &used_fds);
							fd_cloexec(new_fd);
							max_fd = max(max_fd, new_fd);
						}

						/* insufficient resources */
						else
						{
							fprintf(stderr,
								"uh_client_add(): Cannot allocate memory\n");

							close(new_fd);
						}
					}
				}

				/* is a client socket */
				else
				{
					if( ! (cl = uh_client_lookup(cur_fd)) )
					{
						/* this should not happen! */
						fprintf(stderr,
							"uh_client_lookup(): No entry for fd %i!\n",
							cur_fd);

						goto cleanup;
					}

					/* parse message header */
					if( (req = uh_http_header_recv(cl)) != NULL )
					{
						/* RFC1918 filtering required? */
						if( conf->rfc1918_filter &&
						    sa_rfc1918(&cl->peeraddr) &&
						    !sa_rfc1918(&cl->servaddr) )
						{
							uh_http_sendhf(cl, 403, "Forbidden",
								"Rejected request from RFC1918 IP "
								"to public server address");
						}
						else
#ifdef HAVE_LUA
						/* Lua request? */
						if( conf->lua_state &&
						    uh_path_match(conf->lua_prefix, req->url) )
						{
							conf->lua_request(cl, req, conf->lua_state);
						}
						else
#endif
						/* dispatch request */
						if( (pin = uh_path_lookup(cl, req->url)) != NULL )
						{
							/* auth ok? */
							if( !pin->redirected && uh_auth_check(cl, req, pin) )
								uh_dispatch_request(cl, req, pin);
						}

						/* 404 */
						else
						{
							/* Try to invoke an error handler */
							pin = uh_path_lookup(cl, conf->error_handler);

							if( pin && uh_auth_check(cl, req, pin) )
							{
								req->redirect_status = 404;
								uh_dispatch_request(cl, req, pin);
							}
							else
							{
								uh_http_sendhf(cl, 404, "Not Found",
									"No such file or directory");
							}
						}
					}

#ifdef HAVE_TLS
					/* free client tls context */
					if( conf->tls )
						conf->tls_close(cl);
#endif

					cleanup:

					/* close client socket */
					close(cur_fd);
					FD_CLR(cur_fd, &used_fds);

					/* remove from global client list */
					uh_client_remove(cur_fd);
				}
			}
		}
	}

#ifdef HAVE_LUA
	/* destroy the Lua state */
	if( conf->lua_state != NULL )
		conf->lua_close(conf->lua_state);
#endif
}
Esempio n. 17
0
File: dmon.c Progetto: aperezdc/dmon
int
dmon_main (int argc, char **argv)
{
    w_io_t *pidfile_io = NULL;
    char *opts_env = NULL;
    bool success;
    unsigned i, consumed;

    /* Check for "-C configfile" given in the command line. */
    if (argc > 2 && ((argv[1][0] == '-' &&
                      argv[1][1] == 'C' &&
                      argv[1][2] == '\0') ||
                     !strcmp ("--config", argv[1])))

    {
        w_lobj w_io_t *cfg_io = NULL;
        char *err_msg = NULL;

        if ((cfg_io = w_io_unix_open (argv[2], O_RDONLY, 0)) == NULL)
            w_die ("$s: Could not open file '$s', $E\n", argv[0], argv[2]);

        success = w_opt_parse_io (dmon_options, cfg_io, &err_msg);

        if (!success || err_msg)
            w_die ("$s: Error parsing '$s' at line $s\n", argv[0], argv[2], err_msg);

        replace_args_shift (2, &argc, &argv);
    }

    if ((opts_env = getenv ("DMON_OPTIONS")) != NULL)
        replace_args_string (opts_env, &argc, &argv);

    i = consumed = w_opt_parse (dmon_options, NULL, NULL,
                                "cmd [cmd-options] [ -- "
                                "log-cmd [log-cmd-options]]",
                                argc, argv);

    W_DEBUG ("w_opt_parse consumed $I arguments\n", consumed);

    if (workdir_path) {
        if (chdir (workdir_path) != 0)
            w_die ("$s: Cannot use '$s' as work directory, $E\n", argv[0], workdir_path);
    }

    if (status_path) {
        status_io = w_io_unix_open (status_path, O_WRONLY | O_CREAT | O_APPEND, 0666);
        if (!status_io)
            w_die ("$s: Cannot open '$s' for writing, $E\n", argv[0], status_path);
    }

    if (cmd_interval && success_exit)
        w_die ("$s: Options '-i' and '-1' cannot be used together.\n", argv[0]);

    if (load_enabled && almost_zerof (load_low))
        load_low = load_high / 2.0f;

    cmd_task.argv = argv + consumed;

    /* Skip over until "--" is found */
    while (i < (unsigned) argc && strcmp (argv[i], "--") != 0) {
        cmd_task.argc++;
        i++;
    }

    /* There is a log command */
    if (i < (unsigned) argc && strcmp (argv[i], "--") == 0) {
        log_task.argc = argc - cmd_task.argc - consumed - 1;
        log_task.argv = argv + argc - log_task.argc;
        log_task.argv[log_task.argc] = NULL;
    }

    cmd_task.argv[cmd_task.argc] = NULL;

    if (log_task.argc > 0) {
        if (pipe (log_fds) != 0) {
            w_die ("$s: Cannot create pipe: $E\n", argv[0]);
        }
        W_DEBUG ("pipe_read = $i, pipe_write = $i\n", log_fds[0], log_fds[1]);
        fd_cloexec (log_fds[0]);
        fd_cloexec (log_fds[1]);
    }

#ifdef _DEBUG_PRINT
    {
        char **xxargv = cmd_task.argv;
        w_io_format (w_stderr, "cmd:");
        while (*xxargv) w_io_format (w_stderr, " $s", *xxargv++);
        w_io_format (w_stderr, "\n");
        if (log_enabled) {
            char **xxargv = log_task.argv;
            w_io_format (w_stderr, "log:");
            while (*xxargv) w_io_format (w_stderr, " $c", *xxargv++);
            w_io_format (w_stderr, "\n");
        }
    }
#endif /* _DEBUG_PRINT */

    if (cmd_task.argc == 0)
        w_die ("$s: No command to run given.\n", argv[0]);

    if (pidfile_path) {
        pidfile_io = w_io_unix_open (pidfile_path,
                                     O_TRUNC | O_CREAT | O_WRONLY,
                                     0666);
        if (!pidfile_io) {
            w_die ("$s: cannot open '$s' for writing: $E\n",
                   argv[0], pidfile_path);
        }
    }

    if (!nodaemon)
        become_daemon ();

    /* We have a valid file descriptor: write PID */
    if (pidfile_io) {
        w_io_result_t r = w_io_format (pidfile_io,
                                       "$L\n",
                                       (unsigned long) getpid ());
        if (w_io_failed (r))
            W_WARN ("I/O error writing to PID file: $E\n");
        w_obj_unref (pidfile_io);
    }

    setup_signals ();
    alarm (cmd_timeout);

    cmd_task.write_fd = log_fds[1];
    log_task.read_fd  = log_fds[0];

    while (running) {
        W_DEBUG (">>> loop iteration\n");
        if (check_child) {
            int retcode = reap_and_check ();

            /*
             * Wait the specified timeout but DO NOT use safe_sleep(): here
             * we want an interruptible sleep-wait so reaction to signals is
             * quick, which we definitely want for SIGINT/SIGTERM.
             */
            if (cmd_interval && !success_exit && retcode == 0) {
                int retval;
                struct timespec ts;
                ts.tv_sec = cmd_interval;
                ts.tv_nsec = 0;

                do {
                    retval = nanosleep (&ts, &ts);
                    W_DEBUGC ("  nanosleep -> $i\n", retval);
                } while (retval == -1 && errno == EINTR && running);
            }

            /*
             * Either handling signals which interrupt the previous loop,
             * or reap_and_check() may request stopping on successful exit
             */
            if (!running) {
                task_action_queue (&cmd_task, A_NONE);
                break;
            }
        }

        task_action_dispatch_and_write_status ("cmd", &cmd_task);
        if (log_enabled)
            task_action_dispatch_and_write_status ("log", &log_task);

        if (load_enabled) {
            double load_cur;

            W_DEBUGC ("  checking load after sleeping 1s\n");
            interruptible_sleep (1);

            if (getloadavg (&load_cur, 1) == -1)
                W_WARN ("getloadavg() failed: $E\n");

            if (paused) {
                /* If the current load dropped below load_low -> resume */
                if (load_cur <= load_low) {
                    W_DEBUGC ("  resuming...\n");
                    task_signal (&cmd_task, SIGCONT);
                    write_status ("cmd resume $L\n", (unsigned long) cmd_task.pid);
                    paused = 0;
                }
            }
            else {
                /* If the load went above load_high -> pause */
                if (load_cur > load_high) {
                    W_DEBUGC ("  pausing...\n");
                    task_signal (&cmd_task, SIGSTOP);
                    write_status ("cmd pause $L\n", (unsigned long) cmd_task.pid);
                    paused = 1;
                }
            }
        }
        else {
            /* Wait for signals to arrive. */
            W_DEBUGC ("  waiting for signals to come...\n");
            pause ();
        }
    }

    W_DEBUG ("exiting gracefully...\n");

    if (cmd_task.pid != NO_PID) {
        write_status ("cmd stop $L\n", (unsigned long) cmd_task.pid);
        task_action (&cmd_task, A_STOP);
    }
    if (log_enabled && log_task.pid != NO_PID) {
        write_status ("log stop $L\n", (unsigned long) log_task.pid);
        task_action (&log_task, A_STOP);
    }

    if (status_io) {
        w_obj_unref (status_io);
        status_io = NULL;
    }

    exit (EXIT_SUCCESS);
}