Back to index

courier  0.68.2
moduledel.c
Go to the documentation of this file.
00001 /*
00002 ** Copyright 1998 - 2006 Double Precision, Inc.
00003 ** See COPYING for distribution information.
00004 */
00005 
00006 #include      "moduledel.h"
00007 #include      "courier.h"
00008 #include      "maxlongsize.h"
00009 #include      "waitlib/waitlib.h"
00010 #include      <stdlib.h>
00011 #include      <stdio.h>
00012 #include      <errno.h>
00013 #include      <time.h>
00014 #include      <signal.h>
00015 
00016 #include      <sys/types.h>
00017 #if TIME_WITH_SYS_TIME
00018 #include        <sys/time.h>
00019 #include        <time.h>
00020 #else
00021 #if HAVE_SYS_TIME_H
00022 #include        <sys/time.h>
00023 #else
00024 #include        <time.h>
00025 #endif
00026 #endif
00027 #if    HAVE_SYS_SELECT_H
00028 #include      <sys/select.h>
00029 #endif
00030 
00031 #if    HAVE_UNISTD_H
00032 #include      <unistd.h>
00033 #endif
00034 
00035 static char *linebuf=0;
00036 static size_t linebufsize=0;
00037 static char **cols=0;
00038 static size_t colcnt=0;
00039 
00040 unsigned module_nchildren;
00041 unsigned *module_delids;
00042 pid_t *module_pids;
00043 time_t *module_timeout;
00044 int *module_sig;
00045 static time_t delivery_timeout=0;
00046 
00047 char   **module_parsecols(char *p)
00048 {
00049 unsigned l;
00050 size_t ncols=1;
00051 size_t n;
00052 
00053        for (l=0; p[l]; l++)
00054               if (p[l] == '\t')    ++ncols;
00055 
00056        if (ncols >= colcnt)
00057        {
00058               colcnt=ncols+10;
00059               cols=(char **)(cols ? realloc(cols, colcnt*sizeof(char *))
00060                             : malloc(colcnt*sizeof(char *)));
00061        }
00062        ncols=1;
00063        cols[0]=linebuf;
00064        for (n=0; p[n]; n++)
00065               if (p[n] == '\t')
00066                      cols[ncols++]=p+n+1;
00067        cols[ncols]=0;
00068        if (ncols < 6)       return (0);
00069        return (cols);
00070 }
00071 
00072 struct moduledel *module_parsedel(char **cols)
00073 {
00074 size_t n;
00075 const char *cp;
00076 static struct moduledel msginfo;
00077 
00078        for (n=1; cols[n]; n++)
00079               cols[n][-1]=0;
00080 
00081        cp=cols[0];
00082        msginfo.inum=0;
00083        while (*cp >= '0' && *cp <= '9')
00084               msginfo.inum = msginfo.inum*10 + (*cp++ - '0');
00085        msginfo.msgid=cols[1];
00086 
00087        msginfo.sender=cols[2];
00088        msginfo.delid=cols[3];
00089        msginfo.host=cols[4];
00090        msginfo.receipients=&cols[5];
00091        msginfo.nreceipients=(n - 5)/2;
00092        return (&msginfo);
00093 }
00094 
00095 char *module_getline( int (*get_func)(void *), void *ptr)
00096 {
00097 size_t n;
00098 int    c;
00099 
00100        for (n=0; ; n++)
00101        {
00102               do
00103               {
00104                      errno=0;
00105                      c= (*get_func)(ptr);
00106               } while (c == EOF && errno == EINTR);
00107 
00108               if (n >= linebufsize)
00109               {
00110                      if ((linebuf=(char *)
00111                             (linebufsize ? realloc(linebuf,
00112                                    linebufsize += 256):
00113                                    malloc(linebufsize += 256))) == 0)
00114                             clog_msg_errno();
00115               }
00116 
00117               if (c == '\n' || c == EOF)  break;
00118 
00119               linebuf[n]=c;
00120        }
00121        linebuf[n]=0;
00122        if (c == EOF && n == 0)     return (0);
00123        return (linebuf);
00124 }
00125 
00126 static int get_stdin(void *dummy)
00127 {
00128        static char stdin_buf[256];
00129        static char *stdin_p=NULL;
00130        static size_t stdin_left=0;
00131 
00132        while (stdin_left == 0)
00133        {
00134               time_t currentTime=time(NULL);
00135               time_t nextTime=0;
00136               size_t i;
00137               fd_set fds;
00138               struct timeval tv;
00139 
00140               if (delivery_timeout)
00141                      for (i=0; i<module_nchildren; i++)
00142                      {
00143                             size_t n;
00144 
00145                             if (module_pids[i] < 0)
00146                                    continue;
00147 
00148                             if (module_timeout[i] <= currentTime)
00149                             {
00150                                    clog_msg_start_err();
00151                                    clog_msg_str("Error: stuck delivery,"
00152                                                " PID ");
00153                                    clog_msg_uint(module_pids[i]);
00154                                    clog_msg_str(", sending signal ");
00155                                    clog_msg_uint(module_sig[i]);
00156                                    clog_msg_send();
00157 
00158                                    module_timeout[i]=currentTime+10;
00159                                    kill(-module_pids[i], module_sig[i]);
00160                                    module_sig[i]=SIGKILL;
00161                                    continue;
00162                             }
00163 
00164                             n=module_timeout[i] - currentTime;
00165 
00166                             if (nextTime == 0 || n < nextTime)
00167                                    nextTime=n;
00168                      }
00169 
00170               FD_ZERO(&fds);
00171               FD_SET(0, &fds);
00172               tv.tv_sec=nextTime;
00173               tv.tv_usec=0;
00174 
00175               if (select(1, &fds, NULL, NULL, nextTime ? &tv:NULL) > 0)
00176               {
00177                      int n=read(0, stdin_buf, sizeof(stdin_buf));
00178 
00179                      if (n <= 0)
00180                             break;
00181                      
00182                      stdin_p=stdin_buf;
00183                      stdin_left=n;
00184               }
00185        }
00186 
00187        if (stdin_left == 0)
00188               return EOF;
00189 
00190        --stdin_left;
00191        return (int)(unsigned char)*stdin_p++;
00192 }
00193 
00194 struct moduledel *module_getdel()
00195 {
00196 char   **cols;
00197 char   *line=module_getline( &get_stdin, 0);
00198 
00199        if (!line)    return (0);
00200 
00201        if ((cols=module_parsecols(linebuf)) == 0)       return (0);
00202        return (module_parsedel(cols));
00203 }
00204 
00205 void module_completed(unsigned i, unsigned n)
00206 {
00207 char   buf[MAXLONGSIZE+1];
00208 char   *p;
00209 unsigned c;
00210 
00211        i=i;
00212        p=buf+MAXLONGSIZE-1;
00213        *p='\n';
00214        p[1]=0;
00215        c=1;
00216        do
00217        {
00218               *--p= (n % 10) + '0';
00219               ++c;
00220        } while ((n=n / 10) != 0);
00221        if (write (1, p, c) != c)
00222               ;
00223 }
00224 
00225 static void (*childfunc)(unsigned, unsigned);
00226 
00227 static void terminated(pid_t p, int s)
00228 {
00229 int    n;
00230 
00231        for (n=0; n<module_nchildren; n++)
00232               if (module_pids[n] == p)
00233               {
00234                      module_pids[n]= -1;
00235                      (*childfunc)(n, module_delids[n]);
00236                      break;
00237               }
00238 }
00239 
00240 static RETSIGTYPE childsig(int);
00241 
00242 void module_blockset()
00243 {
00244        wait_block();
00245 }
00246 
00247 void module_blockclr()
00248 {
00249        wait_clear(childsig);
00250 }
00251 
00252 void module_restore()
00253 {
00254        wait_restore();
00255 }
00256 
00257 static RETSIGTYPE childsig(int n)
00258 {
00259        n=n;
00260 
00261        wait_reap(terminated, childsig);
00262 
00263 #if    RETSIGTYPE != void
00264        return (0);
00265 #endif
00266 }
00267 
00268 void module_init(void (*func)(unsigned, unsigned))
00269 {
00270 const  char *p=getenv("MAXDELS");
00271 unsigned n;
00272 
00273        if (!p)       p="0";
00274 
00275        if (!func)
00276               func= &module_completed;
00277 
00278        module_nchildren=atol(p);
00279        if (module_nchildren <= 0)  module_nchildren=1;
00280 
00281        if ((module_pids=malloc(module_nchildren*sizeof(*module_pids))) == 0 ||
00282            (module_delids=malloc(module_nchildren*sizeof(*module_delids))) == 0 ||
00283            (module_timeout=malloc(module_nchildren*sizeof(*module_timeout)))
00284            == 0 ||
00285            (module_sig=malloc(module_nchildren*sizeof(*module_sig))) == 0)
00286               clog_msg_errno();
00287 
00288        for (n=0; n<module_nchildren; n++)
00289               module_pids[n]= -1;
00290 
00291        childfunc=func;
00292        signal(SIGCHLD, childsig);
00293 }
00294 
00295 static pid_t module_fork_common(unsigned delid, unsigned *slotptr,
00296        int dorelease)
00297 {
00298 pid_t  pid;
00299 unsigned n;
00300 static unsigned idx=0;
00301 
00302        if (slotptr)
00303               idx= *slotptr;
00304        else
00305        {
00306               for (n=0; n<module_nchildren; n++)
00307               {
00308                      if (module_pids[idx] < 0)   break;
00309                      if (++idx >= module_nchildren)     idx=0;
00310               }
00311 
00312               if (n == module_nchildren)
00313               {
00314                      clog_msg_start_err();
00315                      clog_msg_str(
00316                      "Internal error - no available process slots.");
00317                      clog_msg_send();
00318                      exit(1);
00319               }
00320        }
00321 
00322        if ((pid=fork()) == -1)
00323               return (pid);
00324 
00325        if (pid)
00326        {
00327               time_t n=0;
00328 
00329               module_pids[idx]=pid;
00330               module_delids[idx]=delid;
00331 
00332               if (delivery_timeout)
00333               {
00334                      time(&n);
00335                      n += delivery_timeout;
00336               }
00337               module_timeout[idx] = n;
00338               module_sig[idx] = SIGTERM;
00339        }
00340        else
00341        {
00342               module_restore();
00343        }
00344 
00345        return (pid);
00346 }
00347 
00348 void module_delivery_timeout(time_t n)
00349 {
00350        delivery_timeout=n;
00351 }
00352 
00353 pid_t module_fork_noblock(unsigned delid, unsigned *slotptr)
00354 {
00355        return (module_fork_common(delid, slotptr, 0));
00356 }
00357 
00358 pid_t module_fork(unsigned delid, unsigned *slotptr)
00359 {
00360 pid_t  pid;
00361 
00362        module_blockset();
00363 
00364        pid=module_fork_common(delid, slotptr, 1);
00365 
00366        if (pid)
00367               module_blockclr();
00368        return (pid);
00369 }
00370 
00371 void module_signal(int signum)
00372 {
00373        unsigned n;
00374 
00375        module_blockset();
00376 
00377        for (n=0; n<module_nchildren; n++)
00378               if (module_pids[n] > 0)
00379               {
00380                      kill(module_pids[n], signum);
00381               }
00382        module_blockclr();
00383 }