Esempio n. 1
0
int
main (void)
{
    pid_t pid;

    save_parent = getpid ();

    /* Don't run forever.  */
    alarm (180);

    /* The parent and child should basically run forever without
       tripping on any debug event.  We want to check that GDB updates
       the parent and child running states correctly right after the
       fork.  */
    pid = fork ();
    if (pid > 0)
        return fork_parent ();
    else if (pid == 0)
        return fork_child ();
    else
    {
        perror ("fork");
        return 1;
    }
}
Esempio n. 2
0
int daemon(int nochdir, int noclose)
{
	int fd;

	if (fork_parent() == -1)
		return -1;

	if (setsid() == -1)
		return -1;

	if (!nochdir)
		chdir("/");

	if (!noclose)
	{
		struct STAT st;

		if ((fd = open_not_cancel(_PATH_DEVNULL, O_RDWR, 0)) != -1
			&& (__builtin_expect (FSTAT (fd, &st), 0) == 0))
		{
			if (__builtin_expect (S_ISCHR (st.st_mode), 1) != 0) {
				dup2(fd, STDIN_FILENO);
				dup2(fd, STDOUT_FILENO);
				dup2(fd, STDERR_FILENO);
				if (fd > 2)
					close(fd);
			} else {
				/* We must set an errno value since no
				   function call actually failed.  */
				close_not_cancel_no_status (fd);
				__set_errno (ENODEV);
				return -1;
			}
		} else {
			close_not_cancel_no_status (fd);
			return -1;
		}
	}
	return 0;
}
Esempio n. 3
0
int daemon( int nochdir, int noclose )
{
	int fd;

	if (fork_parent() == -1)
		return -1;

	if (setsid() == -1)
		return(-1);

	if (!nochdir)
		chdir("/");

	if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
		dup2(fd, STDIN_FILENO);
		dup2(fd, STDOUT_FILENO);
		dup2(fd, STDERR_FILENO);
		if (fd > 2)
			close(fd);
	}
	return(0);
}
Esempio n. 4
0
int main(int argc, char **argv)
{
  char *user, *group, *interface, *root, *port, *cmd;
  int niceinc;
  int nofork;
  int timeout;
  int instances;
  int queue;

  int reuse;
  int keepalive;
  int what;
  int value;
  int offset;
  int i, j;
  char c;
  int lfd;
  int nfd;
  struct sigaction sag;
  sigset_t sst;
  int status;
  int hang;
  int busy;
  int tos;
  int ttl;
  int sane;
  int just;
#ifdef USE_IDSA
  int exitcode;
  int killcode;
  int flags;
  unsigned int arisk, crisk, irisk, risk;
#endif

  double limit_load = 0.0;

  port = NULL;
  user = NULL;
  group = NULL;
  root = NULL;
  interface = NULL;
  cmd = NULL;

  just = 0;
  sane = 1;
  reuse = 1;
  keepalive = 1;
  niceinc = 0;
  nofork = 0;
  timeout = 0;
  instances = 0;
  queue = 5;
  tos = 0;
  ttl = 0;
  offset = 0;

#ifdef USE_IDSA
  flags = 0;
  arisk = idsa_risk_make(-0.3,0.8);
  crisk = IDSA_R_UNKNOWN;
  irisk = IDSA_R_PARTIAL;
#endif

  i = j = 1;
  while (i < argc) {
    if (argv[i][0] == '-') {
      c = argv[i][j];
      switch (c) {
      case 'c':
	printf("(c) 2002,2007 Marc Welz: Distributed under the terms of the GNU General Public License\n");
	exit(0);
	break;
      case 'h':		/* print brief help message */
      case '?':
	usage(argv[0]);
	exit(0);
	break;
      case 'v':
#ifdef USE_IDSA
	printf("linetd %s-i\n", VERSION);
#else
	printf("linetd %s\n", VERSION);
#endif
	exit(0);
	break;

	/* flags */
      case 'f':		/* keep in foreground */
	nofork = 1;
	j++;
	break;
      case 'a' :        /* disable reuse of address */
        j++;
	c = argv[i][j];
	switch (c) {
        case 'r':
          reuse = 0;
          break;
	case 'k':
          keepalive = 0;
          break;
	case '\0':
	  fatal_failure(LINET_USAGE, 0, "option -a requires a modifier");
	  break;
	default:
	  fatal_failure(LINET_USAGE, 0, "unknown modifier -a%c", c);
	  break;
        }

	j++;
	if (argv[i][j] == '\0') {
	  j = 1;
	  i++;
	}

        break;
      case 'd' :        /* disable sanity checks */
        sane = 0;
	j++;
        break;

	/* strings */
      case 'u':
      case 'g':
      case 'p':
      case 'r':
      case 'b':
	j++;
	if (argv[i][j] == '\0') {
	  j = 0;
	  i++;
	}
	if (i >= argc) {
	  fatal_failure(LINET_USAGE, 0, "option -%c requires a parameter", c);
	}
	switch (c) {
	case 'u':
	  user = argv[i] + j;
	  break;
	case 'g':
	  group = argv[i] + j;
	  break;
	case 'p':        
	  port = argv[i] + j;
	  break;
	case 'r':
	  root = argv[i] + j;
	  break;
	case 'b':
	  interface = argv[i] + j;
	  break;
	}
	i++;
	j = 1;
	break;

      case 'l':
	j++;
	if (argv[i][j] == '\0') {
	  j = 0;
	  i++;
	}
	if (i >= argc) {
	  fatal_failure(LINET_USAGE, 0, "option -%c requires a parameter", c);
	}
	if (!isdigit(argv[i][j])) {
	  fatal_failure(LINET_USAGE, 0, "option -%c requires a floating point value", c);
	}
        load_fd = open(LOADAVG, O_RDONLY);
        if(load_fd < 0){
          fatal_failure(LINET_SYSTEM, errno, "unable to open %s to read load average", LOADAVG);
        }
	limit_load = atof(argv[i] + j);
	i++;
	j = 1;
	break;

      case 'n':
      case 'm':
      case 'i':
      case 'j':
      case 'q':
      case 't':
	j++;
	if (argv[i][j] == '\0') {
	  j = 0;
	  i++;
	}
	if (i >= argc) {
	  fatal_failure(LINET_USAGE, 0, "option -%c requires a parameter", c);
	}
	if (!isdigit(argv[i][j])) {
	  fatal_failure(LINET_USAGE, 0, "option -%c requires a numeric value", c);
	}
	value = atoi(argv[i] + j);
	switch (c) {
	case 'n':
	  niceinc = value;
	  break;
	case 'm':
	  timeout = value;
	  break;
	case 'i':
	  instances = value;
	  break;
	case 'j':
	  just = value;
	  break;
	case 'q':
	  queue = value;
	  break;
	case 't':
	  ttl = value;
	  break;
	}
	i++;
	j = 1;
	break;

      case 'o':
        j++;
	c = argv[i][j];
	switch (c) {
        case 'c':
          tos = IPTOS_LOWCOST;
          break;
	case 'd':
          tos = IPTOS_LOWDELAY;
          break;
	case 'r':
          tos = IPTOS_RELIABILITY;
          break;
	case 't':
          tos = IPTOS_THROUGHPUT;
          break;

	case '\0':
	  fatal_failure(LINET_USAGE, 0, "option -o requires a modifier");
	  break;
	default:
	  fatal_failure(LINET_USAGE, 0, "unknown modifier -o%c", c);
	  break;
        }

	j++;
	if (argv[i][j] == '\0') {
	  j = 1;
	  i++;
	}

        break;

#ifdef USE_IDSA
      case 'k' : /* risk ratings */
	j++;
	c = argv[i][j];
	j++;
	if (argv[i][j] == '\0') {
	  j = 0;
	  i++;
	}

	if (i >= argc) {
	  fatal_failure(LINET_USAGE, 0, "option -k%c requires a parameter", c);
	}

        risk = idsa_risk_parse(argv[i]+j);

	switch (c) {
	case 'a':
          arisk = risk;
          break;
	case 'c':
          crisk = risk;
          break;
	case 'i':
          irisk = risk;
          break;
        }
	i++;
	j = 1;
        break;

      case 'x':
        j++;
	c = argv[i][j];
	switch (c) {
        case 'e':
	  flags |= IDSA_F_ENV; /* honour IDSA_SOCKET */
          break;
	case 'o':
	  flags |= IDSA_F_FAILOPEN; /* continue on failure */
          break;
	case 'u':
	  flags |= IDSA_F_UPLOAD; /* allow uploading of rules */
          break;
	case '\0':
	  fatal_failure(LINET_USAGE, 0, "option -x requires a modifier");
	  break;
	default:
	  fatal_failure(LINET_USAGE, 0, "unknown modifier -x%c", c);
	  break;
        }
	j++;
	if (argv[i][j] == '\0') {
	  j = 1;
	  i++;
	}
        break;
#endif

      case 's':
	j++;
	c = argv[i][j];
	what = 0;
	switch (c) {
	case 'c':
	  what = RLIMIT_CORE;
	  break;
	case 'd':
	  what = RLIMIT_DATA;
	  break;
	case 'f':
	  what = RLIMIT_FSIZE;
	  break;
	case 'l':
	  what = RLIMIT_MEMLOCK;
	  break;
	case 'm':
	  what = RLIMIT_RSS;
	  break;
	case 'n':
	  what = RLIMIT_NOFILE;
	  break;
	case 's':
	  what = RLIMIT_STACK;
	  break;
	case 't':
	  what = RLIMIT_CPU;
	  break;
	case 'u':
	  what = RLIMIT_NPROC;
	  break;
	case 'v':
	  what = RLIMIT_AS;
	  break;

	case '\0':
	  fatal_failure(LINET_USAGE, 0, "option -s requires a modifier");
	  break;
	default:
	  fatal_failure(LINET_USAGE, 0, "unknown modifier -s%c", c);
	  break;
	}

	j++;
	if (argv[i][j] == '\0') {
	  j = 0;
	  i++;
	}

	if (i >= argc) {
	  fatal_failure(LINET_USAGE, 0, "option -s%c requires a parameter", c);
	}
	if (!isdigit(argv[i][j])) {
	  fatal_failure(LINET_USAGE, 0, "option -s%c requires a numeric value", c);
	}
	value = atoi(argv[i] + j);

        if(resource_count >= LINET_MAXRES){
	  fatal_failure(LINET_USAGE, 0, "too many resource restrictions", c);
        }

        resource_table[resource_count][0] = what;
        resource_table[resource_count][1] = value;
        resource_count++;

	i++;
	j = 1;
	break;

      case '-':
	j++;
	break;
      case '\0':
	j = 1;
	i++;
	break;
      default:
	fatal_failure(LINET_USAGE, 0, "unknown option -%c", argv[i][j]);
	break;
      }
    } else {
      cmd = argv[i];
      offset = i + 1;

      if (sane) {
        if (i + 1 >= argc){
          fprintf(stderr, "%s: warning: zeroth argument should be specified\n", argv[0]);
          offset = i;
        }
      }

      i = argc;
    }
  }

  if (cmd == NULL) {
    fatal_failure(LINET_USAGE, 0, "require a command to run");
  }

  if (!nofork) {
    fork_parent(argv[0]);
  }
#ifdef USE_IDSA
  if (ic == NULL) {
    ic = idsa_open(LINETD, NULL, flags);
  }
  if (ic == NULL) {
    fprintf(stderr, "%s: unable to open idsa connection\n", argv[0]);
    exit(EX_UNAVAILABLE);
  }
#endif

  sigfillset(&(sag.sa_mask));
  sag.sa_flags = 0;

  sag.sa_handler = handle_child;
  if (sigaction(SIGCHLD, &sag, NULL)) {
    fatal_failure(LINET_SYSTEM, errno, "unable to set signal handler");
  }

  sag.sa_handler = handle_stop;
  if (sigaction(SIGTERM, &sag, NULL)) {
    fatal_failure(LINET_SYSTEM, errno, "unable to set signal handler");
  }

  lfd = setup_listener(argv[0], port, interface, queue, ttl, tos, reuse, keepalive);

  drop_root(argv[0], user, group, root);

  if(sane){
    if(access(cmd, X_OK)){
      fatal_failure(LINET_SYSTEM, errno, "\"%s\" %s", cmd, (cmd[0] == '/') ? "appears unavailable" : "might need an absolute path");
    }
  }

  if (niceinc) {
    nice(niceinc);
  }

#ifdef USE_IDSA
  if(idsa_set(ic, LINET_DR, LINET_SCHEME, 1, IDSA_R_SUCCESS, IDSA_R_UNKNOWN, IDSA_R_UNKNOWN, 
        IDSA_SSM,  IDSA_T_STRING, IDSA_SSM_SSTART, 
        "version", IDSA_T_STRING, VERSION, 
        NULL) != IDSA_L_ALLOW){
    fprintf(stderr, "%s: start disallowed\n", LINETD);
    return EX_NOPERM;
  }
#endif

  if (!nofork) {
    close(STDERR_FILENO);
  }

  sigemptyset(&sst);
  sigaddset(&sst, SIGCHLD);
  sigaddset(&sst, SIGTERM);

  sigprocmask(SIG_BLOCK, &sst, NULL);	/* disable child signal for everything execpt accept and sleep */

  while (run) {
#ifdef USE_IDSA
    nfd = accept_connection(lfd, arisk, crisk, irisk);
#else
    nfd = accept_connection(lfd);
#endif
    if (nfd >= 0) {
      run_command(lfd, cmd, &argv[offset], nfd, timeout);
      if(just){
        just--;
        if(just == 0){
          run = 0;
        }
      }
    }

    do{ /* check children and load */
      busy = 0;
      hang = ((instances > 0) && (child_count >= instances)); /* actually wait for child */

      if (zombies || hang) {
        if (waitpid(WAIT_ANY, &status, hang ? 0 : WNOHANG) > 0) {	/* collect pids without risk of EINTR */
#ifdef USE_IDSA

          /* in theory this could parse signals and exit codes. Eg SIG{SEGV,BUS} == ES_INTERNAL etc */

          if (WIFEXITED(status)) {
            exitcode = WEXITSTATUS(status);
            if (exitcode == 0) {
              idsa_set(ic, LINET_JD, LINET_SCHEME, 0, IDSA_R_NONE, IDSA_R_UNKNOWN, IDSA_R_UNKNOWN, 
                  IDSA_SSM, IDSA_T_STRING, IDSA_SSM_WSTOP, 
                  NULL);
            } else {
              idsa_set(ic, LINET_JE, LINET_SCHEME, 0, IDSA_R_PARTIAL, IDSA_R_UNKNOWN, IDSA_R_PARTIAL, 
                  IDSA_SSM, IDSA_T_STRING, IDSA_SSM_WFAIL, 
                  IDSA_ES,  IDSA_T_STRING, IDSA_ES_OTHER, 
                  "exit",   IDSA_T_INT, &exitcode, 
                  NULL);
            }
          } else if (WIFSIGNALED(status)) {
            killcode = WTERMSIG(status);
            idsa_set(ic, LINET_JS, LINET_SCHEME, 0, IDSA_R_PARTIAL, IDSA_R_UNKNOWN, IDSA_R_PARTIAL,
                IDSA_SSM, IDSA_T_STRING, IDSA_SSM_WFAIL, 
                IDSA_ES,  IDSA_T_STRING, IDSA_ES_OTHER, 
                "signal", IDSA_T_INT, &killcode,
                NULL);
          }
#endif
          child_count--;
          busy = ! hang; 
        } else { /* nothing more to collect */
          zombies = 0;
        }
      }

      if((load_fd >= 0) && (zombies == 0)){ /* if zombies then loop will run again, defer load check */
        if(get_load() > limit_load){ /* go to sleep if overloaded */
          sigprocmask(SIG_UNBLOCK, &sst, NULL);	/* enable child|term signal */
          sleep(LINET_SLEEP);
          sigprocmask(SIG_BLOCK, &sst, NULL);	/* disable child|term signal */
          busy = run;
        }
      }
    } while (busy); /* end of child and delay loop */
  } /* end of main loop */

  if(lfd >= 0){
    close(lfd);
  }
  if(load_fd >= 0){
    close(load_fd);
  }

#ifdef USE_IDSA
  idsa_set(ic, LINET_DE, LINET_SCHEME, 0, IDSA_R_TOTAL, IDSA_R_NONE, IDSA_R_UNKNOWN, 
      IDSA_SSM,  IDSA_T_STRING, IDSA_SSM_SSTOP, 
      "version", IDSA_T_STRING, VERSION, 
      NULL);
  idsa_close(ic);
#endif

  return 0;
}
Esempio n. 5
0
int main(int argc, char **argv)
{
#define BUFFER 64
  char buffer[BUFFER];
  char *level, *app, *server, *output;
  int run, fd, i, j, c, verbose, attempts, detach, result, truncate, flags;
  struct katcl_parse *p;
  struct katcl_line *ls, *lo;
  struct sigaction sa;
  time_t now;
  struct tm *local;

  i = j = 1;
  app = argv[0];

  verbose = 0;
  attempts = 2;
  detach = 0;
  truncate = 0;

  server = getenv("KATCP_SERVER");
  if(server == NULL){
    server = "localhost";
  }

  output = NULL;
  level = NULL;

  flags = 0; /* placate -Wall */

  while (i < argc) {
    if (argv[i][0] == '-') {
      c = argv[i][j];
      switch (c) {

        case 'h' :
          usage(app);
          return EX_OK;

        case 'v' : 
          verbose++;
          j++;
          break;

        case 'd' : 
          detach = 1;
          j++;
          break;

        case 'f' : 
          detach = 0;
          j++;
          break;

        case 't' : 
          truncate = 1;
          j++;
          break;

        case 'q' : 
          verbose = 0;
          j++;
          break;

        case 'l' :
        case 'o' :
        case 'a' :
        case 's' :

          j++;
          if (argv[i][j] == '\0') {
            j = 0;
            i++;
          }
          if (i >= argc) {
            fprintf(stderr, "%s: usage: argument needs a parameter\n", app);
            return EX_USAGE;
          }

          switch(c){
            case 'l' :
              level = argv[i] + j;
              break;
            case 'o' :
              output = argv[i] + j;
              break;
            case 'a' : 
              attempts = atoi(argv[i] + j);
              break;
            case 's' : 
              server = argv[i] + j;
              break;
          }

          i++;
          j = 1;
          break;

        case '-' :
          j++;
          break;
        case '\0':
          j = 1;
          i++;
          break;
        default:
          fprintf(stderr, "%s: usage: unknown option -%c\n", app, argv[i][j]);
          return EX_USAGE;
      }
    } else {
      if(output){
        fprintf(stderr, "%s: usage: unexpected extra argument %s (can only save to one file)\n", app, argv[i]);
        return EX_USAGE;
      } 
      output = argv[i];
      i++;
    }
  }

  if(detach){
    if(fork_parent() < 0){
      fprintf(stderr, "%s: unable to detach process\n", app);
      return EX_OSERR;
    }
  }

  sa.sa_handler = handle_signal;
#if 0
  sa.sa_flags = SA_RESTART;
#endif
  sa.sa_flags = 0;
  sigemptyset(&(sa.sa_mask));

  sigaction(SIGHUP, &sa, NULL);
  sigaction(SIGUSR1, &sa, NULL);
  sigaction(SIGUSR2, &sa, NULL);

  if(server == NULL){
    server = "localhost:7147";
  }

  if(level){
    log_changed = 1;
    log_level = log_to_code_katcl(level);
    if(log_level < 0){
      fprintf(stderr, "%s: usage: invalid initial log priority %s\n", app, level);
      return EX_USAGE;
    } 
  }

  if(output == NULL){
    if(detach == 1){
      fprintf(stderr, "%s: usage: need a filename as target\n", app);
      return EX_USAGE;
    }
    fd = STDOUT_FILENO;
  } else {
    flags = O_CREAT | O_WRONLY;
    if(truncate == 0){
      flags |= O_APPEND;
    }
    fd = open(output, flags, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
    if(fd < 0){
      fprintf(stderr, "%s: unable to open file %s: %s\n", app, output, strerror(errno));
      return EX_OSERR;
    }
  }

  lo = create_katcl(fd);
  if(lo == NULL){
    fprintf(stderr, "%s: unable to allocate log state\n", app);
    return EX_OSERR;
  }


  /**********************/

  while((attempts-- > 0) && ((fd = net_connect(server, 0, 0)) < 0)){
    sleep(1);
  }

  if(attempts <= 0){
    sync_message_katcl(lo, KATCP_LEVEL_FATAL, NAME, "unable to connect to %s", server);
    return EX_UNAVAILABLE;
  }

  ls = create_katcl(fd);
  if(ls == NULL){
    sync_message_katcl(lo, KATCP_LEVEL_FATAL, NAME, "unable to allocate parser state");
    return EX_OSERR;
  }

  if(detach){
    fclose(stderr);
  }

  time(&now);
  local = localtime(&now);
  strftime(buffer, BUFFER - 1, "%Y-%m-%dT%H:%M:%S", local);

  sync_message_katcl(lo, KATCP_LEVEL_INFO, NAME, "monitor start for %s at %s", server, buffer);

  for(run = 1; run > 0;){

    if(log_reload > 0){
      if(output){
        fd = open(output, flags, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
        if(fd >= 0){
          exchange_katcl(lo, fd);
        }
      }

      log_reload = 0;
    }
 
    /* WARNING: will only run after the next message - may have to interrupt syscall to get past this */
    if(log_changed > 0){

      level = log_to_string_katcl(log_level);
      if(level){

        p = create_parse_katcl();
        if(p){

          add_string_parse_katcl(p, KATCP_FLAG_STRING | KATCP_FLAG_FIRST, "?log-level");
          add_string_parse_katcl(p, KATCP_FLAG_STRING | KATCP_FLAG_LAST, level);

          append_parse_katcl(lo, p);

          /* dodgy refcount dealings: p is created with refcount = 0, so can only do write at end, otherwise may end up being deallocated */

          append_parse_katcl(ls, p);
          write_katcl(ls);

        }
      } else {
        sync_message_katcl(lo, KATCP_LEVEL_ERROR, NAME, "invalid log priority number %d", level);
      }

      log_changed = 0;
    }

    result = read_katcl(ls);
    if(result < 0){
      sync_message_katcl(lo, KATCP_LEVEL_FATAL, NAME, "read from network failed: %s", strerror(errno));
      return EX_OSERR;
    }

    if(result == 1){
      run = 0;
    }

    while(have_katcl(ls)){
      p = ready_katcl(ls);
      if(p){
        append_parse_katcl(lo, p);
      }
    }

    write_katcl(lo);
  }

  return EX_OK;
#undef BUFFER
}