Exemple #1
0
static void
set_sig_handlers()
{
    int r;
    struct sigaction sa;

    sa.sa_handler = SIG_IGN;
    sa.sa_flags = 0;
    r = sigemptyset(&sa.sa_mask);
    if (r == -1) twarn("sigemptyset()"), exit(111);

    r = sigaction(SIGPIPE, &sa, 0);
    if (r == -1) twarn("sigaction(SIGPIPE)"), exit(111);

    sa.sa_handler = enter_drain_mode;
    r = sigaction(SIGUSR1, &sa, 0);
    if (r == -1) twarn("sigaction(SIGUSR1)"), exit(111);

    sa.sa_handler = exit_cleanly;
    r = sigaction(SIGINT, &sa, 0);
    if (r == -1) twarn("sigaction(SIGINT)"), exit(111);

    sa.sa_handler = exit_cleanly;
    r = sigaction(SIGTERM, &sa, 0);
    if (r == -1) twarn("sigaction(SIGTERM)"), exit(111);
}
Exemple #2
0
/* This is a workaround for a mystifying workaround in libevent's epoll
 * implementation. The epoll_init() function creates an epoll fd with space to
 * handle RLIMIT_NOFILE - 1 fds, accompanied by the following puzzling comment:
 * "Solaris is somewhat retarded - it's important to drop backwards
 * compatibility when making changes. So, don't dare to put rl.rlim_cur here."
 * This is presumably to work around a bug in Solaris, but it has the
 * unfortunate side-effect of causing epoll_ctl() (and, therefore, event_add())
 * to fail for a valid fd if we have hit the limit of open fds. That makes it
 * hard to provide reasonable behavior in that situation. So, let's reduce the
 * real value of RLIMIT_NOFILE by one, after epoll_init() has run. */
static void
nudge_fd_limit()
{
    int r;
    struct rlimit rl;

    r = getrlimit(RLIMIT_NOFILE, &rl);
    if (r != 0) twarn("getrlimit(RLIMIT_NOFILE)"), exit(2);

    rl.rlim_cur--;

    r = setrlimit(RLIMIT_NOFILE, &rl);
    if (r != 0) twarn("setrlimit(RLIMIT_NOFILE)"), exit(2);
}
Exemple #3
0
static void
su(const char *user) {
    int r;
    struct passwd *pwent;

    errno = 0;
    pwent = getpwnam(user);
    if (errno) twarn("getpwnam(\"%s\")", user), exit(32);
    if (!pwent) twarnx("getpwnam(\"%s\"): no such user", user), exit(33);

    r = setgid(pwent->pw_gid);
    if (r == -1) twarn("setgid(%d \"%s\")", pwent->pw_gid, user), exit(34);

    r = setuid(pwent->pw_uid);
    if (r == -1) twarn("setuid(%d \"%s\")", pwent->pw_uid, user), exit(34);
}
Exemple #4
0
void
sockmain()
{
    int i, r, n = 1;
    int64 e, t = nanoseconds();
    struct kevent evs[n];

    for (;;) {
        r = kevent(kq, NULL, 0, evs, n, &ivalts);
        if (r == -1 && errno != EINTR) {
            twarn("kevent");
            exit(1);
        }

        // should tick?
        e = nanoseconds();
        if (e-t > ival) {
            tick(tickval, 0);
            t = e;
        }

        for (i=0; i<r; i++) {
            handle(evs[i].udata, evs[i].filter, evs[i].flags);
        }

    }
}
Exemple #5
0
static void
nullfd(int fd, int flags)
{
    int r;

    close(fd);
    r = open("/dev/null", flags);
    if (r != fd) twarn("open(\"/dev/null\")"), exit(1);
}
Exemple #6
0
int
main(int argc, char **argv)
{
    int r, l;
    struct event_base *ev_base;
    struct job binlog_jobs = {};

    progname = argv[0];
    opts(argc, argv);

    if (detach && binlog_dir) {
        if (binlog_dir[0] != '/') {
            warnx("The -b option requires an absolute path when used with -d.");
            usage("Path is not absolute", binlog_dir);
        }
    }

    job_init();
    prot_init();

    /* We want to make sure that only one beanstalkd tries to use the binlog
     * directory at a time. So acquire a lock now and never release it. */
    if (binlog_dir) {
        r = binlog_lock();
        if (!r) twarnx("failed to lock binlog dir %s", binlog_dir), exit(10);
    }

    r = make_server_socket(host_addr, port);
    if (r == -1) twarnx("make_server_socket()"), exit(111);
    l = r;

    if (user) su(user);
    ev_base = event_init();
    set_sig_handlers();
    nudge_fd_limit();

    r = listen(l, 1024);
    if (r == -1) twarn("listen()");
    accept_handler = (evh)h_accept;
    unbrake();

    binlog_jobs.prev = binlog_jobs.next = &binlog_jobs;
    binlog_init(&binlog_jobs);
    prot_replay_binlog(&binlog_jobs);

    if (detach) {
        daemonize();
        event_reinit(ev_base);
    }

    event_dispatch();
    twarnx("event_dispatch error");
    binlog_shutdown();
    return 0;
}
Exemple #7
0
// Opens f for writing, writes a header, and initializes
// f->free and f->resv.
// Sets f->iswopen if successful.
void
filewopen(File *f)
{
    int fd, r;
    int n;
    int ver = Walver;

    fd = open(f->path, O_WRONLY|O_CREAT, 0400);
    if (fd < 0) {
        twarn("open %s", f->path);
        return;
    }

    r = falloc(fd, f->w->filesize);
    if (r) {
        close(fd);
        errno = r;
        twarn("falloc %s", f->path);
        r = unlink(f->path);
        if (r) {
            twarn("unlink %s", f->path);
        }
        return;
    }

    n = write(fd, &ver, sizeof(int));
    if (n < sizeof(int)) {
        twarn("write %s", f->path);
        close(fd);
        return;
    }

    f->fd = fd;
    f->iswopen = 1;
    fileincref(f);
    f->free = f->w->filesize - n;
    f->resv = 0;
}
Exemple #8
0
void
sockinit(Handle f, void *x, int64 ns)
{
    tick = f;
    tickval = x;
    ival = ns;
    ivalts.tv_sec = ns / 1000000000;
    ivalts.tv_nsec = ns % 1000000000;
    kq = kqueue();
    if (kq == -1) {
        twarn("kqueue");
        exit(1);
    }
}
Exemple #9
0
static void
daemonize()
{
    int r;

    r = chdir("/");
    if (r) return twarn("chdir");

    nullfd(0, O_RDONLY);
    nullfd(1, O_WRONLY);
    nullfd(2, O_WRONLY);
    umask(0);
    dfork();
    setsid();
    dfork();
}
Exemple #10
0
static int
filewrite(File *f, job j, void *buf, int len)
{
    int r;

    r = write(f->fd, buf, len);
    if (r != len) {
        twarn("write");
        return 0;
    }

    f->w->resv -= r;
    f->resv -= r;
    j->walresv -= r;
    j->walused += r;
    f->w->alive += r;
    return 1;
}
Exemple #11
0
static int
readfull(File *f, void *c, int n, int *err, char *desc)
{
    int r;

    r = read(f->fd, c, n);
    if (r == -1) {
        twarn("read");
        warnpos(f, 0, "error reading %s", desc);
        *err = 1;
        return 0;
    }
    if (r != n) {
        warnpos(f, -r, "unexpected EOF reading %d bytes (got %d): %s", n, r, desc);
        *err = 1;
        return 0;
    }
    return r;
}
Exemple #12
0
int main()
{
	Vcodex_t	*tz, *uz;
	Vcodex_t	*huf, *rle, *mtf;
	Vcchar_t	*mt, *cmp, *tstr;
	Vcchar_t	store[2*sizeof(Mt)];
	ssize_t		nc, nu, n;
	Vcmethod_t	*Vctable;

	if(!(Vctable = vcgetmeth("table", 0)))
		terror("table plugin not found");

	if(!(huf = vcopen(0, Vchuffgroup, 0, 0, VC_ENCODE)) )
		terror("Can't open Vchuffgroup handle to compress");
	if(!(rle = vcopen(0, Vcrle, "0", huf, VC_ENCODE|VC_CLOSECODER)) )
		terror("Can't open Vcrle handle to compress");
	if(!(mtf = vcopen(0, Vcmtf, 0, rle, VC_ENCODE|VC_CLOSECODER)) )
		terror("Can't open Vcrle handle to compress");
	if(!(tz = vcopen(0, Vctable, 0, mtf, VC_ENCODE)) )
		terror("Vctable: could not open handle to transform");

	if((n = vcextract(tz, (Void_t**)(&tstr))) <= 0)
		terror("Cannot get encoding string");
	memcpy(store,tstr,n);

	if((nc = vcapply(tz, Mt, sizeof(Mt), &cmp)) <= 0 )
		terror("Vctable: fail transforming");
	twarn("Vctable: rawsz=%d cmpsz=%d\n", sizeof(Mt), nc);

	if(!(uz = vcrestore(store, n)) )
		terror("Vctable: could not recreate handle to decode");

	if((nu = vcapply(uz, cmp, nc, &mt)) != sizeof(Mt))
		terror("Vctable: fail untransforming");

	if(memcmp(mt, Mt, nu) != 0)
		terror("Vctable: results did not match");

	exit(0);
}
Exemple #13
0
// Readrec5 is like readrec, but it reads a record in "version 5"
// of the log format.
static int
readrec5(File *f, job l, int *err)
{
    int r, sz = 0;
    size_t namelen;
    Jobrec5 jr;
    job j;
    tube t;
    char tubename[MAX_TUBE_NAME_LEN];

    r = read(f->fd, &namelen, sizeof(namelen));
    if (r == -1) {
        twarn("read");
        warnpos(f, 0, "error");
        *err = 1;
        return 0;
    }
    if (r != sizeof(namelen)) {
        return 0;
    }
    sz += r;
    if (namelen >= MAX_TUBE_NAME_LEN) {
        warnpos(f, -r, "namelen %zu exceeds maximum of %d", namelen, MAX_TUBE_NAME_LEN - 1);
        *err = 1;
        return 0;
    }

    if (namelen) {
        r = readfull(f, tubename, namelen, err, "v5 tube name");
        if (!r) {
            return 0;
        }
        sz += r;
    }
    tubename[namelen] = '\0';

    r = readfull(f, &jr, Jobrec5size, err, "v5 job struct");
    if (!r) {
        return 0;
    }
    sz += r;

    // are we reading trailing zeroes?
    if (!jr.id) return 0;

    j = job_find(jr.id);
    if (!(j || namelen)) {
        // We read a short record without having seen a
        // full record for this job, so the full record
        // was in an eariler file that has been deleted.
        // Therefore the job itself has either been
        // deleted or migrated; either way, this record
        // should be ignored.
        return 1;
    }

    switch (jr.state) {
    case Reserved:
        jr.state = Ready;
    case Ready:
    case Buried:
    case Delayed:
        if (!j) {
            if (jr.body_size > job_data_size_limit) {
                warnpos(f, -r, "job %"PRIu64" is too big (%"PRId32" > %zu)",
                        jr.id,
                        jr.body_size,
                        job_data_size_limit);
                goto Error;
            }
            t = tube_find_or_make(tubename);
            j = make_job_with_id(jr.pri, jr.delay, jr.ttr, jr.body_size,
                                 t, jr.id);
            j->next = j->prev = j;
            j->r.created_at = jr.created_at;
        }
        j->r.id = jr.id;
        j->r.pri = jr.pri;
        j->r.delay = jr.delay * 1000; // us => ns
        j->r.ttr = jr.ttr * 1000; // us => ns
        j->r.body_size = jr.body_size;
        j->r.created_at = jr.created_at * 1000; // us => ns
        j->r.deadline_at = jr.deadline_at * 1000; // us => ns
        j->r.reserve_ct = jr.reserve_ct;
        j->r.timeout_ct = jr.timeout_ct;
        j->r.release_ct = jr.release_ct;
        j->r.bury_ct = jr.bury_ct;
        j->r.kick_ct = jr.kick_ct;
        j->r.state = jr.state;
        job_insert(l, j);

        // full record; read the job body
        if (namelen) {
            if (jr.body_size != j->r.body_size) {
                warnpos(f, -r, "job %"PRIu64" size changed", j->r.id);
                warnpos(f, -r, "was %"PRId32", now %"PRId32, j->r.body_size, jr.body_size);
                goto Error;
            }
            r = readfull(f, j->body, j->r.body_size, err, "v5 job body");
            if (!r) {
                goto Error;
            }
            sz += r;

            // since this is a full record, we can move
            // the file pointer and decref the old
            // file, if any
            filermjob(j->file, j);
            fileaddjob(f, j);
        }
        j->walused += sz;
        f->w->alive += sz;

        return 1;
    case Invalid:
        if (j) {
            job_remove(j);
            filermjob(j->file, j);
            job_free(j);
        }
        return 1;
    }

Error:
    *err = 1;
    if (j) {
        job_remove(j);
        filermjob(j->file, j);
        job_free(j);
    }
    return 0;
}
Exemple #14
0
tmain()
{
	int		i, rv;
	void		*status;
	char		*objs[N_THREAD];
	pthread_t	thread[N_THREAD];
	int		nthreads = N_THREAD;
	int		iterations = ITERATIONS;
	int		objsize = OBJSIZE;
	int		repetitions = REPETITIONS;
#ifdef VMALLOC
	Vmstat_t	vmst;
#endif

	tresource(-1, 0);

	while(argc > 1)
	{	if(argv[1][0] == '-' && argv[1][1] == 't')
			nthreads = atoi(argv[1]+2);
		else if(argv[1][0] == '-' && argv[1][1] == 'i')
			iterations = atoi(argv[1]+2);
		else if(argv[1][0] == '-' && argv[1][1] == 'r')
			repetitions = atoi(argv[1]+2);
		else if(argv[1][0] == '-' && argv[1][1] == 'z')
			objsize = atoi(argv[1]+2);
		argc--; argv++;
	}

	if(nthreads <= 0 || nthreads > N_THREAD)
		terror("nthreads=%d must be in 1..%d", nthreads, N_THREAD);
	if(repetitions < nthreads)
		repetitions = 0;

	tinfo("nthreads=%d iterations=%d objsize=%d repetitions=%d",
		nthreads, iterations, objsize, repetitions );

	for(i = 0; i < nthreads; ++i)
		if(!(objs[i] = (char*)malloc(objsize)) )
			terror("Can't allocate objs[%d]", i);

	for(i = 0; i < nthreads; ++i)
	{	Worker_t	*w = (Worker_t*)malloc(sizeof(Worker_t));
		w->object = objs[i];
		w->objsize = objsize;
		w->iterations = iterations;
		w->repetitions = repetitions/nthreads;
		if((rv = pthread_create(&thread[i], NULL, worker, (void*)w)) != 0)
			terror("Failed to create thread %d", i);
	}
	for(i = 0; i < nthreads; ++i)
		if((rv = pthread_join(thread[i], &status)) != 0)
			terror("Failed waiting for thread %d", i);

	tresource(0, 0);

#ifdef VMALLOC
	vmstat(0, &vmst);
	twarn(vmst.mesg);
#endif

	texit(0);
}
Exemple #15
0
int
make_server_socket(char *host, char *port)
{
    int fd = -1, flags, r;
    struct linger linger = {0, 0};
    struct addrinfo *airoot, *ai, hints;

    /* See if we got a listen fd from systemd. If so, all socket options etc
     * are already set, so we check that the fd is a TCP listen socket and
     * return. */
    r = sd_listen_fds(1);
    if (r < 0) {
        return twarn("sd_listen_fds"), -1;
    }
    if (r > 0) {
        if (r > 1) {
            twarnx("inherited more than one listen socket;"
                   " ignoring all but the first");
            r = 1;
        }
        fd = SD_LISTEN_FDS_START;
        r = sd_is_socket_inet(fd, 0, SOCK_STREAM, 1, 0);
        if (r < 0) {
            errno = -r;
            twarn("sd_is_socket_inet");
            return -1;
        }
        if (!r) {
            twarnx("inherited fd is not a TCP listen socket");
            return -1;
        }
        return fd;
    }

    memset(&hints, 0, sizeof(hints));
    hints.ai_family = PF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_PASSIVE;
    r = getaddrinfo(host, port, &hints, &airoot);
    if (r == -1)
      return twarn("getaddrinfo()"), -1;

    for(ai = airoot; ai; ai = ai->ai_next) {
      fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
      if (fd == -1) {
        twarn("socket()");
        continue;
      }

      flags = fcntl(fd, F_GETFL, 0);
      if (flags < 0) {
        twarn("getting flags");
        close(fd);
        continue;
      }

      r = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
      if (r == -1) {
        twarn("setting O_NONBLOCK");
        close(fd);
        continue;
      }

      flags = 1;
      setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &flags, sizeof flags);
      setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &flags, sizeof flags);
      setsockopt(fd, SOL_SOCKET, SO_LINGER,   &linger, sizeof linger);
      setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &flags, sizeof flags);

      if (verbose) {
          char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV], *h = host, *p = port;
          r = getnameinfo(ai->ai_addr, ai->ai_addrlen,
                  hbuf, sizeof hbuf,
                  pbuf, sizeof pbuf,
                  NI_NUMERICHOST|NI_NUMERICSERV);
          if (!r) {
              h = hbuf;
              p = pbuf;
          }
          if (ai->ai_family == AF_INET6) {
              printf("bind %d [%s]:%s\n", fd, h, p);
          } else {
              printf("bind %d %s:%s\n", fd, h, p);
          }
      }
      r = bind(fd, ai->ai_addr, ai->ai_addrlen);
      if (r == -1) {
        twarn("bind()");
        close(fd);
        continue;
      }

      r = listen(fd, 1024);
      if (r == -1) {
        twarn("listen()");
        close(fd);
        continue;
      }

      break;
    }

    freeaddrinfo(airoot);

    if(ai == NULL)
      fd = -1;

    return fd;
}
Exemple #16
0
MAIN()
{
  Sfio_t* fw;
  Sfio_t* fr;
  int fds[2];
  int lseek_errno;
  int rv;

  if(!(fw = sfopen(NIL(Sfio_t*), tstfile(0), "w")) )
    terror("Can't create temp file %s to write", tstfile(0));
  if(!(fr = sfopen(NIL(Sfio_t*), tstfile(0), "r")) )
    terror("Can't open temp file %s to read", tstfile(0));

  sfseek(fr, (Sfoff_t)0, SEEK_END);
  if(sfgetc(fr) >= 0 || !sfeof(fr))
    terror("Should have seen eof");

  errno = 0;
  if((rv = sfwrite(fr, "a", 1)) == 1)
    terror("sfwrite returns %d, expecting 1", rv);
  if(errno != EBADF)
    twarn("Wrong errno %d after sfwrite(%d), expecting %d",errno,rv,EBADF);

  /* on some system (eg, apple), lseek does not set errno for this case */
  errno = 0;
  lseek(sffileno(fw), (off_t)(-2), SEEK_SET);
  lseek_errno = errno;
  lseek(sffileno(fw), (off_t)0, SEEK_SET);
  errno = 0;

  if(sfseek(fw, (Sfoff_t)(-2), SEEK_SET) != (Sfoff_t)(-1) )
    terror("sfseek should have failed");
  if(errno != lseek_errno)
    twarn("Wrong errno %d after sfseek, expecting %d", errno, lseek_errno);

  errno = 0;
  if(sfseek(fw, (Sfoff_t)0, SEEK_SET|SEEK_CUR|SEEK_END) >= 0)
    terror("sfseek should not have succeeded");
  if(errno != EINVAL)
    twarn("Wrong errno %d after sfseek, expecting %d", errno, EINVAL);

  if(pipe(fds) < 0)
    terror("Can't create pipes");

  if(!(fw = sfnew(fw, NIL(Void_t*), (size_t)SF_UNBOUND, fds[1], SF_WRITE)) )
    terror("Can't create stream for pipe");

  errno = 0;
  if(sfseek(fw, (Sfoff_t)0, SEEK_SET) >= 0)
    terror("sfseek should have failed on a pipe");
  if(errno != ESPIPE)
    twarn("Wrong errno %d after sfseek, expecting %d", ESPIPE);

  close(sffileno(fw));
  errno = 0;
  if(sfseek(fw, (Sfoff_t)0, SEEK_END) >= 0)
    terror("sfseek should have failed on a closed file descriptor");
  if(errno != EBADF)
    twarn("Wrong errno %d after sfseek, expecting %d", EBADF);

  TSTEXIT(0);
}