dpoke.c
changeset 0 a22a319f5129
child 1 3e9290bf7249
equal deleted inserted replaced
-1:000000000000 0:a22a319f5129
       
     1 #define _POSIX_C_SOURCE 199309L
       
     2 #include <stdio.h>
       
     3 #include <stdlib.h>
       
     4 #include <stdarg.h>
       
     5 #include <string.h>
       
     6 #include <unistd.h>
       
     7 #include <poll.h>
       
     8 #include <time.h>
       
     9 #include <signal.h>
       
    10 #include <sys/types.h>
       
    11 #include <sys/wait.h>
       
    12 #include <fcntl.h>
       
    13 #include <errno.h>
       
    14 #include <math.h>
       
    15 
       
    16 
       
    17 enum DPokeSourceType_en {
       
    18     DPOKE_PROGRAM,
       
    19     DPOKE_FILE,
       
    20     DPOKE_FUNCTION,
       
    21 };
       
    22 typedef enum DPokeSourceType_en DPokeSourceType;
       
    23 
       
    24 #define DPOKE_BUFFER 32
       
    25 struct DPokeSource_st {
       
    26     DPokeSourceType type;
       
    27     char *path;
       
    28     int arg;
       
    29 
       
    30     //FILE *stream;
       
    31     int fd;
       
    32     enum DPokeSourceStatus_en {
       
    33         DPOKE_STARTED,
       
    34         DPOKE_RUNNING,
       
    35         DPOKE_DIED,
       
    36         DPOKE_FAIL,
       
    37         DPOKE_FAILED,
       
    38     } status;
       
    39     char buffer[DPOKE_BUFFER+1];
       
    40     char current[DPOKE_BUFFER+1];
       
    41     int buffer_usage;
       
    42 
       
    43     // DPOKE_PROGRAM-specific fields:
       
    44     int pid;
       
    45 };
       
    46 
       
    47 typedef struct DPokeSource_st DPokeSource;
       
    48 
       
    49 #define LENGTH(X)               (sizeof X / sizeof X[0])
       
    50 
       
    51 char* smprintf(char *fmt, ...) {
       
    52     va_list fmtargs;
       
    53     char *ret;
       
    54     int len;
       
    55 
       
    56     va_start(fmtargs, fmt);
       
    57     len = vsnprintf(NULL, 0, fmt, fmtargs);
       
    58     va_end(fmtargs);
       
    59 
       
    60     ret = malloc(++len);
       
    61     if (ret == NULL) {
       
    62         perror("malloc");
       
    63         exit(1);
       
    64     }
       
    65 
       
    66     va_start(fmtargs, fmt);
       
    67     vsnprintf(ret, len, fmt, fmtargs);
       
    68     va_end(fmtargs);
       
    69 
       
    70     return ret;
       
    71 }
       
    72 
       
    73 
       
    74 void display();
       
    75 
       
    76 extern char* v[];
       
    77 #include "config.h"
       
    78 #ifdef DEBUG
       
    79 #define errprintf(...) fprintf(stderr,...)
       
    80 #else
       
    81 #define errprintf(...)
       
    82 #endif
       
    83 
       
    84 char* v[LENGTH(sources)];
       
    85 
       
    86 static struct pollfd source_fds[LENGTH(sources)];
       
    87 
       
    88 void source_open(int source_id) {
       
    89     DPokeSource *src = &sources[source_id];
       
    90     //FILE* stream;
       
    91     int p_stdout[2];
       
    92     switch (src->type) {
       
    93         case DPOKE_PROGRAM:
       
    94             //stream = popen(src->path, "r");
       
    95             if (pipe(p_stdout)!=0) {
       
    96                 perror("pipe");
       
    97                 exit(7);
       
    98             }
       
    99             pid_t pid = fork();
       
   100             if (pid < 0) {
       
   101                 perror("fork");
       
   102                 exit(7);
       
   103             } else if (pid == 0) {
       
   104                 dup2(open("/dev/null",O_RDONLY),0);
       
   105                 close(p_stdout[0]);
       
   106                 dup2(p_stdout[1],1);
       
   107                 execl("/bin/sh", "sh", "-c", src->path, NULL);
       
   108                 perror("execl");
       
   109                 exit(1);
       
   110             }
       
   111             src->fd = p_stdout[0];
       
   112             src->pid = pid;
       
   113             break;
       
   114         default:
       
   115             errprintf("Don't know how to handle source type %d.\n",src->type);
       
   116             exit(2);
       
   117     }
       
   118     //src->stream = stream;
       
   119     //src->fd = fileno(stream);
       
   120     src->buffer_usage = 0;
       
   121     src->status = DPOKE_STARTED;
       
   122     source_fds[source_id].fd = sources[source_id].fd;
       
   123     source_fds[source_id].events = POLLIN;
       
   124 }
       
   125 
       
   126 static void sigchld_hdl (int sig)
       
   127 {
       
   128     pid_t pid;
       
   129     while ((pid = waitpid(-1, NULL, WNOHANG)) > 0) {
       
   130         for (int i=0;i<LENGTH(sources);i++)
       
   131             if ((sources[i].type == DPOKE_PROGRAM) && (sources[i].pid == pid)) {
       
   132                 sources[i].pid = -1;
       
   133                 errprintf("#%d pid %d died.\n",i,pid);
       
   134                 switch (sources[i].status) {
       
   135                     case DPOKE_STARTED:
       
   136                         sources[i].status = DPOKE_FAIL; break;
       
   137                     case DPOKE_RUNNING:
       
   138                         sources[i].status = DPOKE_DIED; break;
       
   139                     default:
       
   140                         errprintf("#%d died in state %d. Whaddafuck?!\n",i,sources[i].status);
       
   141                         exit(8);
       
   142                 }
       
   143             }
       
   144     }
       
   145 }
       
   146 
       
   147 void source_close(int source_id) {
       
   148     DPokeSource *src = &sources[source_id];
       
   149     if (src->pid != -1) kill(src->pid,SIGTERM);
       
   150     if (src->fd != -1) close(src->fd);
       
   151     source_fds[source_id].fd = -1;
       
   152 }
       
   153 
       
   154 double dpoke_time() {
       
   155     struct timespec tp;
       
   156     if (clock_gettime(CLOCK_MONOTONIC,&tp)) {
       
   157         perror("clock_gettime");
       
   158         exit(5);
       
   159     }
       
   160     return tp.tv_sec + tp.tv_nsec*1E-9;
       
   161 }
       
   162 
       
   163 int main(int argc, char* argv[]) {
       
   164     struct sigaction act;
       
   165 
       
   166     memset (&act, 0, sizeof(act));
       
   167     act.sa_handler = sigchld_hdl;
       
   168     if (sigaction(SIGCHLD, &act, 0)) {
       
   169         perror ("sigaction");
       
   170         exit(6);
       
   171     }
       
   172 
       
   173     for (int i = 0; i < LENGTH(sources); i++ ) {
       
   174         source_open(i);
       
   175         v[i] = sources[i].current;
       
   176     }
       
   177     int status;
       
   178     int sleeptime = 10000;
       
   179     double prevtime=dpoke_time();
       
   180     while (1) {
       
   181         status = poll(source_fds,LENGTH(sources), sleeptime);
       
   182         if (status < 0) {
       
   183             if (errno == EINTR)
       
   184                 continue;
       
   185         }
       
   186         for (int i = 0; i < LENGTH(sources); i++) {
       
   187             DPokeSource *src = sources+i;
       
   188             if (source_fds[i].revents & POLLIN) {
       
   189                 int data_read = read(src->fd,src->buffer+src->buffer_usage,DPOKE_BUFFER-src->buffer_usage);
       
   190                 if (data_read>0) {
       
   191                     src->buffer_usage += data_read;
       
   192                     if (src->buffer_usage==DPOKE_BUFFER) {
       
   193                         errprintf("Buffer is full for #%d.\n",i);
       
   194                     }
       
   195                     src->buffer[src->buffer_usage] = '\0';
       
   196                     char* eolpos = strchr(src->buffer + src->buffer_usage - data_read,'\n');
       
   197                     if (eolpos) {
       
   198                         memcpy(src->current,src->buffer,eolpos-src->buffer);
       
   199                         src->current[eolpos-src->buffer] = '\0';
       
   200                         src->buffer_usage -= (eolpos - src->buffer + 1);
       
   201                         memmove(src->buffer,eolpos + 1,src->buffer_usage + 1);
       
   202                     }
       
   203                     if (src->status == DPOKE_STARTED)
       
   204                         src->status = DPOKE_RUNNING;
       
   205                 } else {
       
   206                     perror("read");
       
   207                     exit(3);
       
   208                 }
       
   209             } else if ((source_fds[i].revents & POLLHUP)||(src->status==DPOKE_DIED)) {
       
   210                 errprintf("#%d HUP\n",i);
       
   211                 source_close(i);
       
   212                 if (src->status==DPOKE_STARTED)
       
   213                     src->status = DPOKE_FAIL;
       
   214                 else
       
   215                     source_open(i);
       
   216             } else if (source_fds[i].revents) {
       
   217                 errprintf("#%d revents: %d\n",i,source_fds[i].revents);
       
   218             }
       
   219             if (src->status==DPOKE_FAIL) {
       
   220                 src->status = DPOKE_FAILED;
       
   221                 errprintf("#%d Marked as failure\n",i);
       
   222                 strcpy(src->current,FAILURE_MSG);
       
   223             }
       
   224         }
       
   225         double curtime = dpoke_time();
       
   226         if ((curtime-prevtime)>MINTIME) {
       
   227             display();
       
   228             prevtime = curtime;
       
   229             sleeptime = 10000;
       
   230         } else {
       
   231             double sleepd = (prevtime+MINTIME - curtime)*1000;
       
   232             sleeptime = ceil(sleepd);
       
   233             errprintf("%f %f %f %f\n",prevtime,curtime,MINTIME,sleepd);
       
   234         }
       
   235         errprintf("Will sleep for %d\n",sleeptime);
       
   236     }
       
   237     return 0;
       
   238 }
       
   239 /*
       
   240 ABCnDEF0
       
   241 01234567
       
   242 eolpos = 3
       
   243 bu = 7
       
   244 3-0+1 = 4
       
   245 bu = 3
       
   246 memmove:
       
   247 01234567
       
   248 34534567
       
   249 nDEn
       
   250 */