u-isdn/isdn_4/util.c

371 lines
7.0 KiB
C

/*
* This file is part of the ISDN master program.
*
* Copyright (C) 1995 Matthias Urlichs.
* See the file COPYING for license details.
*/
#include "master.h"
/* If we could assume it'd work right without any memory,
we might die cleanly, like AT/Q does. Maybe sometime in the future.
Thus, DO NOT assume xmalloc aborts; it may still return NULL. */
void *
xmalloc(size_t sz)
{
void *foo;
foo = malloc(sz);
if(foo == NULL) {
syslog(LOG_CRIT,"No memory for %d bytes! Dying!\n",sz);
abort();
}
return foo;
}
void *
gxmalloc(size_t sz)
{
void *foo;
foo = gmalloc(sz);
if(foo == NULL) {
syslog(LOG_CRIT,"No memory for %d bytes! Dying!\n",sz);
abort();
}
return foo;
}
void *
gcxmalloc(size_t sz)
{
void *foo;
foo = gcmalloc(sz);
if(foo == NULL) {
syslog(LOG_CRIT,"No memory for %d bytes! Dying!\n",sz);
abort();
}
return foo;
}
void *
gbxmalloc(size_t sz)
{
void *foo;
foo = gbmalloc(sz);
if(foo == NULL) {
syslog(LOG_CRIT,"No memory for %d bytes! Dying!\n",sz);
abort();
}
return foo;
}
/* Too many strings to keep track of, no time for garbage collection. */
/* Enter them in a binary tree... */
/* str_enter MUST NOT be called while any string in the tree is temporarily
modified. No string in the tree may be permanently modified in ANY way. */
/* Actually, with GC enabled this gets a whole lot simpler. */
char *str_enter(char *master)
{
#ifdef DO_GC
char *foo = gbxmalloc(strlen(master)+1);
strcpy(foo,master);
return foo;
#else
struct string **str = &stringdb;
struct string *st = *str;
if(master == NULL)
return NULL;
while(st != NULL) {
int sc;
if(st->data == master)
return master;
sc = strcmp(master,st->data);
if(sc == 0)
return st->data;
else if(sc < 0)
str = &st->left;
else
str = &st->right;
st = *str;
}
st = xmalloc(sizeof(struct string)+strlen(master));
if(st == NULL)
return NULL;
GrabStrs++;
strcpy(st->data,master);
st->left = st->right = NULL;
*str = st;
chkone(st);
return st->data;
#endif
}
/* Simpleminded, bidirectional wildmat().
If both strings are patterns, this doesn't work. Unfortunately, pattern
joining is obviously NP-complete, and I don't know any algorithms to do it
anyway. */
char *wildmatch(char *a, char *b)
{
if(a == NULL)
return b;
else if(b == NULL)
return a;
else if(wildmat(a,b) > 0)
return a;
else if(wildmat(b,a) > 0)
return b;
else
return NULL;
}
ulong_t
maskmatch(ulong_t a, ulong_t b)
{
return a & b;
}
/* Given a string aaa+bbb, return aaa. */
char *
strippat(char *a)
{
char aa[30];
char *aplus = strchr(a,'+');
if(aplus == NULL)
return a;
*aplus = '\0';
strcpy(aa,a);
*aplus = '+';
return str_enter(aa);
}
/* Given strings +aaa+bbb and +ccc+aaa, return +aaa+bbb+ccc. */
static char *
pluscat(char *a, char *b)
{
if(a == NULL)
return b;
if(b == NULL)
return a;
if(*a != '+')
return b;
if(*b != '+')
return a;
{
char classpat[50];
char *classind = classpat;
strcpy(classpat,a);
while(*classind) {
if(*classind == '+')
*classind = '\0';
classind++;
}
{
char *bnext = b;
do {
b = bnext + 1;
bnext = strchr(b,'+');
if(bnext != NULL) *bnext = '\0';
for(a = classpat+1; a < classind; a += strlen(a)+1)
if(strcmp(a,b) == 0)
break;
if(a >= classind) {
strcpy(classind+1,b);
classind += strlen(b)+1;
}
if(bnext != NULL) *bnext = '+';
} while(bnext != NULL);
for(a = classpat; a < classind; a += strlen(a))
*a++ = '+';
*a = '\0';
return str_enter(classpat);
}
}
}
/* "abc" "bcd" -> "bc" */
/* "abc+bc" "bcd+b" -> "bc+bc+b" */
/* "abc+bc" "bcd+d" -> NULL */
/* It is of course possible to optimize all of this, but it's not worth the
work. */
char *
classmatch(char *a, char *b)
{
if(a == NULL)
return NULL;
if(b == NULL)
return NULL;
if(*b == '*' || *b == '\0')
return a;
if(*a == '*' || *a == '\0')
return b;
if(*a == '+' || *b == '+') {
if(*a == '+' && *b == '+') {
char classpat[50];
if(strcmp(a,b) == 0)
return a;
strcpy(classpat,a);
strcat(classpat,b);
return str_enter(classpat);
} else {
char classpat[50], *classend = classpat;
char *aorig,*bplus;
if(*a != '+') {
char *tmp = a; a = b; b = tmp;
}
if((bplus=strchr(b,'+')) != NULL) *bplus='\0';
strcpy(classpat,b); classend = classpat+strlen(b);
aorig = a;
do {
char *thisa = a;
while(*++a != '\0' && *a != '+') {
if(strchr(b,*a) != NULL) {
while(thisa < a) {
if(strchr(b,*thisa) != NULL)
*classend++ = *thisa;
thisa++;
}
goto cont;
}
}
if(bplus != NULL) *bplus='+';
return NULL;
cont:;
} while((a = strchr(a,'+')) != NULL);
if(bplus != NULL) *bplus='+';
*classend = '\0';
strcat(classpat,pluscat(aorig,bplus));
return str_enter(classpat);
}
} else {
char classpat[30];
char *classind = classpat;
char *aplus, *bplus;
if((aplus=strchr(a,'+')) != NULL) *aplus='\0';
if((bplus=strchr(b,'+')) != NULL) *bplus='\0';
while(*a != 0) {
if(strchr(b,*a) != NULL)
*classind++ = *a;
a++;
}
if(aplus != NULL) *aplus='+';
if(bplus != NULL) *bplus='+';
if(classpat == classind)
return NULL;
*classind = 0;
/* If the class is one character long, there's not much point
in carrying around all the baggage. */
if((classind > classpat+1) && (aplus != NULL || bplus != NULL))
return classmatch(str_enter(classpat),pluscat(aplus,bplus));
else
return str_enter(classpat);
}
}
/* Put something into the environment. */
void
putenv2 (const char *key, const char *val)
{
char *xx = (char *)xmalloc (strlen (key) + strlen (val) + 2);
if (xx != NULL) {
sprintf (xx, "%s=%s", key, val);
putenv (xx);
}
}
void Xbreak(void) { }
void
xquit (const char *s, const char *t)
{
if (s != NULL)
syslog (LOG_WARNING, "%s %s: %m", s, t ? t : "");
abort();
}
void panic(const char *x, ...)
{
*((char *)0xdeadbeef) = 0; /* Crash */
}
void
dropdead(void)
{
if(zzconn != NULL && zzconn->cg != NULL)
syslog(LOG_ERR, "Startup of %s:%s cancelled -- timeout",zzconn->cg->site,zzconn->cg->protocol);
else
syslog(LOG_ERR, "Startup cancelled because of a timeout!");
exit(9);
}
void
log_idle (void *xxx)
{
static time_t started = 0;
char repbuf[80];
struct tm *tm;
time_t now;
int nc1=0,nc2=0,nc3=0;
struct conninfo *conn;
for(conn = isdn4_conn; conn != NULL; conn = conn->next) {
if(conn->ignore)
continue;
if(conn->state < c_down)
continue;
else if(conn->state == c_up)
nc1++;
else if(conn->state == c_down)
nc3++;
else
nc2++;
}
if(started == 0)
started = time(NULL);
now = time(NULL);
tm = localtime(&now);
now = (now - started) / 60;
sprintf(repbuf,"#%d %02d:%02d %d,%d,%d G:%d/%d+%d", (int)now, tm->tm_hour,tm->tm_min,nc1,nc2,nc3,GrabAllocs,GrabFrees,GrabStrs);
connreport(repbuf,"*",0);
if(!(now % 5))
syslog (LOG_DEBUG, "ISDN is alive; %d minutes.",(int)now);
timeout (log_idle, NULL, 60 * HZ);
}
void
queue_idle (void *xxx)
{
runqueues ();
timeout (queue_idle, NULL, HZ);
}
void
alarmsig(void)
{
printf("Dead");
}
void
do_quitnow(void *nix)
{
quitnow = 1;
kill_progs(NULL);
}