This repository has been archived on 2024-04-08. You can view files and clone it, but cannot push or open issues or pull requests.
deb-mbse/mbtask/mbtask.c

1732 lines
46 KiB
C
Raw Normal View History

2001-08-17 05:46:24 +00:00
/*****************************************************************************
*
* $Id$
2001-08-17 05:46:24 +00:00
* Purpose ...............: MBSE BBS Task Manager
*
*****************************************************************************
2007-02-11 14:35:34 +00:00
* Copyright (C) 1997-2007
2001-08-17 05:46:24 +00:00
*
* Michiel Broek FIDO: 2:280/2802
* Beekmansbos 10
* 1971 BV IJmuiden
* the Netherlands
*
* This file is part of MBSE BBS.
*
* This BBS is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* MBSE BBS is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MBSE BBS; see the file COPYING. If not, write to the Free
* Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*****************************************************************************/
2002-06-30 13:20:57 +00:00
#include "../config.h"
2004-02-21 17:22:00 +00:00
#include "../lib/mbselib.h"
#include "../paths.h"
2001-08-17 05:46:24 +00:00
#include "signame.h"
#include "taskstat.h"
#include "taskutil.h"
#include "taskregs.h"
#include "taskcomm.h"
2004-03-20 13:26:34 +00:00
#include "taskdisk.h"
2005-04-16 14:49:58 +00:00
#include "taskibc.h"
#include "callstat.h"
2001-08-17 05:46:24 +00:00
#include "outstat.h"
#include "../lib/nodelist.h"
2002-02-22 21:15:21 +00:00
#include "ports.h"
#include "calllist.h"
#include "ping.h"
2003-03-24 19:44:38 +00:00
#include "taskchat.h"
2001-08-17 05:46:24 +00:00
#include "mbtask.h"
/*
* Global variables
*/
static onetask task[MAXTASKS]; /* Array with tasks */
2002-02-22 21:15:21 +00:00
extern tocall calllist[MAXTASKS]; /* Array with calllist */
2001-08-17 05:46:24 +00:00
reg_info reginfo[MAXCLIENT]; /* Array with clients */
static pid_t pgrp; /* Pids group */
int sock = -1; /* Datagram socket */
struct sockaddr_un servaddr; /* Server address */
struct sockaddr_un from; /* From address */
2006-02-13 19:26:30 +00:00
struct sockaddr_in myaddr_in; /* IBC local socket */
struct sockaddr_in clientaddr_in; /* IBC remote socket */
int ibcsock = -1; /* IBC socket */
2001-08-17 05:46:24 +00:00
int fromlen;
2003-08-03 15:11:33 +00:00
char waitmsg[81]; /* Waiting message */
2001-08-17 05:46:24 +00:00
static char spath[PATH_MAX]; /* Socket path */
int logtrans = 0; /* Log transactions */
struct taskrec TCFG; /* Task config record */
struct sysconfig CFG; /* System config */
struct _nodeshdr nodeshdr; /* Nodes header record */
struct _nodes nodes; /* Nodes data record */
struct _fidonethdr fidonethdr; /* Fidonet header rec. */
struct _fidonet fidonet; /* Fidonet data record */
time_t tcfg_time; /* Config record time */
time_t cfg_time; /* Config record time */
time_t tty_time; /* TTY config time */
2001-08-17 05:46:24 +00:00
char tcfgfn[PATH_MAX]; /* Config file name */
char cfgfn[PATH_MAX]; /* Config file name */
char ttyfn[PATH_MAX]; /* TTY file name */
2002-02-22 21:15:21 +00:00
extern int ping_isocket; /* Ping socket */
2001-08-17 05:46:24 +00:00
int internet = FALSE; /* Internet is down */
2002-02-04 20:37:01 +00:00
double Load; /* System Load */
2001-08-17 05:46:24 +00:00
int Processing; /* Is system running */
int ZMH = FALSE; /* Zone Mail Hour */
int UPSalarm = FALSE; /* UPS alarm status */
2004-09-19 14:08:01 +00:00
int UPSdown = FALSE; /* UPS down status */
2001-08-17 05:46:24 +00:00
extern int s_bbsopen; /* BBS open semafore */
extern int s_scanout; /* Scan outbound sema */
extern int s_mailout; /* Mail out semafore */
extern int s_mailin; /* Mail in semafore */
extern int s_index; /* Compile nl semafore */
extern int s_newnews; /* New news semafore */
extern int s_reqindex; /* Create req index sem */
extern int s_msglink; /* Messages link sem */
int masterinit = FALSE; /* Master init needed */
2001-12-23 14:15:58 +00:00
int ptimer = PAUSETIME; /* Pause timer */
int tflags = FALSE; /* if nodes with Txx */
extern int nxt_hour; /* Next event hour */
extern int nxt_min; /* Next event minute */
extern _alist_l *alist; /* Nodes to call list */
2002-02-24 13:52:13 +00:00
int rescan = FALSE; /* Master rescan flag */
extern int pots_calls;
extern int isdn_calls;
extern int inet_calls;
2002-02-24 17:17:58 +00:00
extern int pots_lines; /* POTS lines available */
extern int isdn_lines; /* ISDN lines available */
extern int pots_free; /* POTS lines free */
extern int isdn_free; /* ISDN lines free */
extern pp_list *pl; /* List of tty ports */
2002-03-23 13:12:29 +00:00
extern int ipmailers; /* TCP/IP mail sessions */
2003-02-12 20:20:59 +00:00
extern int tosswait; /* Toss wait timer */
extern pid_t mypid; /* Pid of daemon */
2003-12-23 21:07:33 +00:00
int G_Shutdown = FALSE; /* Global shutdown */
int nodaemon = FALSE; /* Run in foreground */
2006-02-13 19:26:30 +00:00
extern time_t resettime; /* IBC reset time */
2006-02-15 19:56:26 +00:00
int Run_IBC = TRUE; /* Run IBC server */
2001-12-23 14:15:58 +00:00
2001-08-17 05:46:24 +00:00
void logtasks(void);
2001-08-17 05:46:24 +00:00
/*
* Load main configuration, if it doesn't exist, create it.
* This is the case the very first time when you start MBSE BBS.
*/
void load_maincfg(void)
{
2002-09-28 22:20:45 +00:00
FILE *fp;
struct utsname un;
int i;
if ((fp = fopen(cfgfn, "r")) == NULL) {
masterinit = TRUE;
memset(&CFG, 0, sizeof(CFG));
/*
* Fill Registration defaults
*/
2005-08-29 21:03:28 +00:00
snprintf(CFG.bbs_name, 36, "MBSE BBS");
2002-09-28 22:20:45 +00:00
uname((struct utsname *)&un);
2005-01-07 21:46:24 +00:00
#if defined(__USE_GNU)
2005-08-29 21:03:28 +00:00
snprintf(CFG.sysdomain, 36, "%s.%s", un.nodename, un.domainname);
2005-01-07 21:46:24 +00:00
#elif defined(__linux__)
2005-08-29 21:03:28 +00:00
snprintf(CFG.sysdomain, 36, "%s.%s", un.nodename, un.__domainname);
2005-08-28 11:34:24 +00:00
#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
2005-08-29 21:03:28 +00:00
snprintf(CFG.sysdomain, 36, "%s", un.nodename); /* No domain in FreeBSD */
2005-01-07 21:46:24 +00:00
#else
#error "Don't know un.domainname on this OS"
2001-08-25 19:53:11 +00:00
#endif
2005-08-29 21:03:28 +00:00
snprintf(CFG.comment, 56, "MBSE BBS development");
snprintf(CFG.origin, 51, "MBSE BBS. Made in the Netherlands");
snprintf(CFG.location, 36, "Earth");
2002-09-28 22:20:45 +00:00
/*
* Fill Filenames defaults
*/
2005-08-29 21:03:28 +00:00
snprintf(CFG.logfile, 15, "system.log");
snprintf(CFG.error_log, 15, "error.log");
snprintf(CFG.default_menu, 15, "main.mnu");
snprintf(CFG.deflang, 10, "en");
2005-08-29 21:03:28 +00:00
snprintf(CFG.chat_log, 15, "chat.log");
snprintf(CFG.welcome_logo, 15, "logo.asc");
snprintf(CFG.mgrlog, 15, "manager.log");
snprintf(CFG.debuglog, 15, "debug.log");
2002-09-28 22:20:45 +00:00
/*
* Fill Global defaults
*/
2005-08-29 21:03:28 +00:00
snprintf(CFG.bbs_usersdir, 65, "%s/home", getenv("MBSE_ROOT"));
snprintf(CFG.nodelists, 65, "%s/var/nodelist", getenv("MBSE_ROOT"));
snprintf(CFG.inbound, 65, "%s/var/unknown", getenv("MBSE_ROOT"));
snprintf(CFG.pinbound, 65, "%s/var/inbound", getenv("MBSE_ROOT"));
snprintf(CFG.outbound, 65, "%s/var/bso/outbound", getenv("MBSE_ROOT"));
snprintf(CFG.msgs_path, 65, "%s/var/msgs", getenv("MBSE_ROOT"));
snprintf(CFG.uxpath, 65, "%s", getenv("MBSE_ROOT"));
snprintf(CFG.badtic, 65, "%s/var/badtic", getenv("MBSE_ROOT"));
snprintf(CFG.ticout, 65, "%s/var/ticqueue", getenv("MBSE_ROOT"));
snprintf(CFG.req_magic, 65, "%s/var/magic", getenv("MBSE_ROOT"));
snprintf(CFG.alists_path, 65, "%s/var/arealists", getenv("MBSE_ROOT"));
snprintf(CFG.out_queue, 65, "%s/var/queue", getenv("MBSE_ROOT"));
snprintf(CFG.rulesdir, 65, "%s/var/rules", getenv("MBSE_ROOT"));
2002-09-28 22:20:45 +00:00
CFG.leavecase = TRUE;
/*
* Newfiles reports
*/
2005-08-29 21:03:28 +00:00
snprintf(CFG.ftp_base, 65, "%s/ftp/pub", getenv("MBSE_ROOT"));
2002-09-28 22:20:45 +00:00
CFG.newdays = 30;
CFG.security.level = 20;
CFG.new_split = 27;
CFG.new_force = 30;
/*
* BBS Globals
*/
CFG.CityLen = 6;
CFG.exclude_sysop = TRUE;
CFG.iConnectString = FALSE;
CFG.iAskFileProtocols = FALSE;
CFG.sysop_access = 32000;
CFG.password_length = 4;
CFG.iPasswd_Char = '.';
CFG.idleout = 3;
CFG.iQuota = 10;
CFG.iCRLoginCount = 10;
CFG.bbs_loglevel = DLOG_ALLWAYS | DLOG_ERROR | DLOG_ATTENT | DLOG_NORMAL | DLOG_VERBOSE;
CFG.util_loglevel = DLOG_ALLWAYS | DLOG_ERROR | DLOG_ATTENT | DLOG_NORMAL | DLOG_VERBOSE;
CFG.OLR_NewFileLimit = 30;
CFG.OLR_MaxReq = 25;
CFG.slow_util = TRUE;
CFG.iCrashLevel = 100;
CFG.iAttachLevel = 100;
CFG.new_groups = 25;
2003-07-29 20:42:38 +00:00
CFG.max_logins = 1;
CFG.AskNewmail = YES;
CFG.AskNewfiles = YES;
2002-09-28 22:20:45 +00:00
CFG.slow_util = TRUE;
CFG.iCrashLevel = 100;
CFG.iAttachLevel = 100;
CFG.new_groups = 25;
2005-08-29 21:03:28 +00:00
snprintf(CFG.startname, 9, "bbs");
2002-09-28 22:20:45 +00:00
CFG.freespace = 10;
/*
* New Users
*/
CFG.newuser_access.level = 20;
CFG.iCapUserName = TRUE;
CFG.iDataPhone = TRUE;
CFG.iVoicePhone = TRUE;
CFG.iDOB = TRUE;
CFG.iTelephoneScan = TRUE;
CFG.iLocation = TRUE;
CFG.iHotkeys = TRUE;
CFG.iCapLocation = FALSE;
CFG.AskAddress = TRUE;
CFG.GiveEmail = TRUE;
/*
* Colors
*/
2003-01-06 13:44:30 +00:00
CFG.TextColourF = CYAN;
CFG.TextColourB = BLACK;
CFG.UnderlineColourF = YELLOW;
CFG.UnderlineColourB = BLACK;
CFG.InputColourF = LIGHTCYAN;
CFG.InputColourB = BLACK;
CFG.CRColourF = WHITE;
CFG.CRColourB = BLACK;
CFG.MoreF = LIGHTMAGENTA;
CFG.MoreB = BLACK;
CFG.HiliteF = WHITE;
CFG.HiliteB = BLACK;
CFG.FilenameF = YELLOW;
CFG.FilenameB = BLACK;
CFG.FilesizeF = LIGHTMAGENTA;
CFG.FilesizeB = BLACK;
CFG.FiledateF = LIGHTGREEN;
CFG.FiledateB = BLACK;
CFG.FiledescF = CYAN;
CFG.FiledescB = BLACK;
CFG.MsgInputColourF = CYAN;
CFG.MsgInputColourB = BLACK;
2002-09-28 22:20:45 +00:00
/*
* Paging
*/
CFG.iPageLength = 30;
CFG.iMaxPageTimes = 5;
CFG.iAskReason = TRUE;
CFG.iSysopArea = 1;
CFG.iAutoLog = TRUE;
CFG.iChatPromptChk = TRUE;
CFG.iStopChatTime = TRUE;
2001-08-17 05:46:24 +00:00
2002-09-28 22:20:45 +00:00
/*
* Fill ticconf defaults
*/
CFG.ct_PlusAll = TRUE;
CFG.ct_Notify = TRUE;
CFG.ct_Message = TRUE;
CFG.ct_TIC = TRUE;
CFG.tic_days = 30;
2005-08-29 21:03:28 +00:00
snprintf(CFG.hatchpasswd, 21, "DizIzMyBIGseeKret");
2002-09-28 22:20:45 +00:00
CFG.tic_systems = 10;
CFG.tic_groups = 25;
CFG.tic_dupes = 16000;
/*
* Fill Mail defaults
*/
CFG.maxpktsize = 150;
CFG.maxarcsize = 300;
2005-08-29 21:03:28 +00:00
snprintf(CFG.badboard, 65, "%s/var/mail/badmail", getenv("MBSE_ROOT"));
snprintf(CFG.dupboard, 65, "%s/var/mail/dupemail", getenv("MBSE_ROOT"));
snprintf(CFG.popnode, 65, "localhost");
snprintf(CFG.smtpnode, 65, "localhost");
snprintf(CFG.nntpnode, 65, "localhost");
2002-09-28 22:20:45 +00:00
CFG.toss_days = 30;
CFG.toss_dupes = 16000;
CFG.toss_old = 60;
CFG.defmsgs = 500;
CFG.defdays = 90;
CFG.toss_systems = 10;
CFG.toss_groups = 25;
CFG.UUCPgate.zone = 2;
CFG.UUCPgate.net = 292;
CFG.UUCPgate.node = 875;
2005-08-29 21:03:28 +00:00
snprintf(CFG.UUCPgate.domain, 13, "fidonet");
2002-09-28 22:20:45 +00:00
CFG.nntpdupes = 16000;
2002-10-28 13:57:38 +00:00
CFG.ca_PlusAll = TRUE;
CFG.ca_Notify = TRUE;
CFG.ca_Passwd = TRUE;
CFG.ca_Pause = TRUE;
CFG.ca_Check = TRUE;
2002-09-28 22:20:45 +00:00
for (i = 0; i < 32; i++) {
2005-08-29 21:03:28 +00:00
snprintf(CFG.fname[i], 17, "Flag %d", i+1);
snprintf(CFG.aname[i], 17, "Flag %d", i+1);
2002-09-28 22:20:45 +00:00
}
2005-08-29 21:03:28 +00:00
snprintf(CFG.aname[0], 17, "Everyone");
2002-09-28 22:20:45 +00:00
/*
* Fido mailer defaults
*/
CFG.timeoutreset = 3L;
CFG.timeoutconnect = 60L;
2005-08-29 21:03:28 +00:00
snprintf(CFG.phonetrans[0].match, 21, "31-255");
snprintf(CFG.phonetrans[1].match, 21, "31-");
snprintf(CFG.phonetrans[1].repl, 21, "0");
snprintf(CFG.phonetrans[2].repl, 21, "00");
2004-07-22 20:30:58 +00:00
CFG.IP_Speed = 256000;
2002-09-28 22:20:45 +00:00
CFG.dialdelay = 60;
2005-08-29 21:03:28 +00:00
snprintf(CFG.IP_Flags, 31, "ICM,XX,IBN");
2002-09-28 22:20:45 +00:00
CFG.cico_loglevel = DLOG_ALLWAYS | DLOG_ERROR | DLOG_ATTENT | DLOG_NORMAL | DLOG_VERBOSE;
/*
* WWW defaults
*/
2005-08-29 21:03:28 +00:00
snprintf(CFG.www_root, 81, "/var/www/htdocs");
snprintf(CFG.www_link2ftp, 21, "files");
snprintf(CFG.www_url, 41, "http://%s", CFG.sysdomain);
snprintf(CFG.www_charset, 21, "ISO 8859-1");
snprintf(CFG.www_author, 41, "Your Name");
2003-01-06 13:44:30 +00:00
if (strlen(_PATH_CONVERT))
2005-08-29 21:03:28 +00:00
snprintf(CFG.www_convert, 81, "%s -geometry x100", _PATH_CONVERT);
2002-09-28 22:20:45 +00:00
CFG.www_files_page = 10;
CFG.maxarticles = 500;
2004-03-17 20:24:59 +00:00
CFG.priority = 15;
#ifdef __linux__
CFG.do_sync = TRUE;
#endif
CFG.is_upgraded = TRUE;
2002-09-28 22:20:45 +00:00
if ((fp = fopen(cfgfn, "a+")) == NULL) {
perror("");
fprintf(stderr, "Can't create %s\n", cfgfn);
2002-10-20 20:58:55 +00:00
exit(MBERR_INIT_ERROR);
2002-09-28 22:20:45 +00:00
}
fwrite(&CFG, sizeof(CFG), 1, fp);
fclose(fp);
chmod(cfgfn, 0640);
} else {
fread(&CFG, sizeof(CFG), 1, fp);
fclose(fp);
2003-09-09 19:39:51 +00:00
if (strlen(CFG.debuglog) == 0)
2005-08-29 21:03:28 +00:00
snprintf(CFG.debuglog, 15, "debug.log");
2002-09-28 22:20:45 +00:00
}
cfg_time = file_time(cfgfn);
2001-08-17 05:46:24 +00:00
}
/*
* Load task configuration data.
*/
void load_taskcfg(void)
{
2006-02-13 19:26:30 +00:00
FILE *fp;
if ((fp = fopen(tcfgfn, "r")) == NULL) {
memset(&TCFG, 0, sizeof(TCFG));
TCFG.maxload = 1.50;
snprintf(TCFG.zmh_start, 6, "02:30");
snprintf(TCFG.zmh_end, 6, "03:30");
snprintf(TCFG.cmd_mailout, 81, "%s/bin/mbfido scan web -quiet", getenv("MBSE_ROOT"));
snprintf(TCFG.cmd_mailin, 81, "%s/bin/mbfido tic toss web -quiet", getenv("MBSE_ROOT"));
snprintf(TCFG.cmd_newnews, 81, "%s/bin/mbfido news web -quiet", getenv("MBSE_ROOT"));
snprintf(TCFG.cmd_mbindex1, 81, "%s/bin/mbindex -quiet", getenv("MBSE_ROOT"));
if (strlen(_PATH_GOLDNODE))
snprintf(TCFG.cmd_mbindex2, 81, "%s -f -q", _PATH_GOLDNODE);
snprintf(TCFG.cmd_msglink, 81, "%s/bin/mbmsg link -quiet", getenv("MBSE_ROOT"));
snprintf(TCFG.cmd_reqindex, 81, "%s/bin/mbfile index -quiet", getenv("MBSE_ROOT"));
TCFG.max_tcp = 0;
snprintf(TCFG.isp_ping1, 41, "192.168.1.1");
snprintf(TCFG.isp_ping2, 41, "192.168.1.1");
if ((fp = fopen(tcfgfn, "a+")) == NULL) {
Syslog('?', "$Can't create %s", tcfgfn);
die(MBERR_INIT_ERROR);
2001-08-17 05:46:24 +00:00
}
2006-02-13 19:26:30 +00:00
fwrite(&TCFG, sizeof(TCFG), 1, fp);
fclose(fp);
chmod(tcfgfn, 0640);
Syslog('+', "Created new %s", tcfgfn);
} else {
fread(&TCFG, sizeof(TCFG), 1, fp);
fclose(fp);
}
2001-08-17 05:46:24 +00:00
2006-02-13 19:26:30 +00:00
tcfg_time = file_time(tcfgfn);
2001-08-17 05:46:24 +00:00
}
2006-02-05 14:15:17 +00:00
/*
* Milliseconds timer, returns 0 on success.
*/
int msleep(int msecs)
{
int rc;
struct timespec req, rem;
rem.tv_sec = 0;
rem.tv_nsec = 0;
req.tv_sec = msecs / 1000;
req.tv_nsec = (msecs % 1000) * 1000000;
while (TRUE) {
rc = nanosleep(&req, &rem);
if (rc == 0)
break;
if ((errno == EINVAL) || (errno == EFAULT)) {
WriteError("$msleep(%d)", msecs);
break;
}
/*
* Error was EINTR, run timer again to complete.
*/
req.tv_sec = rem.tv_sec;
req.tv_nsec = rem.tv_nsec;
rem.tv_sec = 0;
rem.tv_nsec = 0;
}
return rc;
}
2001-08-17 05:46:24 +00:00
/*
* Launch an external program in the background.
* On success add it to the tasklist and return
2001-12-23 14:15:58 +00:00
* the pid. Set the pause timer.
2001-08-17 05:46:24 +00:00
*/
pid_t launch(char *cmd, char *opts, char *name, int tasktype)
{
2006-02-13 19:26:30 +00:00
static char buf[PATH_MAX];
2006-05-23 19:18:52 +00:00
static char *vector[16];
2006-02-13 19:26:30 +00:00
int i, rc = 0;
pid_t pid = 0;
2001-08-17 05:46:24 +00:00
if (checktasks(0) >= MAXTASKS) {
Syslog('?', "Launch: can't execute %s, maximum tasks reached", cmd);
return 0;
}
2006-05-23 19:18:52 +00:00
for (i = 0; i < 16; i++)
vector[i] = NULL;
2006-02-01 20:55:45 +00:00
if (opts == NULL)
2005-08-29 21:03:28 +00:00
snprintf(buf, PATH_MAX, "%s", cmd);
else
2005-08-29 21:03:28 +00:00
snprintf(buf, PATH_MAX, "%s %s", cmd, opts);
2001-08-17 05:46:24 +00:00
i = 0;
vector[i++] = strtok(buf," \t\n\0");
while ((vector[i++] = strtok(NULL," \t\n")) && (i<16));
vector[15] = NULL;
2001-08-17 05:46:24 +00:00
if (file_exist(vector[0], X_OK)) {
2007-02-11 14:35:34 +00:00
WriteError("Launch: can't execute %s, command not found", vector[0]);
return 0;
}
2006-02-01 20:55:45 +00:00
2006-02-05 14:15:17 +00:00
switch (pid = fork()) {
2001-08-17 05:46:24 +00:00
case -1:
2006-02-13 19:26:30 +00:00
WriteError("$Launch: error, can't fork grandchild");
2001-08-17 05:46:24 +00:00
return 0;
case 0:
2006-02-05 14:15:17 +00:00
/*
* A delay in the child process to prevent it returns
2006-02-13 19:26:30 +00:00
* before the main process sees it ever started.
2006-02-05 14:15:17 +00:00
*/
msleep(150);
2001-08-17 05:46:24 +00:00
/* From Paul Vixies cron: */
rc = setsid(); /* It doesn't seem to help */
if (rc == -1)
2007-02-11 14:35:34 +00:00
WriteError("$Launch: setsid()");
2001-08-17 05:46:24 +00:00
close(0);
if (open("/dev/null", O_RDONLY) != 0) {
2007-02-11 14:35:34 +00:00
WriteError("$Launch: \"%s\": reopen of stdin to /dev/null failed", buf);
_exit(MBERR_EXEC_FAILED);
2001-08-17 05:46:24 +00:00
}
close(1);
if (open("/dev/null", O_WRONLY | O_APPEND | O_CREAT,0600) != 1) {
2007-02-11 14:35:34 +00:00
WriteError("$Launch: \"%s\": reopen of stdout to /dev/null failed", buf);
_exit(MBERR_EXEC_FAILED);
2001-08-17 05:46:24 +00:00
}
close(2);
if (open("/dev/null", O_WRONLY | O_APPEND | O_CREAT,0600) != 2) {
2007-02-11 14:35:34 +00:00
WriteError("$Launch: \"%s\": reopen of stderr to /dev/null failed", buf);
_exit(MBERR_EXEC_FAILED);
2001-08-17 05:46:24 +00:00
}
errno = 0;
rc = execv(vector[0],vector);
2007-02-11 14:35:34 +00:00
WriteError("$Launch: execv \"%s\" failed, returned %d", cmd, rc);
2002-10-20 20:58:55 +00:00
_exit(MBERR_EXEC_FAILED);
2001-08-17 05:46:24 +00:00
default:
/* grandchild's daddy's process */
break;
}
2001-08-17 05:46:24 +00:00
/*
* Add it to the tasklist.
*/
for (i = 0; i < MAXTASKS; i++) {
if (strlen(task[i].name) == 0) {
strcpy(task[i].name, name);
strcpy(task[i].cmd, cmd);
if (opts)
strcpy(task[i].opts, opts);
task[i].pid = pid;
task[i].status = 0;
task[i].running = TRUE;
task[i].rc = 0;
task[i].tasktype = tasktype;
logtasks();
break;
2001-08-17 05:46:24 +00:00
}
}
2001-08-17 05:46:24 +00:00
ptimer = PAUSETIME;
2001-12-23 14:15:58 +00:00
if (opts)
Syslog('+', "Launch: task %d \"%s %s\" success, pid=%d", i, cmd, opts, pid);
else
Syslog('+', "Launch: task %d \"%s\" success, pid=%d", i, cmd, pid);
return pid;
2001-08-17 05:46:24 +00:00
}
/*
* Count specific running tasks
*/
int runtasktype(int tasktype)
{
2006-02-04 13:56:21 +00:00
int i, count = 0;
2001-08-17 05:46:24 +00:00
2006-02-04 13:56:21 +00:00
for (i = 0; i < MAXTASKS; i++) {
if (strlen(task[i].name) && task[i].running && (task[i].tasktype == tasktype))
count++;
}
return count;
2001-08-17 05:46:24 +00:00
}
void logtasks(void)
{
int i, first = TRUE;
if (first) {
first = FALSE;
Syslog('t', "Task Type pid stat rc");
Syslog('t', "---------------- ------- ----- ---- -----");
for (i = 0; i < MAXTASKS; i++)
if (strlen(task[i].name))
Syslog('t', "%-16s %s %5d %s %5d", task[i].name, callmode(task[i].tasktype),
task[i].pid, task[i].running?"runs":"stop", task[i].rc);
}
}
2001-08-17 05:46:24 +00:00
/*
* Check all running tasks registered in the tasklist.
* Report programs that are stopped. If signal is set
* then send that signal.
*/
int checktasks(int onsig)
{
int i, j, rc, count = 0, status;
2001-08-17 05:46:24 +00:00
2002-02-12 22:42:09 +00:00
for (i = 0; i < MAXTASKS; i++) {
if (strlen(task[i].name)) {
2001-08-17 05:46:24 +00:00
2002-02-12 22:42:09 +00:00
if (onsig) {
if (kill(task[i].pid, onsig) == 0)
Syslog('+', "%s to %s (pid %d) succeeded", SigName[onsig], task[i].name, task[i].pid);
2002-02-12 22:42:09 +00:00
else
Syslog('+', "%s to %s (pid %d) failed", SigName[onsig], task[i].name, task[i].pid);
2002-02-12 22:42:09 +00:00
}
2001-08-17 05:46:24 +00:00
task[i].rc = wait4(task[i].pid, &status, WNOHANG | WUNTRACED, NULL);
task[i].status = status;
2006-02-04 13:56:21 +00:00
/*
* If task was set not running, handle status
2006-02-04 13:56:21 +00:00
*/
if (task[i].rc) {
task[i].running = FALSE;
2002-02-24 13:52:13 +00:00
/*
* If a mailer call is finished, set the global rescan flag.
*/
2002-02-12 22:42:09 +00:00
if (task[i].tasktype == CM_POTS || task[i].tasktype == CM_ISDN || task[i].tasktype == CM_INET)
2002-02-24 13:52:13 +00:00
rescan = TRUE;
2002-02-12 22:42:09 +00:00
ptimer = PAUSETIME;
/*
* If a nodelist compiler is ready, reload the nodelists configuration
*/
if (task[i].tasktype == MBINDEX) {
deinitnl();
initnl();
}
2001-08-17 05:46:24 +00:00
logtasks();
}
switch (task[i].rc) {
case -1:
if (errno == ECHILD)
Syslog('+', "Task %d \"%s\" is ready", i, task[i].name);
else
Syslog('+', "Task %d \"%s\" is ready, error: %s", i, task[i].name, strerror(errno));
break;
case 0:
/*
* Update last known status when running.
*/
task[i].status = status;
count++;
break;
default:
if (WIFEXITED(task[i].status)) {
rc = WEXITSTATUS(task[i].status);
if (rc)
Syslog('+', "Task %s is ready, error=%d", task[i].name, rc);
2002-02-12 22:42:09 +00:00
else
Syslog('+', "Task %s is ready", task[i].name);
} else if (WIFSIGNALED(task[i].status)) {
rc = WTERMSIG(task[i].status);
/*
* Here we don't report an error number, on FreeBSD WIFSIGNALED
* seems true while there's nothing wrong.
*/
Syslog('+', "Task %s terminated", task[i].name);
} else if (WIFSTOPPED(task[i].status)) {
rc = WSTOPSIG(task[i].status);
Syslog('+', "Task %s stopped on signal %s (%d)", task[i].name, SigName[rc], rc);
}
break;
}
2001-08-17 05:46:24 +00:00
/*
* Remove finished task from the list
*/
if (!task[i].running) {
for (j = 0; j < MAXTASKS; j++) {
if (calllist[j].taskpid == task[i].pid) {
calllist[j].calling = FALSE;
calllist[j].taskpid = 0;
rescan = TRUE;
2002-02-12 22:42:09 +00:00
}
2001-08-17 05:46:24 +00:00
}
2002-02-12 22:42:09 +00:00
memset(&task[i], 0, sizeof(onetask));
}
2001-08-17 05:46:24 +00:00
}
2002-02-12 22:42:09 +00:00
}
2001-08-17 05:46:24 +00:00
2002-02-12 22:42:09 +00:00
return count;
2001-08-17 05:46:24 +00:00
}
2003-12-23 21:07:33 +00:00
/*
* This function triggers the shutdown and is only installed for SIGTERM
* and SIGINT. On NetBSD the threads signal handlers cannot be disabled,
* so in fact all threads call this function as soon as one of these
* signals is received. The first one arrived will initiate the shutdown.
*/
void start_shutdown(int onsig)
{
2006-04-17 08:00:54 +00:00
Syslog('+', "Trigger shutdown on signal %s", SigName[onsig]);
2003-12-23 21:07:33 +00:00
signal(onsig, SIG_IGN);
G_Shutdown = TRUE;
}
/*
* Normal fatal signal handler, but also used during shutdown.
*/
2001-08-17 05:46:24 +00:00
void die(int onsig)
{
int i, count;
2004-09-19 14:08:01 +00:00
char temp[80];
2001-08-17 05:46:24 +00:00
2003-02-08 15:28:31 +00:00
signal(onsig, SIG_IGN);
2004-09-19 14:08:01 +00:00
if (onsig < NSIG) {
if ((onsig == SIGTERM) || (nodaemon && (onsig == SIGINT))) {
Syslog('+', "Starting normal shutdown (%s)", SigName[onsig]);
} else {
Syslog('+', "Abnormal shutdown on signal %s", SigName[onsig]);
}
} else {
2004-09-19 14:08:01 +00:00
Syslog('+', "Shutdown on error %d", onsig);
}
2001-08-17 05:46:24 +00:00
2003-02-08 15:28:31 +00:00
/*
* First check if there are tasks running, if so try to stop them
*/
if ((count = checktasks(0))) {
Syslog('+', "There are %d tasks running, sending SIGTERM", count);
checktasks(SIGTERM);
for (i = 0; i < 15; i++) {
sleep(1);
count = checktasks(0);
if (count == 0)
break;
2001-08-17 05:46:24 +00:00
}
2003-02-08 15:28:31 +00:00
if (count) {
/*
* There are some diehards running...
*/
Syslog('+', "There are %d tasks running, sending SIGKILL", count);
count = checktasks(SIGKILL);
2001-08-17 05:46:24 +00:00
}
2003-02-08 15:28:31 +00:00
if (count) {
sleep(1);
count = checktasks(0);
if (count)
Syslog('?', "Still %d tasks running, giving up", count);
}
}
2003-12-22 19:40:21 +00:00
if ((count = checktasks(0)))
Syslog('?', "Shutdown with %d tasks still running", count);
else
Syslog('+', "Good, no more tasks running");
2004-09-19 14:08:01 +00:00
/*
* Now check for users online and other programs not started
* under control of mbtask.
*/
count = 30;
while (count) {
reg_fre_r(temp);
2004-09-19 14:08:01 +00:00
if (strcmp(temp, "100:0;") == 0) {
Syslog('+', "Good, no more other programs running");
break;
}
Syslog('+', "%s", temp+6);
sleep(1);
count--;
}
if ((count == 0) && strcmp(temp, "100:0;")) {
Syslog('?', "Continue shutdown with other programs running");
}
2003-12-22 19:40:21 +00:00
/*
2006-02-13 19:26:30 +00:00
* Disconnect chatservers
2003-12-22 19:40:21 +00:00
*/
2006-02-15 19:56:26 +00:00
if (Run_IBC)
ibc_shutdown();
/*
* Free memory
*/
2006-02-13 19:26:30 +00:00
deinit_ping();
2003-02-08 15:28:31 +00:00
deinitnl();
2006-02-13 19:26:30 +00:00
deinit_diskwatch();
unload_ports();
2003-02-08 15:28:31 +00:00
ulocktask();
printable(NULL, 0);
/*
* Close socket
*/
2003-02-08 15:28:31 +00:00
if (sock != -1)
close(sock);
if (!file_exist(spath, R_OK)) {
unlink(spath);
}
2003-02-08 15:28:31 +00:00
Syslog(' ', "MBTASK finished");
exit(onsig);
2001-08-17 05:46:24 +00:00
}
/*
* Put a lock on this program.
*/
int locktask(char *root)
{
2003-08-03 14:08:07 +00:00
char *tempfile, *lockfile;
FILE *fp;
pid_t oldpid;
tempfile = calloc(PATH_MAX, sizeof(char));
lockfile = calloc(PATH_MAX, sizeof(char));
2005-08-29 21:03:28 +00:00
snprintf(tempfile, PATH_MAX, "%s/var/run/mbtask.tmp", root);
snprintf(lockfile, PATH_MAX, "%s/var/run/mbtask", root);
2003-08-03 14:08:07 +00:00
if ((fp = fopen(tempfile, "w")) == NULL) {
perror("mbtask");
printf("Can't create lockfile \"%s\"\n", tempfile);
free(tempfile);
free(lockfile);
return 1;
}
fprintf(fp, "%10u\n", getpid());
fclose(fp);
while (TRUE) {
if (link(tempfile, lockfile) == 0) {
unlink(tempfile);
free(tempfile);
free(lockfile);
return 0;
}
if ((fp = fopen(lockfile, "r")) == NULL) {
perror("mbtask");
printf("Can't open lockfile \"%s\"\n", tempfile);
unlink(tempfile);
free(tempfile);
free(lockfile);
return 1;
}
if (fscanf(fp, "%u", &oldpid) != 1) {
perror("mbtask");
printf("Can't read old pid from \"%s\"\n", tempfile);
fclose(fp);
unlink(tempfile);
free(tempfile);
free(lockfile);
return 1;
2001-08-17 05:46:24 +00:00
}
fclose(fp);
2003-08-03 14:08:07 +00:00
if (kill(oldpid,0) == -1) {
if (errno == ESRCH) {
printf("Stale lock found for pid %u\n", oldpid);
unlink(lockfile);
/* no return, try lock again */
} else {
perror("mbtask");
printf("Kill for %u failed\n",oldpid);
unlink(tempfile);
free(tempfile);
free(lockfile);
return 1;
}
} else {
printf("Another mbtask is already running, pid=%u\n", oldpid);
unlink(tempfile);
free(tempfile);
free(lockfile);
return 1;
2001-08-17 05:46:24 +00:00
}
2003-08-03 14:08:07 +00:00
}
2001-08-17 05:46:24 +00:00
}
void ulocktask(void)
{
2003-08-03 14:08:07 +00:00
char *lockfile;
pid_t oldpid;
FILE *fp;
struct passwd *pw;
pw = getpwnam((char *)"mbse");
lockfile = calloc(PATH_MAX, sizeof(char));
2005-08-29 21:03:28 +00:00
snprintf(lockfile, PATH_MAX, "%s/var/run/mbtask", pw->pw_dir);
2003-08-03 14:08:07 +00:00
if ((fp = fopen(lockfile, "r")) == NULL) {
WriteError("$Can't open lockfile \"%s\"", lockfile);
free(lockfile);
return;
}
2003-08-03 14:08:07 +00:00
if (fscanf(fp, "%u", &oldpid) != 1) {
WriteError("$Can't read old pid from \"%s\"", lockfile);
fclose(fp);
unlink(lockfile);
free(lockfile);
return;
}
fclose(fp);
2003-08-03 14:08:07 +00:00
if (oldpid == getpid()) {
(void)unlink(lockfile);
}
free(lockfile);
2001-08-17 05:46:24 +00:00
}
2001-08-25 19:53:11 +00:00
/*
* External Semafore Checks
*/
void test_sema(char *);
void test_sema(char *sema)
{
2003-02-08 15:28:31 +00:00
if (IsSema(sema)) {
RemoveSema(sema);
Syslog('s', "Semafore %s detected", sema);
sem_set(sema, TRUE);
}
2001-08-25 19:53:11 +00:00
}
2001-08-17 05:46:24 +00:00
/*
* Check semafore's, system status flags etc. This is called
* each second to test for condition changes.
*/
void check_sema(void);
void check_sema(void)
{
2003-02-08 15:28:31 +00:00
/*
* Check UPS status.
*/
if (IsSema((char *)"upsalarm")) {
if (!UPSalarm)
Syslog('!', "UPS: power failure");
UPSalarm = TRUE;
} else {
if (UPSalarm)
Syslog('!', "UPS: the power is back");
UPSalarm = FALSE;
}
if (IsSema((char *)"upsdown")) {
Syslog('!', "UPS: power failure, starting shutdown");
2004-09-19 14:08:01 +00:00
UPSdown = TRUE;
2001-08-17 05:46:24 +00:00
/*
2003-02-08 15:28:31 +00:00
* Since the upsdown semafore is permanent, the system WILL go down
* there is no point for this program to stay. Signal all tasks and stop.
2001-08-17 05:46:24 +00:00
*/
2003-02-08 15:28:31 +00:00
die(MBERR_UPS_ALARM);
}
2001-08-17 05:46:24 +00:00
2003-02-08 15:28:31 +00:00
/*
* Check Zone Mail Hour
*/
get_zmh();
2001-08-17 05:46:24 +00:00
2003-02-08 15:28:31 +00:00
/*
* Semafore's that still can be detected, usefull for
* external programs that create them.
*/
test_sema((char *)"newnews");
test_sema((char *)"mailout");
test_sema((char *)"mailin");
test_sema((char *)"scanout");
2001-08-17 05:46:24 +00:00
}
2006-02-13 19:26:30 +00:00
void start_scheduler(int port)
2001-08-17 05:46:24 +00:00
{
2001-12-23 14:15:58 +00:00
struct passwd *pw;
2003-12-22 19:40:21 +00:00
char *cmd = NULL;
2004-12-29 12:39:47 +00:00
if (nodaemon)
printf("init fidonet\n");
2001-12-23 14:15:58 +00:00
InitFidonet();
2004-12-29 12:39:47 +00:00
if (nodaemon)
printf("done\n");
2001-12-23 14:15:58 +00:00
/*
* Registrate this server for mbmon in slot 0.
*/
reginfo[0].pid = getpid();
strcpy(reginfo[0].tty, "-");
strcpy(reginfo[0].uname, "mbse");
strcpy(reginfo[0].prg, "mbtask");
strcpy(reginfo[0].city, "localhost");
strcpy(reginfo[0].doing, "Start");
2005-10-16 12:13:20 +00:00
reginfo[0].started = (int)time(NULL);
2004-12-29 12:39:47 +00:00
if (nodaemon)
printf("reginfo filled\n");
2001-12-23 14:15:58 +00:00
Processing = TRUE;
TouchSema((char *)"mbtask.last");
/*
* Setup UNIX Datagram socket
*/
if ((sock = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) {
2003-12-24 12:00:00 +00:00
WriteError("$Can't create socket");
2002-10-20 20:58:55 +00:00
die(MBERR_INIT_ERROR);
2001-12-23 14:15:58 +00:00
}
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sun_family = AF_UNIX;
strcpy(servaddr.sun_path, spath);
2003-07-06 11:49:01 +00:00
if (bind(sock, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {
2001-12-23 14:15:58 +00:00
close(sock);
sock = -1;
2003-12-24 12:00:00 +00:00
WriteError("$Can't bind socket %s", spath);
2002-10-20 20:58:55 +00:00
die(MBERR_INIT_ERROR);
2001-12-23 14:15:58 +00:00
}
2004-12-29 12:39:47 +00:00
if (nodaemon)
printf("sockets created\n");
2001-12-23 14:15:58 +00:00
2006-02-13 19:26:30 +00:00
/*
* Setup IBC socket
*/
2006-02-15 19:56:26 +00:00
if (Run_IBC) {
myaddr_in.sin_family = AF_INET;
myaddr_in.sin_addr.s_addr = INADDR_ANY;
myaddr_in.sin_port = port;
Syslog('+', "IBC: listen on %s, port %d", inet_ntoa(myaddr_in.sin_addr), ntohs(myaddr_in.sin_port));
ibcsock = socket(AF_INET, SOCK_DGRAM, 0);
if (ibcsock == -1) {
WriteError("$IBC: can't create listen socket");
die(MBERR_INIT_ERROR);
}
2006-02-13 19:26:30 +00:00
2006-02-15 19:56:26 +00:00
if (bind(ibcsock, (struct sockaddr *)&myaddr_in, sizeof(struct sockaddr_in)) == -1) {
WriteError("$IBC: can't bind listen socket");
die(MBERR_INIT_ERROR);
}
2006-02-13 19:26:30 +00:00
2006-02-15 19:56:26 +00:00
srand(getpid());
resettime = time(NULL) + (time_t)86400;
}
2006-02-13 19:26:30 +00:00
2001-12-23 14:15:58 +00:00
/*
* The flag masterinit is set if a new config.data is created, this
* is true if mbtask is started the very first time. Then we run
* mbsetup init to create the default databases.
*/
if (masterinit) {
2003-12-22 19:40:21 +00:00
pw = getpwuid(getuid());
2001-12-23 14:15:58 +00:00
cmd = xstrcpy(pw->pw_dir);
cmd = xstrcat(cmd, (char *)"/bin/mbsetup");
launch(cmd, (char *)"init", (char *)"mbsetup", MBINIT);
free(cmd);
sleep(2);
masterinit = FALSE;
}
2004-12-29 12:39:47 +00:00
if (nodaemon)
printf("init nodelists\n");
2001-12-23 14:15:58 +00:00
initnl();
sem_set((char *)"scanout", TRUE);
2002-02-24 17:17:58 +00:00
if (!TCFG.max_tcp && !pots_lines && !isdn_lines) {
2003-12-24 12:00:00 +00:00
Syslog('?', "WARNING: this system cannot connect to other systems, check setup");
2002-02-24 17:17:58 +00:00
}
2003-12-22 19:40:21 +00:00
/*
* Run the scheduler
2003-12-22 19:40:21 +00:00
*/
scheduler();
2003-12-23 21:07:33 +00:00
die(SIGTERM);
2003-12-22 19:40:21 +00:00
}
/*
* Scheduler loop
2003-12-22 19:40:21 +00:00
*/
void scheduler(void)
2003-12-22 19:40:21 +00:00
{
2006-02-13 19:26:30 +00:00
struct passwd *pw;
int rlen, rc, running = 0, i, found, call_work = 0, len;
static int LOADhi = FALSE, oldmin = 70, olddo = 70, oldsec = 70, call_entry = MAXTASKS;
2006-05-22 12:09:15 +00:00
char *cmd = NULL, *opts, port[21], crbuf[512];
2006-02-13 19:26:30 +00:00
static char doing[32], buf[2048];
time_t now;
struct tm tm, utm;
2003-12-22 19:40:21 +00:00
#if defined(__linux__)
2006-02-13 19:26:30 +00:00
FILE *fp;
2003-12-22 19:40:21 +00:00
#endif
2006-02-13 19:26:30 +00:00
double loadavg[3];
pp_list *tpl;
struct pollfd pfd[3];
socklen_t sl;
struct sockaddr_in ffrom;
2003-12-22 19:40:21 +00:00
2006-05-22 12:09:15 +00:00
Syslog('+', "Starting scheduler loop");
2003-12-22 19:40:21 +00:00
pw = getpwuid(getuid());
2001-12-30 15:04:11 +00:00
/*
* Enter the mainloop (forever)
*/
2001-12-23 14:15:58 +00:00
do {
2006-02-13 19:26:30 +00:00
/*
* Poll UNIX Datagram socket and IBC UDP socket until the defined timeout of one second.
* This means we listen if a MBSE BBS client program has something to tell us.
* Timeout is one second, after the timeout the rest of the mainloop is executed.
2006-02-13 19:26:30 +00:00
*/
pfd[0].fd = sock;
pfd[0].events = POLLIN;
pfd[0].revents = 0;
pfd[1].fd = ping_isocket;
2006-02-13 19:26:30 +00:00
pfd[1].events = POLLIN;
pfd[1].revents = 0;
if (Run_IBC) {
pfd[2].fd = ibcsock;
pfd[2].events = POLLIN;
pfd[2].revents = 0;
}
if (Run_IBC)
rc = poll(pfd, 3, 1000);
else
rc = poll(pfd, 2, 1000);
2006-02-13 19:26:30 +00:00
if (rc == -1) {
/*
* Poll can be interrupted by a finished child so that's not a real error.
*/
if (errno != EINTR) {
Syslog('?', "$poll() rc=%d sock=%d, events=%04x", rc, sock, pfd[0].revents);
Syslog('?', "$poll() rc=%d sock=%d, events=%04x", rc, ibcsock, pfd[1].revents);
if (Run_IBC)
Syslog('?', "$poll() rc=%d sock=%d, events=%04x", rc, ping_isocket, pfd[2].revents);
2006-02-13 19:26:30 +00:00
}
} else if (rc) {
if (pfd[0].revents & POLLIN) {
/*
2006-05-22 12:09:15 +00:00
* Process the clients request for mbtask commands.
2006-02-13 19:26:30 +00:00
*/
memset(&buf, 0, sizeof(buf));
fromlen = sizeof(from);
rlen = recvfrom(sock, buf, sizeof(buf) -1, 0, (struct sockaddr *)&from, &fromlen);
if (rlen == -1) {
2006-05-22 12:09:15 +00:00
WriteError("$recvfrom() for command receiver");
2006-02-13 19:26:30 +00:00
} else {
do_cmd(buf);
}
}
if (pfd[1].revents & POLLIN || pfd[1].revents & POLLERR || pfd[1].revents & POLLHUP || pfd[1].revents & POLLNVAL) {
/*
* Ping reply received.
*/
sl = sizeof(ffrom);
if ((len = recvfrom(ping_isocket, &buf, sizeof(buf)-1, 0,(struct sockaddr *)&ffrom, &sl)) != -1) {
ping_receive(buf, len);
} else {
WriteError("$recvfrom() for ping receiver");
}
2006-02-13 19:26:30 +00:00
}
if (Run_IBC && (pfd[2].revents & POLLIN || pfd[2].revents & POLLERR ||
pfd[2].revents & POLLHUP || pfd[2].revents & POLLNVAL)) {
2006-05-22 12:09:15 +00:00
/*
* IBC chat command received.
*/
2006-02-13 19:26:30 +00:00
sl = sizeof(myaddr_in);
memset(&clientaddr_in, 0, sizeof(struct sockaddr_in));
memset(&crbuf, 0, sizeof(crbuf));
if ((len = recvfrom(ibcsock, &crbuf, sizeof(crbuf)-1, 0,(struct sockaddr *)&clientaddr_in, &sl)) != -1) {
ibc_receiver(crbuf);
} else {
WriteError("$recvfrom() for IBC receiver");
}
}
}
if (G_Shutdown)
2003-12-22 19:40:21 +00:00
break;
2001-08-17 05:46:24 +00:00
2001-12-23 14:15:58 +00:00
/*
* Check all registered connections and semafore's
*/
2006-02-15 19:56:26 +00:00
if (Run_IBC)
check_servers();
2001-12-23 14:15:58 +00:00
reg_check();
check_sema();
2002-02-24 12:56:14 +00:00
check_ports();
2006-02-13 19:26:30 +00:00
diskwatch();
check_ping();
2001-08-17 05:46:24 +00:00
2001-12-23 14:15:58 +00:00
/*
2002-02-22 21:15:21 +00:00
* Check the systems load average.
2001-12-23 14:15:58 +00:00
*/
2002-02-04 21:22:27 +00:00
Load = loadavg[0] = loadavg[1] = loadavg[2] = 0.0;
2004-12-28 15:30:52 +00:00
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
2002-02-04 20:37:01 +00:00
if (getloadavg(loadavg, 3) == 3) {
Load = loadavg[0];
}
2002-02-04 21:22:27 +00:00
#elif defined(__linux__)
2001-12-23 14:15:58 +00:00
if ((fp = fopen((char *)"/proc/loadavg", "r"))) {
2002-02-04 21:22:27 +00:00
if (fscanf(fp, "%lf %lf %lf", &loadavg[0], &loadavg[1], &loadavg[2]) == 3) {
2002-02-04 20:37:01 +00:00
Load = loadavg[0];
2002-02-04 21:22:27 +00:00
} else {
Syslog('-', "error");
2001-12-23 14:15:58 +00:00
}
fclose(fp);
}
2005-01-07 21:46:24 +00:00
#else
#error "Don't know how to get the loadaverage on this OS"
2002-02-04 20:37:01 +00:00
#endif
if (Load >= TCFG.maxload) {
if (!LOADhi) {
Syslog('!', "System load too high: %2.2f (%2.2f)", Load, TCFG.maxload);
2002-02-04 20:37:01 +00:00
LOADhi = TRUE;
}
} else {
if (LOADhi) {
Syslog('!', "System load normal: %2.2f (%2.2f)", Load, TCFG.maxload);
2002-02-04 20:37:01 +00:00
LOADhi = FALSE;
}
}
2001-08-17 05:46:24 +00:00
2001-12-23 14:15:58 +00:00
/*
* Report to the system monitor.
*/
memset(&doing, 0, sizeof(doing));
if ((running = checktasks(0)))
2005-08-29 21:03:28 +00:00
snprintf(doing, 32, "Run %d tasks", running);
2004-09-19 14:08:01 +00:00
else if (UPSdown)
2005-08-29 21:03:28 +00:00
snprintf(doing, 32, "UPS shutdown");
2001-12-23 14:15:58 +00:00
else if (UPSalarm)
2005-08-29 21:03:28 +00:00
snprintf(doing, 32, "UPS alarm");
2001-12-23 14:15:58 +00:00
else if (!s_bbsopen)
2005-08-29 21:03:28 +00:00
snprintf(doing, 32, "BBS is closed");
2001-12-23 14:15:58 +00:00
else if (Processing)
2005-08-29 21:03:28 +00:00
snprintf(doing, 32, "%s", waitmsg);
2001-12-23 14:15:58 +00:00
else
2005-08-29 21:03:28 +00:00
snprintf(doing, 32, "Overload %2.2f", Load);
2001-08-17 05:46:24 +00:00
2005-08-29 21:03:28 +00:00
snprintf(reginfo[0].doing, 36, "%s", doing);
2005-10-16 12:13:20 +00:00
reginfo[0].lastcon = (int)time(NULL);
/*
2001-12-23 14:15:58 +00:00
* Touch the mbtask.last semafore to prove this daemon
* is actually running.
2001-12-30 15:04:11 +00:00
* Reload configuration data if some file is changed.
*/
2001-12-23 14:15:58 +00:00
now = time(NULL);
2004-12-29 12:39:47 +00:00
localtime_r(&now, &tm);
gmtime_r(&now, &utm);
2004-12-29 12:39:47 +00:00
if (tm.tm_min != olddo) {
2001-12-30 15:04:11 +00:00
/*
* Each minute we execute this part
*/
2003-02-08 15:28:31 +00:00
if (tosswait)
tosswait--;
2004-12-29 12:39:47 +00:00
olddo = tm.tm_min;
2001-12-23 14:15:58 +00:00
TouchSema((char *)"mbtask.last");
if (file_time(tcfgfn) != tcfg_time) {
Syslog('+', "Task configuration changed, reloading");
2001-12-23 14:15:58 +00:00
load_taskcfg();
deinitnl();
initnl();
sem_set((char *)"scanout", TRUE);
2001-12-23 14:15:58 +00:00
}
if (file_time(cfgfn) != cfg_time) {
Syslog('+', "Main configuration changed, reloading");
2001-12-23 14:15:58 +00:00
load_maincfg();
deinitnl();
initnl();
sem_set((char *)"scanout", TRUE);
}
if (file_time(ttyfn) != tty_time) {
Syslog('+', "Ports configuration changed, reloading");
load_ports();
2002-02-22 21:15:21 +00:00
check_ports();
deinitnl();
initnl();
sem_set((char *)"scanout", TRUE);
2001-12-23 14:15:58 +00:00
}
/*
* If the next event time is reached, rescan the outbound
*/
2004-12-29 12:39:47 +00:00
if ((utm.tm_hour == nxt_hour) && (utm.tm_min == nxt_min)) {
Syslog('+', "It is now %02d:%02d UTC, starting new event", utm.tm_hour, utm.tm_min);
sem_set((char *)"scanout", TRUE);
}
}
2002-06-05 19:30:31 +00:00
/*
* Check system processing state
*/
2001-12-23 14:15:58 +00:00
if (s_bbsopen && !UPSalarm && !LOADhi) {
2002-06-05 19:30:31 +00:00
if (!Processing) {
Syslog('+', "Resuming normal operations");
2002-06-05 19:30:31 +00:00
Processing = TRUE;
}
} else {
if (Processing) {
Syslog('+', "Suspending operations");
2002-06-05 19:30:31 +00:00
Processing = FALSE;
}
}
2001-12-23 14:15:58 +00:00
2002-06-06 19:46:44 +00:00
/*
* Check Pause Timer, make sure it's only checked
* once each second. Also do pingcheck.
*/
2004-12-29 12:39:47 +00:00
if (tm.tm_sec != oldsec) {
oldsec = tm.tm_sec;
2002-06-06 19:46:44 +00:00
if (ptimer)
ptimer--;
}
2002-06-05 19:30:31 +00:00
if (Processing) {
2001-12-23 14:15:58 +00:00
/*
* Here we run all normal operations.
*/
2001-12-30 15:04:11 +00:00
running = checktasks(0);
2001-12-23 14:15:58 +00:00
if (s_mailout && (!ptimer) && (!runtasktype(MBFIDO))) {
2006-02-13 19:26:30 +00:00
launch(TCFG.cmd_mailout, NULL, (char *)"mailout", MBFIDO);
running = checktasks(0);
s_mailout = FALSE;
2001-12-23 14:15:58 +00:00
}
if (s_mailin && (!ptimer) && (!runtasktype(MBFIDO))) {
2003-02-08 15:28:31 +00:00
/*
* Here we should check if no mailers are running. Only start
* processing the inbound if no mailers are running, but on busy
* systems this may hardly be the case. So we wait for 30 minutes
* and if there are still mailers running, mbfido is started
* anyway.
*/
if ((ipmailers + runtasktype(CM_ISDN) + runtasktype(CM_POTS)) == 0) {
Syslog('i', "Mailin, no mailers running, start direct");
tosswait = TOSSWAIT_TIME;
2006-02-13 19:26:30 +00:00
launch(TCFG.cmd_mailin, NULL, (char *)"mailin", MBFIDO);
running = checktasks(0);
s_mailin = FALSE;
2006-01-29 16:47:32 +00:00
} else {
Syslog('i', "Mailin, tosswait=%d", tosswait);
if (tosswait == 0) {
2006-02-13 19:26:30 +00:00
launch(TCFG.cmd_mailin, NULL, (char *)"mailin", MBFIDO);
running = checktasks(0);
s_mailin = FALSE;
2006-01-29 16:47:32 +00:00
}
2003-02-08 15:28:31 +00:00
}
2001-12-23 14:15:58 +00:00
}
if (s_newnews && (!ptimer) && (!runtasktype(MBFIDO))) {
2006-02-13 19:26:30 +00:00
launch(TCFG.cmd_newnews, NULL, (char *)"newnews", MBFIDO);
running = checktasks(0);
s_newnews = FALSE;
2001-12-23 14:15:58 +00:00
}
/*
* Only run the nodelist compiler if nothing else
* is running. There's no hurry to compile the
* new lists. If more then one compiler is defined,
* start them in parallel.
*/
if (s_index && (!ptimer) && (!running)) {
2006-01-29 16:47:32 +00:00
if (strlen(TCFG.cmd_mbindex1)) {
2006-02-13 19:26:30 +00:00
launch(TCFG.cmd_mbindex1, NULL, (char *)"compiler 1", MBINDEX);
2006-01-29 16:47:32 +00:00
}
if (strlen(TCFG.cmd_mbindex2)) {
2006-02-13 19:26:30 +00:00
launch(TCFG.cmd_mbindex2, NULL, (char *)"compiler 2", MBINDEX);
2006-01-29 16:47:32 +00:00
}
if (strlen(TCFG.cmd_mbindex3)) {
2006-02-13 19:26:30 +00:00
launch(TCFG.cmd_mbindex3, NULL, (char *)"compiler 3", MBINDEX);
2006-01-29 16:47:32 +00:00
}
2001-12-23 14:15:58 +00:00
running = checktasks(0);
s_index = FALSE;
}
/*
* Linking messages is also only done when there is
* nothing else to do.
*/
if (s_msglink && (!ptimer) && (!running)) {
2006-02-13 19:26:30 +00:00
launch(TCFG.cmd_msglink, NULL, (char *)"msglink", MBFIDO);
2001-12-23 14:15:58 +00:00
running = checktasks(0);
s_msglink = FALSE;
}
/*
2001-12-30 15:04:11 +00:00
* Creating filerequest indexes, also only if nothing to do.
2001-12-23 14:15:58 +00:00
*/
if (s_reqindex && (!ptimer) && (!running)) {
2006-02-13 19:26:30 +00:00
launch(TCFG.cmd_reqindex, NULL, (char *)"reqindex", MBFILE);
2001-12-23 14:15:58 +00:00
running = checktasks(0);
s_reqindex = FALSE;
}
2002-06-05 19:30:31 +00:00
} /* if (Processing) */
2001-08-17 05:46:24 +00:00
2004-12-29 12:39:47 +00:00
if ((tm.tm_sec / SLOWRUN) != oldmin) {
2001-08-17 05:46:24 +00:00
2002-06-05 19:30:31 +00:00
/*
* These tasks run once per 20 seconds.
*/
2004-12-29 12:39:47 +00:00
oldmin = tm.tm_sec / SLOWRUN;
2002-06-05 19:30:31 +00:00
if (Processing) {
2001-08-17 05:46:24 +00:00
/*
* Update outbound status if needed.
*/
2002-02-24 13:52:13 +00:00
if (rescan) {
rescan = FALSE;
outstat();
2002-02-24 13:52:13 +00:00
call_work = check_calllist();
}
/*
* Launch the systems to call, start one system each time.
* Set the safety counter to MAXTASKS + 1, this forces that
* the counter really will advance to the next node in case
* of failing sessions.
*/
i = MAXTASKS + 1;
found = FALSE;
if (call_work) {
while (TRUE) {
/*
* Rotate the call entries
*/
if (call_entry == MAXTASKS)
call_entry = 0;
else
call_entry++;
2002-01-27 22:33:46 +00:00
/*
* If a valid entry, and not yet calling, and the retry time is reached,
* then launch a callprocess for this node.
*/
if (calllist[call_entry].addr.zone && !calllist[call_entry].calling &&
2005-10-16 12:13:20 +00:00
(calllist[call_entry].cst.trytime < (int)now)) {
2002-03-23 13:12:29 +00:00
if ((calllist[call_entry].callmode == CM_INET) && (ipmailers < TCFG.max_tcp) && internet) {
found = TRUE;
break;
}
2002-02-24 17:17:58 +00:00
if ((calllist[call_entry].callmode == CM_ISDN) && (runtasktype(CM_ISDN) < isdn_free)) {
found = TRUE;
break;
}
2002-02-24 17:17:58 +00:00
if ((calllist[call_entry].callmode == CM_POTS) && (runtasktype(CM_POTS) < pots_free)) {
found = TRUE;
break;
}
}
/*
* Safety counter, if all systems are already calling, we should
* never break out of this loop anymore.
*/
i--;
if (!i)
break;
}
if (found) {
cmd = xstrcpy(pw->pw_dir);
cmd = xstrcat(cmd, (char *)"/bin/mbcico");
/*
* For ISDN or POTS, select a free tty device.
*/
switch (calllist[call_entry].callmode) {
case CM_ISDN: for (tpl = pl; tpl; tpl = tpl->next) {
if (!tpl->locked && (tpl->dflags & calllist[call_entry].diflags)) {
2005-08-29 21:03:28 +00:00
snprintf(port, 21, "-l %s ", tpl->tty);
break;
}
}
break;
case CM_POTS: for (tpl = pl; tpl; tpl = tpl->next) {
if (!tpl->locked && (tpl->mflags & calllist[call_entry].moflags)) {
2005-08-29 21:03:28 +00:00
snprintf(port, 21, "-l %s ", tpl->tty);
break;
}
}
break;
default: port[0] = '\0';
break;
}
2006-05-22 12:09:15 +00:00
opts = calloc(41, sizeof(char));
2004-01-20 20:02:42 +00:00
if (calllist[call_entry].addr.point) {
2005-08-29 21:03:28 +00:00
snprintf(opts, 41, "%sp%u.f%u.n%u.z%u.%s", port, calllist[call_entry].addr.point,
calllist[call_entry].addr.node, calllist[call_entry].addr.net,
calllist[call_entry].addr.zone, calllist[call_entry].addr.domain);
2004-01-20 20:02:42 +00:00
} else {
2005-09-11 13:07:42 +00:00
snprintf(opts, 41, "%sf%u.n%u.z%u.%s", port, calllist[call_entry].addr.node,
calllist[call_entry].addr.net,
calllist[call_entry].addr.zone, calllist[call_entry].addr.domain);
2004-01-20 20:02:42 +00:00
}
2006-02-13 19:26:30 +00:00
calllist[call_entry].taskpid = launch(cmd, opts, (char *)"mbcico", calllist[call_entry].callmode);
if (calllist[call_entry].taskpid)
calllist[call_entry].calling = TRUE;
running = checktasks(0);
2002-02-24 13:52:13 +00:00
rescan = TRUE;
2006-05-22 12:09:15 +00:00
free(opts);
free(cmd);
cmd = NULL;
}
}
2002-06-05 19:30:31 +00:00
} /* if (Processing) */
} /* if ((tm->tm_sec / SLOWRUN) != oldmin) */
} while (! G_Shutdown);
2003-12-22 19:40:21 +00:00
Syslog('+', "Scheduler stopped");
2001-08-17 05:46:24 +00:00
}
int main(int argc, char **argv)
{
2003-01-27 21:55:42 +00:00
struct passwd *pw;
2003-08-03 14:08:07 +00:00
char *lockfile;
int i, chatport = 0;
2003-01-27 21:55:42 +00:00
pid_t frk;
FILE *fp;
2006-02-13 19:26:30 +00:00
struct servent *se;
2001-08-17 05:46:24 +00:00
2003-01-27 21:55:42 +00:00
/*
* Print copyright notices and setup logging.
*/
printf("MBTASK: MBSE BBS v%s Task Manager Daemon\n", VERSION);
printf(" %s\n\n", COPYRIGHT);
2001-08-17 05:46:24 +00:00
2003-01-27 21:55:42 +00:00
/*
* Catch all the signals we can, and ignore the rest. Note that SIGKILL can't be ignored
* but that's live. This daemon should only be stopped by SIGTERM.
*/
for (i = 0; i < NSIG; i++) {
2004-12-29 12:39:47 +00:00
if ((i == SIGHUP) || (i == SIGPIPE) || (i == SIGBUS) || (i == SIGILL) || (i == SIGSEGV))
2003-01-27 21:55:42 +00:00
signal(i, (void (*))die);
2003-12-23 21:07:33 +00:00
else if ((i == SIGINT) || (i == SIGTERM))
signal(i, (void (*))start_shutdown);
else
signal(i, SIG_IGN);
2003-01-27 21:55:42 +00:00
}
2001-08-17 05:46:24 +00:00
/*
* Secret undocumented startup switch, ie: no help available.
*/
if ((argc == 2) && (strcmp(argv[1], "-nd") == 0)) {
nodaemon = TRUE;
}
2004-12-29 12:39:47 +00:00
init_pingsocket();
2003-01-27 21:55:42 +00:00
/*
* mbtask is setuid root, drop privileges to user mbse.
* This will stay forever like this, no need to become
* root again. The child can't even become root anymore.
*/
pw = getpwnam((char *)"mbse");
if (setuid(pw->pw_uid)) {
perror("");
fprintf(stderr, "can't setuid to mbse\n");
close(ping_isocket);
exit(MBERR_INIT_ERROR);
}
/*
* If running in the foreground under valgrind the next call fails.
* Developers should know what they are doing so we are not bailing out.
*/
2003-01-27 21:55:42 +00:00
if (setgid(pw->pw_gid)) {
perror("");
fprintf(stderr, "can't setgid to bbs\n");
if (! nodaemon) {
close(ping_isocket);
exit(MBERR_INIT_ERROR);
}
2003-01-27 21:55:42 +00:00
}
2001-08-17 05:46:24 +00:00
2003-01-27 21:55:42 +00:00
umask(007);
if (locktask(pw->pw_dir)) {
close(ping_isocket);
exit(MBERR_NO_PROGLOCK);
}
2001-08-17 05:46:24 +00:00
2005-08-29 21:03:28 +00:00
snprintf(cfgfn, PATH_MAX, "%s/etc/config.data", getenv("MBSE_ROOT"));
2003-01-27 21:55:42 +00:00
load_maincfg();
2004-12-29 12:39:47 +00:00
if (nodaemon)
printf("main config loaded\n");
mypid = getpid();
2004-12-29 12:39:47 +00:00
if (nodaemon)
printf("my pid is %d\n", mypid);
2003-01-27 21:55:42 +00:00
Syslog(' ', " ");
Syslog(' ', "MBTASK v%s", VERSION);
2004-12-29 12:39:47 +00:00
if (nodaemon)
Syslog('+', "Starting in no-daemon mode");
2005-08-29 21:03:28 +00:00
snprintf(tcfgfn, PATH_MAX, "%s/etc/task.data", getenv("MBSE_ROOT"));
2003-01-27 21:55:42 +00:00
load_taskcfg();
2005-08-29 21:03:28 +00:00
2003-01-27 21:55:42 +00:00
status_init();
2001-08-25 19:53:11 +00:00
2006-02-15 19:56:26 +00:00
if ((se = getservbyname("fido", "udp")) == NULL) {
WriteError("IBC: no fido udp entry in /etc/services, cannot start Internet BBS Chat");
Run_IBC = FALSE;
} else {
chatport = se->s_port;
if (strlen(CFG.bbs_name) == 0) {
WriteError("IBC: mbsetup 1.2.1 is empty, cannot start Internet BBS Chat");
Run_IBC = FALSE;
} else if (strlen(CFG.myfqdn) == 0) {
Run_IBC = FALSE;
WriteError("IBC: mbsetup 1.2.10 is empty, cannot start Internet BBS Chat");
}
2006-02-15 19:56:26 +00:00
}
2003-01-27 21:55:42 +00:00
memset(&task, 0, sizeof(task));
memset(&reginfo, 0, sizeof(reginfo));
memset(&calllist, 0, sizeof(calllist));
2005-08-29 21:03:28 +00:00
snprintf(spath, PATH_MAX, "%s/tmp/mbtask", getenv("MBSE_ROOT"));
snprintf(ttyfn, PATH_MAX, "%s/etc/ttyinfo.data", getenv("MBSE_ROOT"));
2003-01-27 21:55:42 +00:00
initnl();
load_ports();
check_ports();
2003-03-24 19:44:38 +00:00
chat_init();
2006-05-25 16:37:52 +00:00
ibc_init();
2001-08-17 05:46:24 +00:00
2003-01-27 21:55:42 +00:00
/*
* Now that init is complete and this program is locked, it is
* safe to remove a stale socket if it is there after a crash.
*/
if (!file_exist(spath, R_OK))
unlink(spath);
2001-08-17 05:46:24 +00:00
if (nodaemon) {
/*
* For debugging, run in foreground mode
*/
mypid = getpid();
2004-12-29 12:39:47 +00:00
printf("init complete, starting scheduler ...\n");
start_scheduler(chatport);
} else {
/*
* Server initialization is complete. Now we can fork the
* daemon and return to the user. We need to do a setpgrp
* so that the daemon will no longer be assosiated with the
* users control terminal. This is done before the fork, so
* that the child will not be a process group leader. Otherwise,
* if the child were to open a terminal, it would become
* associated with that terminal as its control terminal.
*/
if ((pgrp = setpgid(0, 0)) == -1) {
Syslog('?', "$setpgid failed");
die(MBERR_INIT_ERROR);
}
2003-01-27 21:55:42 +00:00
frk = fork();
switch (frk) {
case -1:
Syslog('?', "$Unable to fork daemon");
die(MBERR_INIT_ERROR);
case 0:
/*
* Starting the deamon child process here.
*/
fclose(stdin);
if (open("/dev/null", O_RDONLY) != 0) {
Syslog('?', "$Reopen of stdin to /dev/null failed");
_exit(MBERR_EXEC_FAILED);
}
fclose(stdout);
if (open("/dev/null", O_WRONLY | O_APPEND | O_CREAT,0600) != 1) {
Syslog('?', "$Reopen of stdout to /dev/null failed");
_exit(MBERR_EXEC_FAILED);
}
fclose(stderr);
if (open("/dev/null", O_WRONLY | O_APPEND | O_CREAT,0600) != 2) {
Syslog('?', "$Reopen of stderr to /dev/null failed");
_exit(MBERR_EXEC_FAILED);
}
mypid = getpid();
start_scheduler(chatport);
/* Not reached */
default:
/*
* Here we detach this process and let the child
* run the deamon process. Put the child's pid
* in the lockfile before leaving.
*/
lockfile = calloc(PATH_MAX, sizeof(char));
2005-08-29 21:03:28 +00:00
snprintf(lockfile, PATH_MAX, "%s/var/run/mbtask", pw->pw_dir);
if ((fp = fopen(lockfile, "w"))) {
fprintf(fp, "%10u\n", frk);
fclose(fp);
}
free(lockfile);
Syslog('+', "Starting daemon with pid %d", frk);
exit(MBERR_OK);
}
2003-01-27 21:55:42 +00:00
}
/*
2006-05-22 12:09:15 +00:00
* Not reached in daemon mode.
2003-01-27 21:55:42 +00:00
*/
return 0;
2001-08-17 05:46:24 +00:00
}