|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T f
Length: 16867 (0x41e3)
Types: TextFile
Names: »filtercont.c«
└─⟦2d1937cfd⟧ Bits:30007241 EUUGD22: P.P 5.0
└─⟦dc59850a2⟧ »EurOpenD22/pp5.0/pp-5.tar.Z«
└─⟦e5a54fb17⟧
└─⟦this⟧ »pp-5.0/Chans/filtercontrol/filtercont.c«
/* filtercont.c: filter control channel */
# ifndef lint
static char Rcsid[] = "@(#)$Header: /cs/research/pp/hubris/pp-beta/Chans/filtercontrol/RCS/filtercont.c,v 5.0 90/09/20 15:48:12 pp Exp Locker: pp $";
# endif
/*
* $Header: /cs/research/pp/hubris/pp-beta/Chans/filtercontrol/RCS/filtercont.c,v 5.0 90/09/20 15:48:12 pp Exp Locker: pp $
*
* $Log: filtercont.c,v $
* Revision 5.0 90/09/20 15:48:12 pp
* rcsforce : 5.0 public release
*
*/
#include "util.h"
#include "retcode.h"
#include "expand.h"
#include "qmgr.h"
#include "q.h"
#include "prm.h"
#include <sys/stat.h>
#include <sys/file.h>
#include <sys/wait.h>
#include <signal.h>
extern char *mquedir;
extern char *quedfldir;
extern char *formdfldir;
extern char *logdfldir;
extern CHAN *ch_nm2struct();
extern char *expand_dyn ();
extern void err_abrt(), rd_end(), sys_init(), arg2vstr();
CHAN *mychan;
char *this_msg = NULL, *this_chan = NULL;
char *none_str = "none";
static struct type_Qmgr_DeliveryStatus *process ();
static int processMsg ();
static int doFormat ();
static int is_mychan_file ();
static int hdrinlist ();
static int in_BPT ();
static int file_create ();
static int do_child_logging ();
static int file_link ();
static int initialise ();
static int security_check ();
static void dirinit ();
static struct type_Qmgr_DeliveryStatus *new_DeliveryStatus();
static ADDR *getnthrecip ();
int first_failureDR;
int value;
char *error, buf[BUFSIZ];
/* \f
*/
/* main routine */
main (argc, argv)
int argc;
char **argv;
{
sys_init(argv[0]);
dirinit ();
#ifdef PP_DEBUG
if (argc>1 && (strcmp(argv[1],"debug") == 0))
debug_channel_control(argc,argv,initialise,process, NULLIFP);
else
#endif
channel_control (argc, argv, initialise, process, NULLIFP);
}
/* \f
*/
/* routine to move to correct place in file system */
static void dirinit ()
{
if (chdir (quedfldir) < 0)
err_abrt (RP_LIO, " Unable to change directory to '%s'",
quedfldir);
}
/* \f
*/
/* channel initialise routine */
static int initialise (arg)
struct type_Qmgr_Channel *arg;
{
char *name;
name = qb2str(arg);
if ((mychan = ch_nm2struct(name)) == NULLCHAN) {
PP_OPER(NULLCP, ("Chan/filtercont : Channel '%s' not known",name));
if (name != NULL) free(name);
return NOTOK;
}
(void) signal (SIGCHLD, SIG_DFL);
/* check if a filter channel */
if (name != NULL) free(name);
return OK;
}
/* \f
*/
/* routine to check if allowed to filter this message through this channel */
static int security_check (msg)
struct type_Qmgr_ProcMsg *msg;
{
char *msg_file = NULL, *msg_chan = NULL;
int result;
result = TRUE;
msg_file = qb2str (msg->qid);
msg_chan = qb2str (msg->channel);
if ((mychan == NULLCHAN) || (strcmp(msg_chan,mychan->ch_name) != 0)) {
PP_LOG(LLOG_EXCEPTIONS,
("Chans/fcontrol channel err: '%s'",msg_chan));
result = FALSE;
}
/* free all storage used */
if (msg_file != NULL) free(msg_file);
if (msg_chan != NULL) free(msg_chan);
return result;
}
/* \f
*/
/* routine called to do filter */
Expand expand_macros[] = {
"sender", NULLCP,
"822sender", NULLCP,
"400sender", NULLCP,
"qid", NULLCP,
"ua-id", NULLCP,
"p1-id", NULLCP,
"recip", NULLCP,
"822recip", NULLCP,
"400recip", NULLCP,
"table", NULLCP,
"outmta", NULLCP,
NULLCP, NULLCP};
static struct type_Qmgr_DeliveryStatus *process (arg)
struct type_Qmgr_ProcMsg *arg;
{
struct prm_vars prm;
Q_struct que;
ADDR *sender = NULL;
ADDR *recips = NULL;
int rcount;
struct type_Qmgr_UserList *ix;
ADDR *adr;
bzero((char *) &que,sizeof(que));
bzero((char *) &prm,sizeof(prm));
delivery_init(arg->users);
delivery_setall(int_Qmgr_status_messageFailure);
first_failureDR = TRUE;
if (security_check(arg) != TRUE)
return deliverystate;
if (this_msg != NULL) free(this_msg);
if (this_chan != NULL) free(this_chan);
this_msg = qb2str(arg->qid);
this_chan = qb2str(arg->channel);
PP_LOG(LLOG_NOTICE,
("%s formatting msg '%s'",mychan->ch_name,this_msg));
if (rp_isbad(rd_msg(this_msg,&prm,&que,&sender,&recips,&rcount))) {
PP_LOG(LLOG_EXCEPTIONS,
("%s rd_msg err: '%s'",mychan->ch_name,this_msg));
rd_end();
return delivery_setallstate(int_Qmgr_status_messageFailure,
"Can't read message");
}
expand_macros[0].expansion = que.Oaddress->ad_value;
expand_macros[1].expansion = que.Oaddress->ad_r822adr;
expand_macros[2].expansion = que.Oaddress->ad_r400adr;
expand_macros[3].expansion = this_msg;
expand_macros[4].expansion = que.ua_id;
expand_macros[5].expansion = que.msgid.mpduid_string;
if (mychan->ch_table != NULLTBL)
expand_macros[9].expansion = mychan->ch_table->tb_name;
else
expand_macros[9].expansion = none_str;
if (arg->users == NULL)
PP_LOG(LLOG_NOTICE,
("%s : passed a NULL user list for message '%s'",
mychan->ch_name,
this_msg));
/* check each recipient for processing */
for (ix = arg->users; ix; ix = ix->next) {
error = NULLCP;
if ((adr = getnthrecip(&que,ix->RecipientId->parm)) == NULL) {
PP_LOG(LLOG_EXCEPTIONS,
("%s : failed to find recipient %d of msg '%s'",mychan->ch_name,ix->RecipientId->parm, this_msg));
delivery_setstate(ix->RecipientId->parm,
int_Qmgr_status_messageFailure,
"Unable to find specified recipient");
continue;
}
switch(chan_acheck (adr, mychan, 1, (char **)NULL)) {
case OK:
expand_macros[6].expansion = adr -> ad_value;
expand_macros[7].expansion = adr -> ad_r822adr;
expand_macros[8].expansion = adr -> ad_r400adr;
if (adr -> ad_outchan
&& adr -> ad_outchan -> li_mta)
expand_macros[10].expansion = adr -> ad_outchan -> li_mta;
else
expand_macros[10].expansion = none_str;
value = int_Qmgr_status_messageFailure;
if (processMsg(this_msg,adr) == NOTOK) {
PP_LOG(LLOG_EXCEPTIONS,
("%s : failed to process msg '%s' for recip '%d' on channel '%s'",mychan->ch_name,this_msg, adr->ad_no, this_chan));
delivery_setstate(adr->ad_no,
value,
(error == NULLCP) ? "Problems with filtering" : error);
} else {
/* CHANGE update adr->ad_rcnt in struct and in file */
PP_LOG(LLOG_NOTICE,
("%s : processed '%s' for recipient %d",mychan->ch_name,this_msg,adr->ad_no));
adr->ad_rcnt++;
wr_ad_rcntno(adr,adr->ad_rcnt);
delivery_set(adr->ad_no,int_Qmgr_status_success);
}
break;
default:
break;
}
if (error != NULLCP)
free(error);
}
rd_end();
return deliverystate;
}
/* \f
*/
static int processMsg (msg,recip)
/* returns OK if managed to process msg for recip on mychan */
char *msg;
ADDR *recip;
{
char *origdir = NULL,
*newdir = NULL;
int result = OK;
struct stat statbuf;
if (qid2dir(msg, recip, TRUE, &origdir) != OK) {
PP_LOG(LLOG_EXCEPTIONS,
("%s original directory not found for recipient %d of message '%s'",mychan->ch_name,recip->ad_no, msg));
error = strdup("Unable to find original directory");
result = NOTOK;
}
/* temp change so as to get new directory name */
recip->ad_rcnt++;
if ((result == OK)
&& (qid2dir(msg, recip, FALSE, &newdir) != OK)) {
PP_LOG(LLOG_EXCEPTIONS,
("%s couldn't construct new directory for recipient '%d' of message '%s'",mychan->ch_name,recip->ad_no, msg));
error = strdup ("Unable to construct new directory");
result = NOTOK;
}
recip->ad_rcnt--;
if ((result == OK)
&& (stat(newdir, &statbuf) == OK)
&& ((statbuf.st_mode & S_IFMT) == S_IFDIR)) {
/* directory already exists and so reformatting already done */
PP_LOG(LLOG_NOTICE,
("%s : work already done for recipient %d of message '%s'",mychan->ch_name,recip->ad_no, msg));
if (origdir != NULL) free(origdir);
if (newdir != NULL) free(newdir);
return OK;
}
if ((result == OK) && (doFormat(origdir,newdir,msg) != OK))
result = NOTOK;
if (origdir != NULL) free(origdir);
if (newdir != NULL) free(newdir);
return result;
}
/* \f
*/
static int doFormat (orig, new, msg)
/* reformats orig directory contents to new directory through mychan */
char *orig, /* original directory */
*new, /* new directory */
*msg; /* message */
{
char tmpdir[FILNSIZE],
newfile[FILNSIZE],
*stripped_file,
*origfile,
*subdir,
file[FILNSIZE];
int result = OK;
struct stat statbuf;
(void) sprintf(tmpdir, "%s/%s/tmp.%s",
mquedir, msg, mychan->ch_name);
if (stat(tmpdir, &statbuf) == OK) {
/* exists so remove it */
char *cmdline = (char *) malloc((unsigned int) (strlen("rm -rf ") + strlen(tmpdir) +1));
sprintf(cmdline, "rm -rf %s", tmpdir);
system(cmdline);
if (cmdline != NULL) free(cmdline);
}
if (mkdir(tmpdir, 0777) != OK) {
PP_SLOG(LLOG_EXCEPTIONS, tmpdir,
("Can't make directory"));
(void) sprintf (buf,
"Unable to make temporary directory '%s'",
tmpdir);
error = strdup(buf);
result = NOTOK;
}
if (result == OK) {
msg_rinit(orig);
if (msg_rfile(file) != RP_OK) {
PP_LOG(LLOG_EXCEPTIONS,
("%s empty or non exsistant dir %s",mychan->ch_name,orig));
(void) sprintf (buf,
"Original directory '%s' is empty",
orig);
error = strdup (buf);
result = NOTOK;
} else {
do {
stripped_file = file + strlen(orig) + 1;
sprintf(newfile,"%s/%s",tmpdir, stripped_file);
stripped_file = newfile + strlen(tmpdir) +1;
/* stripped file now local to tmpdir */
origfile = rindex(file,'/');
*origfile = '\0';
while ((result == OK)
&& ((subdir = index(stripped_file,'/')) != NULL)){
/* check intervening directories */
*subdir = '\0';
if (!((stat(newfile, &statbuf) == OK)
&& ((statbuf.st_mode & S_IFMT) == S_IFDIR))) {
/* sub dir not there so mkdir */
if (mkdir(newfile, 0777) != OK) {
PP_SLOG(LLOG_EXCEPTIONS,
newfile,
("Can't make directory"));
(void) sprintf (buf,
"Failed to make directory '%s'",
newfile);
error = strdup(buf);
result = NOTOK;
} else
PP_TRACE(("%s : made directory %s",mychan->ch_name,newfile));
}
*subdir = '/';
stripped_file = subdir+1;
}
if ( result == OK) {
subdir = rindex(newfile,'/');
*subdir = '\0';
if (is_mychan_file(stripped_file) == TRUE)
result = file_create(file,newfile,stripped_file);
else
result = file_link(file,newfile,stripped_file);
*subdir = '/';
}
*origfile = '/';
} while ((result == OK) && (msg_rfile(file) == RP_OK)) ;
}
msg_rend();
if ((result == OK) && (rename(tmpdir, new) == -1)) {
PP_SLOG(LLOG_EXCEPTIONS, "rename",
("Can't rename directory '%s' to '%s'",
tmpdir, new));
(void) sprintf (buf,
"Failed to rename %s to %s",
tmpdir, new);
error = strdup (buf);
result = NOTOK;
}
}
return result;
}
static int is_mychan_file(name)
char *name;
{
char *suffix;
if (hdrinlist(mychan->ch_bpt_in)
&& (strncmp(name,"hdr.",4) == 0))
return TRUE;
if ((suffix = index(name,'.')) == NULL)
return FALSE;
return in_BPT(++suffix,mychan->ch_bpt_in);
}
static int hdrinlist(list)
LIST_BPT *list;
{
LIST_BPT *ix = list;
while ((ix != NULL)
&& (strncmp(ix->li_name,"hdr.",4) != 0))
ix = ix->li_next;
return (ix == NULL) ? FALSE : TRUE;
}
static int in_BPT(suffix, list)
char *suffix;
LIST_BPT *list;
{
LIST_BPT *ix = list;
while ((ix != NULL)
&& (strcmp(suffix,ix->li_name) != 0))
ix = ix->li_next;
return (ix == NULL) ? FALSE : TRUE;
}
/* \f
*/
static int file_create (orig, tmp, file)
char *orig, /* original message directory */
*tmp, /* where to put new file */
*file; /* file to format */
{
char filein[FILNSIZE], /* input file */
fileout[FILNSIZE], /* output file */
*name = NULL, /* base name of file */
*program = NULL, /* full name of exec'd program */
*ix,
*info_copy,
*expanded = NULL,
*margv[100];
int fd_in, /* input file id */
fd_out, /* output file id */
fd_sterr[2], /* stderr pipe */
pid, /* child process id */
pgmresult,
margc,
i, total_len,
result = OK;
struct stat statbuf;
(void) sprintf(filein, "%s/%s",orig,file);
if (strncmp(mychan->ch_bpt_out->li_name,"hdr.",4) == 0) {
(void) sprintf(fileout, "%s/%s",tmp,mychan->ch_bpt_out->li_name);
} else {
name = strdup(file);
ix = index(name,'.');
*ix = '\0';
(void) sprintf(fileout, "%s/%s.%s",
tmp,name,mychan->ch_bpt_out->li_name);
}
if ((fd_in = open(filein, O_RDONLY, 0666)) == -1) {
PP_SLOG(LLOG_EXCEPTIONS, filein,
("Can't open file"));
(void) sprintf(buf,
"Unable to open input file '%s'",
filein);
error = strdup(buf);
return NOTOK;
}
if ((fd_out = open(fileout, O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1) {
PP_SLOG(LLOG_EXCEPTIONS, fileout,
("Can't open file"));
(void) sprintf(buf,
"Unable to open output file '%s'",
fileout);
error = strdup(buf);
return NOTOK;
}
if (pipe(fd_sterr) != 0) {
PP_SLOG(LLOG_EXCEPTIONS, "pipe",
("Can't pipe standard err"));
error = strdup("Failed to pipe standard error");
return NOTOK;
}
/* get program name */
if (mychan->ch_info == NULL) {
PP_OPER(NULLCP,
("%s cannot find channel info",mychan->ch_name));
value = int_Qmgr_status_mtaFailure;
error = strdup("No channel info associated with channel");
return NOTOK;
}
info_copy = strdup (mychan -> ch_info);
if ((margc = sstr2arg(info_copy, 100, margv, " \t")) < 1) {
PP_OPER(NULLCP,
("%s : no arguments in ch_info string",
mychan->ch_name));
value = int_Qmgr_status_mtaFailure;
(void) sprintf(buf,
"No arguments in info string '%s'",
mychan -> ch_info);
error = strdup(buf);
return NOTOK;
}
if (margv[0][0] == '/')
/* given full path name */
program = strdup(margv[0]);
else {
program = (char *) malloc((unsigned int)
(strlen(formdfldir) + 1 +
strlen(margv[0]) + 1));
sprintf(program,"%s/%s",formdfldir,margv[0]);
}
if (stat(program, &statbuf) != OK) {
PP_OPER(NULLCP,
("%s : missing filter '%s'",mychan -> ch_name, program));
value = int_Qmgr_status_mtaFailure;
(void) sprintf (buf,
"Missing filter '%s'",
program);
error = strdup(buf);
return NOTOK;
}
total_len = 0;
for (i = 0; i < margc; i++) {
if (index (margv[i], '$'))
margv[i] = expand_dyn (margv[i],
expand_macros);
else
margv[i] = strdup (margv[i]);
total_len += strlen(margv[i]) + 3;
/* +3 for intervening space and possible quotes */
}
total_len += 10;
/* just in case */
expanded = malloc((unsigned)(total_len * sizeof(char)));
arg2vstr (0, total_len, expanded, margv);
if ((ix = index (expanded, ' ')) == NULLCP)
ix = expanded;
PP_NOTICE (("%s %s < %s > %s", program, ix,
filein, fileout));
#ifdef BSD42
if ((pid = vfork ()) == 0) {
#else
if ((pid = tryfork()) == 0) {
#endif
/* in child so redirect in- and out-put */
dup2 (fd_in, 0);
dup2 (fd_out, 1);
dup2 (fd_sterr[1], 2);
close(fd_in);
close(fd_out);
close(fd_sterr[0]);
close(fd_sterr[1]);
execv(program,margv);
_exit (1);
} else if (pid == -1) {
PP_SLOG(LLOG_EXCEPTIONS, this_msg,
("tryfork failed"));
error = strdup("Tryfork tailed");
result = NOTOK;
} else {
union wait w;
while ((pgmresult = wait(&w)) != pid && pgmresult != -1)
PP_TRACE(("process %d returned", pgmresult));
if ((pgmresult == pid) && !WIFSIGNALED(w) &&
w.w_retcode == 0)
result = OK;
else
result = NOTOK;
}
close(fd_sterr[1]);
do_child_logging(fd_sterr[0]);
close(fd_in);
close(fd_out);
if (program != NULL) free(program);
for (i = 0; i < margc; i++)
free(margv[i]);
if (expanded) free(expanded);
free (info_copy);
return result;
}
static int do_child_logging(ifd)
int ifd;
{
/* log stuff child puts out on stderr */
char line[LINESIZE];
int len;
FILE *fd = fdopen(ifd, "r");
while (fgets(line, LINESIZE, fd) != NULL) {
len = strlen(line);
if (line[len-1] == '\n')
line[len-1] = '\0';
PP_LOG(LLOG_NOTICE,
("%s : %s",mychan->ch_name,line));
}
fclose(fd);
}
static int file_link(orig,tmp,file)
char *orig, /* original message directory */
*tmp, /* new temporary directory */
*file; /* file to link across */
{
char old[FILNSIZE], /* old file */
new[FILNSIZE]; /* new link */
struct stat statbuf;
int result = OK;
(void) sprintf(old, "%s/%s",orig,file);
(void) sprintf(new, "%s/%s",tmp,file);
if ((stat(old, &statbuf) == OK)
&& (stat(new, &statbuf) != OK)
&& (link(old, new) != -1)) {
result = OK;
} else {
(void) sprintf(buf,
"Failed to link '%s' to '%s'",
new, old);
error = strdup(buf);
result = NOTOK;
}
return result;
}
static ADDR *getnthrecip(que, num)
Q_struct *que;
int num;
{
ADDR *ix = que->Raddress;
int icount = 1;
if (num == 0)
return que->Oaddress;
while ((ix != NULL) && (icount++ < num))
ix = ix->ad_next;
return ix;
}