コード例 #1
0
ファイル: courier.c プロジェクト: gosht9/courier
int main(int argc, char **argv)
{
    if (argc > 1 && strcmp(argv[1], "--version") == 0)
    {
        printf("%s\n", COURIER_COPYRIGHT);
        exit(0);
    }

    if (chdir(courierdir()))
    {
        perror("chdir");
        return (1);
    }
    if (argc < 2)	return (0);

    if (strcmp(argv[1], "stop") == 0)
    {
        int	fd;

        trigger(TRIGGER_STOP);

        /* Wait until the exclusive lock goes away: */

        signal(SIGHUP, SIG_DFL);
        if ((fd=open(TMPDIR "/courierd.lock", O_RDWR|O_CREAT, 0600))
                < 0)	clog_msg_errno();

        alarm(15);	/* But abort after 15 seconds. */

        ll_lock_ex(fd);
        return (0);
    }

    if (strcmp(argv[1], "restart") == 0)
    {
        trigger(TRIGGER_RESTART);
        return (0);
    }

    if (strcmp(argv[1], "flush") == 0)
    {
        ino_t	n;
        struct	ctlfile	ctf;

        if (getuid())
        {
            /*
            ** We'll fail trying to open the pipe anyway, but let's
            ** give a meaningful error message now.
            */
            fprintf(stderr,
                    "courier flush can be executed only by the superuser.\n");
            exit(1);
        }

        if (argc < 3)
        {
            trigger(TRIGGER_FLUSH);	/* Everything */
            exit(0);
        }

        if (comparseqid(argv[2], &n) == 0 &&
                ctlfile_openi(n, &ctf, 1) == 0)
        {
            int c=ctlfile_searchfirst(&ctf, COMCTLFILE_MSGID);

            if (c >= 0 && strcmp(ctf.lines[c]+1, argv[2]) == 0)
            {
                char	*s=courier_malloc(sizeof(TRIGGER_FLUSHMSG)+1+
                                          strlen(argv[2]));

                strcat(strcat(strcpy(s, TRIGGER_FLUSHMSG),
                              argv[2]), "\n");
                trigger(s);
                ctlfile_close(&ctf);
                return (0);
            }
            ctlfile_close(&ctf);
        }
        fprintf(stderr, "No such message.\n");
        exit(1);
        return (1);
    }

    /* Might as well... */

    if (strcmp(argv[1], "start") == 0)
    {
        pid_t	p;
        int	waitstat;
        char	dummy;

        /*
        ** Ok, courierd will close file descriptor 3 when it starts, so we
        ** put a pipe on there, and wait for it to close.
        */
        int	pipefd[2];

        close(3);
        if (open("/dev/null", O_RDONLY) != 3 || pipe(pipefd))
        {
            fprintf(stderr, "Cannot open pipe\n");
            exit(1);
        }

        if (getuid())
        {
            /*
            ** We'll fail trying to execute courierd anyway, but let's
            ** give a meaningful error message now.
            */
            fprintf(stderr, "courier start can be executed only by the superuser.\n");
            return (1);
        }
        signal(SIGCHLD, SIG_DFL);
        while ((p=fork()) == -1)
        {
            perror("fork");
            sleep(10);
        }
        if (p == 0)
        {
            dup2(pipefd[1], 3);
            close(pipefd[1]);
            close(pipefd[0]);
            while ((p=fork()) == -1)
            {
                perror("fork");
                sleep(10);
            }
            if (p == 0)
            {
                /*
                ** stdin from the bitbucket.  stdout to
                ** /dev/null, or the bitbucket.
                */

                signal(SIGHUP, SIG_IGN);
                close(0);
                open("/dev/null", O_RDWR);
                dup2(0, 1);
                dup2(0, 2);
                /* See if we can disconnect from the terminal */

#ifdef	TIOCNOTTY
                {
                    int fd=open("/dev/tty", O_RDWR);

                    if (fd >= 0)
                    {
                        ioctl(fd, TIOCNOTTY, 0);
                        close(fd);
                    }
                }
#endif
                /* Remove any process groups */

#if	HAVE_SETPGRP
#if	SETPGRP_VOID
                setpgrp();
#else
                setpgrp(0, 0);
#endif
#endif
                execl( DATADIR "/courierctl.start",
                       "courierctl.start", (char *)0);
                perror("exec");
                _exit(1);
            }
            _exit(0);
        }
        close(pipefd[1]);
        while (wait(&waitstat) != p)
            ;
        if (read(pipefd[0], &dummy, 1) < 0)
            ; /* ignore */
        close(pipefd[0]);
        close(3);
        return (0);
    }

    if (strcmp(argv[1], "clear") == 0 && argc > 2)
    {
        libmail_changeuidgid(MAILUID, MAILGID);

        if (strcmp(argv[2], "all") == 0)
        {
            courier_clear_all();
        }
        else
        {
            track_save(argv[2], TRACK_ADDRACCEPTED);
            printf("%s cleared.\n", argv[2]);
        }
        return (0);
    }

    if (argc > 2 && strcmp(argv[1], "show") == 0 &&
            strcmp(argv[2], "all") == 0)
    {
        libmail_changeuidgid(MAILUID, MAILGID);
        courier_show_all();
    }

    return (0);
}
コード例 #2
0
ファイル: commsgcancel.c プロジェクト: svarshavchik/courier
int msgcancel(const char *qid, const char **reason, int nreason,
	int chkuid)
{
ino_t	n;
struct	ctlfile ctf;
struct	stat	stat_buf;
uid_t	u=getuid();
int	c, d;
struct	iovec *iova;
static const char default_cancel_msg[]="Message cancelled.";
static const char *default_cancel_msgp[1]= { default_cancel_msg };

static const char x=COMCTLFILE_CANCEL_MSG;
char	*s;

	if (comparseqid(qid, &n))	return (-1);
        if (ctlfile_openi(n, &ctf, 0))	return (-1);
	if (fstat(ctf.fd, &stat_buf) || (chkuid && u && u != stat_buf.st_uid) ||
		ctf.cancelled)
	{
		ctlfile_close(&ctf);
		return (-1);
	}
	c=ctlfile_searchfirst(&ctf, COMCTLFILE_MSGID);
	if (c < 0 || strcmp(ctf.lines[c]+1, qid))
	{
		ctlfile_close(&ctf);
		return (-1);
	}

	if ((iova=(struct iovec *)malloc(sizeof(struct iovec) * 3 *
		(nreason == 0 ? 1:nreason))) == 0)
	{
		perror("enomem");
		exit(1);
	}

	if (nreason == 0)
	{
		reason=default_cancel_msgp;
		nreason=1;
	}

	c=0;
	while (nreason)
	{
		iova[c].iov_base=(caddr_t)&x;
		iova[c].iov_len=1;
		c++;
		iova[c].iov_base=(caddr_t) *reason;
		iova[c].iov_len=strlen( *reason );
		c++;
		iova[c].iov_base=(caddr_t)"\n";
		iova[c].iov_len=1;
		c++;
		++reason;
		--nreason;
	}

	s=malloc(sizeof(TRIGGER_FLUSHMSG)+strlen(qid)+3);
	if (!s)
	{
		perror("malloc");
		exit(1);
	}
	strcat(strcat(strcpy(s, TRIGGER_FLUSHMSG " "), qid), "\n");

	d=writev(ctf.fd, iova, c);
	ctlfile_close(&ctf);
	while (c)
	{
		--c;
		if (iova[c].iov_len > d)
		{
			perror("writev");
			free(iova);
			free(s);
			return (0);
		}
		d -= iova[c].iov_len;
	}
	free(iova);
	trigger(s);
	free(s);
	return (0);
}
コード例 #3
0
ファイル: courierd.C プロジェクト: svarshavchik/courier
int courierbmain()
{
    fd_set	fds, fdc;
    struct	mybuf trigger_buf;

    clog_open_syslog("courierd");
    rw_init_verbose(1);
    if (rw_init_courier(0))	return (1);
    drvinfo::init();

    libmail_changeuidgid(MAILUID, MAILGID);
    signal(SIGPIPE, SIG_IGN);

    respawnlo=config_time_respawnlo();
    respawnhi=config_time_respawnhi();

    retryalpha=config_time_retryalpha();
    retrybeta=config_retrybeta();
    retrygamma=config_time_retrygamma();
    retrymaxdelta=config_retrymaxdelta();
    flushtime=0;
    delaytime=config_time_submitdelay();

    queuefill=config_time_queuefill();
    nextqueuefill=0;

    purgedir(MSGQDIR);
    purgedir(MSGSDIR);
    rmdir(MSGQDIR);
    mkdir(MSGQDIR, 0755);
    trackpurge();

    if ((triggerw=open(triggername, O_WRONLY, 0)) < 0 ||
            (triggerr=open(triggername, O_RDONLY, 0)) < 0)
        clog_msg_errno();

    time(&start_time);

    courierbstart=start_time;

    msgq::init(queuehi);

    shutdown_flag=0;
    FD_ZERO(&fds);

    unsigned nd;
    int	maxfd=triggerr;

    FD_SET(maxfd, &fds);
    mybuf_init(&trigger_buf, triggerr);

    for (nd=0; nd<drvinfo::nmodules; nd++)
    {
        int	fd=drvinfo::modules[nd].module_from.fd;

        if (fd > maxfd)	maxfd=fd;
        FD_SET(fd, &fds);
    }

    ++maxfd;

    time_t	current_time, next_time, shutdown_time;

    current_time=start_time;

    shutdown_time=0;

    msgq::queuescan();	// Initial queue scan

    int	doscantmp=1;

////////////////////////////////////////////////////////////////////////////
//
// Main loop:
//
// A) Scan tmp for new messages.
//
// B) Schedule messages for delivery, when their time comes.
//
// C) Update statistics.
//
// D) Stop scheduling messages when restart signal received.
//
// E) Restart if there's no activity for 5 mins after we've been running
//    for respawnlo amount of times.
//
// F) When we've been running for respawnhi amount of time, stop scheduling
//    messages, restart when all deliveries have been completed.
//
// G) Receive delivery completion messages from modules.
//
////////////////////////////////////////////////////////////////////////////
    for (;;)
    {
        msgq	*mp;

        if (shutdown_flag)
            doscantmp=0;

        if (doscantmp)
            doscantmp=msgq::tmpscan();

        if (shutdown_flag && msgq::inprogress == 0)
            break;

        if (current_time >= start_time + respawnhi && !shutdown_flag)
        {
            clog_msg_start_info();
            clog_msg_str("SHUTDOWN: respawnhi limit reached.");
            clog_msg_send();
            shutdown_flag=1;
            continue;
        }

        if (diskspacelow() && msgq::queuehead &&
                msgq::queuehead->nextsenddel <= current_time)
        {
            clog_msg_start_err();
            clog_msg_str("Low on disk space.");
            clog_msg_send();
            for (mp=msgq::queuehead; mp &&
                    mp->nextsenddel <= current_time + 300;
                    mp=mp->next)
                mp->nextsenddel=current_time+300;
        }

        if (!shutdown_flag)
        {
            while ((mp=msgq::queuehead) != 0 &&
                    mp->nextsenddel <= current_time)
            {
                mp->removewq();
                mp->start_message();
            }
        }

        if (nextqueuefill && nextqueuefill <= current_time)
        {
            nextqueuefill=0;
            if (!shutdown_flag)
            {
                msgq::queuescan();
            }

        }

        next_time=0;
        if ( msgq::queuehead && msgq::queuehead->nextsenddel
                > current_time)
            next_time=msgq::queuehead->nextsenddel;
        if (!shutdown_flag && msgq::inprogress == 0 &&
                shutdown_time == 0)
        {
            shutdown_time=current_time + 5 * 60;
            if (shutdown_time < start_time + respawnlo)
                shutdown_time=start_time + respawnlo;
        }

        if (shutdown_time && (next_time == 0 ||
                              shutdown_time < next_time))
            next_time=shutdown_time;

        if (nextqueuefill)
        {
            /* Or, wake up next time we need to refill the queue */

            if (next_time == 0 || nextqueuefill < next_time)
            {
                next_time=nextqueuefill;
            }
        }

        fdc=fds;

        struct	timeval	tv;

        if (next_time)
        {
            tv.tv_sec= next_time > current_time ?
                       next_time - current_time:0;
            tv.tv_usec=0;
        }

#if 1
        {
            char buf[40];

            clog_msg_start_info();
            clog_msg_str("Waiting.  shutdown time=");
            strcpy(buf, shutdown_time ? ctime(&shutdown_time):"none\n");
            *strchr(buf, '\n')=0;
            clog_msg_str(buf);

            clog_msg_str(", wakeup time=");
            strcpy(buf, next_time ? ctime(&next_time):"none\n");
            *strchr(buf, '\n')=0;
            clog_msg_str(buf);
            clog_msg_str(", queuedelivering=");
            clog_msg_int(msgq::queuedelivering);
            clog_msg_str(", inprogress=");
            clog_msg_int(msgq::inprogress);
            clog_msg_send();
        }
#endif

        while (select(maxfd, &fdc, (fd_set *)0, (fd_set *)0,
                      (next_time && doscantmp == 0 ?
                       &tv:(struct timeval *)0)) < 0)
        {
            if (errno != EINTR)	clog_msg_errno();
        }
        time(&current_time);
        if (shutdown_time)
        {
            if (current_time >= shutdown_time &&
                    msgq::inprogress == 0)
            {
                clog_msg_start_info();
                clog_msg_str("SHUTDOWN: respawnlo limit reached, system inactive.");
                clog_msg_send();
                shutdown_flag=1;
            }
            shutdown_time=0;
        }

        /* Handle commands sent via the trigger pipe */

        if (FD_ISSET(triggerr, &fdc))
        {
            unsigned	l;
            char	cmdbuf[256];
            int	c;

            do
            {
                l=0;
                do
                {
                    c=mybuf_get(&trigger_buf);
                    if (l < sizeof(cmdbuf)-1)
                        cmdbuf[l++]=c;
                } while (c != '\n');
                cmdbuf[l]=0;

                if (strcmp(cmdbuf, TRIGGER_NEWMSG) == 0)
                    doscantmp=1;
                else if (strcmp(cmdbuf, TRIGGER_RESTART) == 0)
                {
                    shutdown_flag=1;
                    clog_msg_start_info();
                    clog_msg_str("SHUTDOWN: Restarting...");
                    clog_msg_send();
                }
                else if (strcmp(cmdbuf, TRIGGER_STOP) == 0)
                {
                    clog_msg_start_info();
                    clog_msg_str("SHUTDOWN: Stopping...");
                    clog_msg_send();
                    _exit(99);
                }
                else if (strcmp(cmdbuf, TRIGGER_FLUSH) == 0)
                {
                    flushtime=current_time;
                    for (mp=msgq::queuehead; mp;
                            mp=mp->next)
                        mp->nextsenddel=current_time;
                }
                else if (strncmp(cmdbuf, TRIGGER_FLUSHMSG,
                                 sizeof(TRIGGER_FLUSHMSG)-1) == 0)
                {
                    char *p;
                    ino_t	n;

                    if ((p=strchr(cmdbuf, '\n')) != 0)
                        *p=0;

                    p=cmdbuf+sizeof(TRIGGER_FLUSHMSG)-1;
                    while (*p == ' ')	++p;
                    if (comparseqid(p, &n) == 0 &&
                            !shutdown_flag)
                        msgq::flushmsg(n, p);
                }
            } while (mybuf_more(&trigger_buf));
        }

        for (nd=0; nd<drvinfo::nmodules; nd++)
        {
            struct mybuf *p= &drvinfo::modules[nd].module_from;
            size_t	delnum;
            int	c;

            if (!FD_ISSET(p->fd, &fdc))	continue;
            do
            {
                delnum=0;
                while (errno=0, ((c=mybuf_get(p)) != '\n'))
                {
                    if (c < 0)
                    {
                        if (errno == EINTR)
                            continue;

                        clog_msg_start_err();
                        clog_msg_str("MODULE ");
                        clog_msg_str(
                            drvinfo::modules[nd]
                            .module->name);
                        clog_msg_str(" ABORTED.");
                        clog_msg_send();
                        _exit(1);
                    }
                    if (c >= '0' && c <= '9')
                        delnum=delnum * 10 + (c-'0');
                }
                msgq::completed(drvinfo::modules[nd], delnum);
            } while (mybuf_more(p));
            if (!shutdown_flag)	shutdown_time=0;
        }
    }

    close(triggerr);
    close(triggerw);

    drvinfo::cleanup();
    return (0);
}