123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471 |
- #include "conf.h"
-
- void usage()
- {
- static const struct option opts[] = PYFCGI_LONG_OPT;
- static const char *help[][2] = PYFCGI_OPT_HELP;
- size_t i;
- dprintf(2, "Usage : %s -e PYMODULE [-E PYFUN] [OPTIONS]\n", PYFCGI_NAME);
- dprintf(2, "\nOptions list :\n");
- i=0;
- while(opts[i].name)
- {
- dprintf(2, "\t-%c, --%s", opts[i].val, opts[i].name);
- switch(opts[i].has_arg)
- {
- case required_argument:
- dprintf(2, "=%s\n",
- help[i][1]?help[i][1]:"ARG");
- break;
- case optional_argument:
- dprintf(2, "[=%s]\n",
- help[i][1]?help[i][1]:"ARG");
- break;
- default: //no_argument
- dprintf(2, "\n");
- }
- dprintf(2, "\t\t%s\n", help[i][0]);
- i++;
- }
- dprintf(2, "%s", PYFCGI_HELP_TEXT);
- }
-
- void print_version(int fd)
- {
- char pyversion[16];
- pyfcgi_python_version(pyversion);
- dprintf(fd, "%s\nPython %s\n", PACKAGE_STRING, pyversion);
- }
-
- void default_conf()
- {
- memset(&PyFCGI_conf, 0, sizeof(pyfcgi_conf_t));
- PyFCGI_conf.context.pid = getpid();
- PyFCGI_conf.min_wrk = 1;
- PyFCGI_conf.max_wrk = 5;
- PyFCGI_conf.max_reqs = 1000;
- PyFCGI_conf.pep333 = 1;
- PyFCGI_conf.verbosity = 0;
- PyFCGI_conf.pool_timeout = 5;
- PyFCGI_conf.worker_timeout = 3;
- PyFCGI_conf.worker_gc_timeout = 7;
-
- PyFCGI_conf.context.uptime = time(NULL);
- }
-
- int parse_args(int argc, char *argv[])
- {
- static const struct option long_options[] = PYFCGI_LONG_OPT;
- char ident[] = "pyfcgi[XXXXXXXX]";
- int c, opt_i;
-
- while(1)
- {
- c = getopt_long(argc, argv, PYFCGI_SHORT_OPT, long_options,
- &opt_i);
- if(c == -1) { break; }
- switch(c)
- {
- case 'V':
- print_version(1);
- exit(0);
- case 'C':
- dprintf(2, "Config parser not yet implemented :'(\n");
- exit(1);
- case 'e':
- PyFCGI_conf.py_entrymod = strdup(optarg);
- break;
- case 'E':
- PyFCGI_conf.py_entryfun = strdup(optarg);
- break;
- case 'A':
- PyFCGI_conf.pep333 = 0;
- break;
- case 'w':
- PyFCGI_conf.min_wrk = atoi(optarg);
- break;
- case 'W':
- PyFCGI_conf.max_wrk = atoi(optarg);
- break;
- case 'v':
- PyFCGI_conf.verbosity = 1;
- pyfcgi_logger_add(NULL, 0xFF, 0xFF,
- PYFCGI_LOGGER_FMT_DEFAULT);
- break;
- case 'm':
- PyFCGI_conf.max_reqs = atoi(optarg);
- if(PyFCGI_conf.max_reqs < 0)
- {
- PyFCGI_conf.max_reqs = 0;
- }
- break;
- case 'f':
- PyFCGI_conf.worker_fast_spawn = 1;
- break;
- case 't':
- PyFCGI_conf.worker_timeout = atoi(optarg);
- if(PyFCGI_conf.worker_timeout < 0)
- {
- PyFCGI_conf.worker_timeout = 0;
- }
- break;
- case 'L':
- if(parse_optlog(optarg))
- {
- exit(1);
- }
- break;
- case 'S':
- snprintf(ident+7, 8, "%4d]", PyFCGI_conf.context.pid);
- pyfcgi_logger_enable_syslog(ident);
- break;
- case 'P':
- PyFCGI_conf.pidfile = strdup(optarg);
- /**@todo create pidfile and put master pid in it */
- break;
- case 's':
- if(pyfcgi_monitor_check_sock(optarg) < 0)
- {
- exit(1);
- }
- PyFCGI_conf.mon_socket = strdup(optarg);
- /**@todo check strdup returned value */
- break;
- case 'h':
- usage();
- exit(0);
- default:
- usage();
- exit(1);
- }
- }
- if(optind < argc)
- {
- for(opt_i=optind; opt_i<argc; opt_i++)
- {
- dprintf(2, "Unkown argument '%s'\n", argv[opt_i]);
- }
- usage();
- exit(1);
- }
- if(!PyFCGI_conf.py_entrymod)
- {
- dprintf(2, "No python entry module given... exiting\n");
- usage();
- exit(2);
- }
- if(!PyFCGI_conf.py_entryfun)
- {
- PyFCGI_conf.py_entryfun = PYENTRY_DEFAULT_FUN;
- }
- if(check_entrypoint_import())
- {
- usage();
- exit(3);
- }
- return 0;
- }
-
- int check_entrypoint_import()
- {
- pid_t pid;
- int status;
- void *ret;
-
- pid = fork();
- if(!pid)
- {
- pyinit();
- ret = (void*)import_entrypoint();
- if(!ret)
- {
- dprintf(2, "Unable to import entrypoint...\n");
- exit(1);
- }
- pyfcgi_log(LOG_DEBUG, "Entrypoint import [OK]");
- Py_Exit(0);
- }
- waitpid(pid, &status, 0);
- return WEXITSTATUS(status);
- }
-
- int parse_optlog(const char* logspec)
- {
- char *filename, *filter, *fmt;
- int filt;
-
- filename = strdup(logspec); /**@todo check error */
- filter = filename;
- while(*filter && *filter != ';') { filter++; }
- if(*filter)
- {
- *filter = '\0';
- filter++;
- }
- fmt = filter;
- while(*fmt && *fmt != ';') { fmt++; }
- if(*fmt)
- {
- *fmt = '\0';
- fmt++;
- }
- if(!strlen(filter))
- {
- filt = 0xFF;
- }
- else
- {
- filt = strtol(filter, NULL, !strncmp(filter, "0x", 2)?16:10);
- }
- fmt = strlen(fmt)?fmt:NULL;
- if(pyfcgi_logger_add(filename, filt, filt, fmt))
- {
- return 1;
- }
- return 0;
- }
-
- int pyfcgi_wd_init(void (*wd_sig_cleaner)(int), const struct timespec *delay)
- {
- struct sigaction act;
- struct sigevent sev;
- pyfcgi_context_t *context;
- struct timespec timeout;
- double part, tmp;
- int err;
-
- context = &(PyFCGI_conf.context);
-
- timeout = PyFCGI_conf.context.wd_delay = *delay;
-
- //kill delay timeout
- timeout.tv_nsec *= 1.5;
- part = modf(((double)timeout.tv_sec/2.0), &tmp);
- timeout.tv_nsec += part * 1000000000;
- timeout.tv_sec = (time_t)(timeout.tv_sec * 1.5);
- timeout.tv_sec += timeout.tv_nsec / 1000000000;
- if(part != 0.0)
- {
- timeout.tv_nsec /= (long)(part * 1000000000);
- }
-
- PyFCGI_conf.context.wd_killdelay = timeout;
-
- pyfcgi_log(LOG_DEBUG,
- "Set watchdog with %d.%09ds timeout (%d.%09ds for SIGKILL)",
- PyFCGI_conf.context.wd_delay.tv_sec,
- PyFCGI_conf.context.wd_delay.tv_nsec,
- PyFCGI_conf.context.wd_killdelay.tv_sec,
- PyFCGI_conf.context.wd_killdelay.tv_nsec);
-
- // Creating new timer with default sigevent (SIGEV_SIGNAL with SIGALRM)
- if(timer_create(CLOCK_REALTIME, NULL, &(context->wd_timer)) < 0)
- {
- err = errno;
- pyfcgi_log(LOG_ALERT, "Unable to create watchdog timer : %s",
- strerror(err));
- errno = err;
- return -1;
- }
- // Creating a new timer sending SIGKILL after 1.5 delay
- sev.sigev_notify = SIGEV_SIGNAL;
- sev.sigev_signo = SIGKILL;
- if(timer_create(CLOCK_REALTIME, &sev, &(context->wd_timerkill)) < 0)
- {
- err = errno;
- pyfcgi_log(LOG_ALERT, "Unable to create kill watchdog timer : %s",
- strerror(err));
- errno = err;
- return -1;
- }
-
- // Registering SIGALRM signal handler
- act.sa_handler = wd_sig_cleaner?wd_sig_cleaner:pyfcgi_wd_default_sighandler;
- sigemptyset(&act.sa_mask);
- act.sa_flags = 0;
- act.sa_restorer = NULL;
- if(sigaction(SIGALRM, &act, &(context->wd_oldsig)) < 0)
- {
- err = errno;
- pyfcgi_log(LOG_ALERT, "Unable to set the signal handler for watchdog timer : %s",
- strerror(err));
- errno = err;
- return -1;
- }
- context->wd = 1;
- return 0;
- }
-
- int pyfcgi_wd_arm()
- {
- pyfcgi_context_t *context;
- struct itimerspec timeout;
- int err, res;
-
- context = &(PyFCGI_conf.context);
-
- if(!context->wd) { return 0; }
-
- timeout.it_value = context->wd_delay;
- timeout.it_interval.tv_sec = 0;
- timeout.it_interval.tv_nsec = 0;
-
- context = &(PyFCGI_conf.context);
- res = 0;
-
- if(timer_settime(context->wd_timer, 0, &timeout, NULL) < 0)
- {
- err = errno;
- pyfcgi_log(LOG_ALERT, "Unable to arm watchdog : %s",
- strerror(err));
- res = -1;
- }
-
- timeout.it_value = context->wd_killdelay;
- timeout.it_interval = timeout.it_value;
-
- if(timer_settime(context->wd_timerkill, 0, &timeout, NULL) < 0)
- {
- err = errno;
- pyfcgi_log(LOG_ALERT, "Unable to pause killer watchdog : %s",
- strerror(err));
- res = -1;
- }
- return res;
- }
-
- int pyfcgi_wd_pause()
- {
- pyfcgi_context_t *context;
- struct itimerspec zero;
- int err, res;
-
- context = &(PyFCGI_conf.context);
- if(!context->wd) { return 0; }
-
- memset(&zero, 0, sizeof(struct itimerspec));
-
- res = 0;
-
- if(timer_settime(context->wd_timer, TIMER_ABSTIME, &zero, NULL) < 0)
- {
- err = errno;
- pyfcgi_log(LOG_ALERT, "Unable to pause watchdog : %s",
- strerror(err));
- res = -1;
- }
- if(timer_settime(context->wd_timerkill, TIMER_ABSTIME, &zero, NULL) < 0)
- {
- err = errno;
- pyfcgi_log(LOG_ALERT, "Unable to pause killer watchdog : %s",
- strerror(err));
- res = -1;
- }
- return res;
- }
-
- int pyfcgi_wd_stop()
- {
- int err, res;
- pyfcgi_context_t *context;
-
- context = &(PyFCGI_conf.context);
- if(!context->wd) { return 0; }
- res = 0;
-
- if(timer_delete(context->wd_timer) < 0)
- {
- err = errno;
- pyfcgi_log(LOG_WARNING, "Unable to delete watchdog timer : %s",
- strerror(err));
- res = -1;
- }
- if(timer_delete(context->wd_timerkill) < 0)
- {
- err = errno;
- pyfcgi_log(LOG_WARNING, "Unable to delete killer watchdog timer : %s",
- strerror(err));
- res = -1;
- }
- if(sigaction(SIGALRM, &(context->wd_oldsig), NULL) < 0)
- {
- err = errno;
- pyfcgi_log(LOG_WARNING, "Unable to restore signal handler : %s",
- strerror(err));
- res = -1;
- }
- context->wd = 0;
- pyfcgi_log(LOG_DEBUG, "Watchdog stopped");
- return res;
- }
-
- void pyfcgi_wd_default_sighandler(int signum)
- {
- pyfcgi_log(LOG_ALERT, "Timeout after %d.%09ds",
- PyFCGI_conf.context.wd_delay.tv_sec,
- PyFCGI_conf.context.wd_delay.tv_nsec);
- pyfcgi_wd_stop();
- exit(PYFCGI_TIMEOUT);
- }
-
- char *status2str(int status)
- {
- char buff[1024], *buffptr;
- size_t left = 1024, ret;
- short reason;
-
- reason = 0;
- buffptr = buff;
-
- if(status & (PYFCGI_WORKER_FAIL | PYFCGI_MASTER_FAIL))
- {
- buffptr += ret = snprintf(buffptr, left, "%s ",
- (status & PYFCGI_WORKER_FAIL)?"Worker":"Master");
- left -= ret;
- status &= ((0xFFFF) ^ (PYFCGI_WORKER_FAIL | PYFCGI_MASTER_FAIL));
- }
- if(status & PYFCGI_FATAL)
- {
- buffptr += ret = snprintf(buffptr, left, "fatal ");
- left -= ret;
- status ^= PYFCGI_FATAL;
- }
- if(status & EXIT_PYERR)
- {
- buffptr += ret = snprintf(buffptr, left, "Python");
- left -= ret;
- status ^= EXIT_PYERR;
- }
- if( status & PYFCGI_TIMEOUT)
- {
- buffptr += ret = snprintf(buffptr, left, "Timeout");
- left -= ret;
- reason = 1;
- status ^= PYFCGI_TIMEOUT;
- }
- if(status & PYFCGI_ERR)
- {
- buffptr += ret = snprintf(buffptr, left, "Error");
- left -= ret;
- reason = 1;
- status ^= PYFCGI_ERR;
- }
- if(!reason)
- {
- buffptr += ret = snprintf(buffptr, left, "Failure");
- left -= ret;
- }
- if(status)
- {
- buffptr += ret = snprintf(buffptr, left, "%d", status);
- left -= ret;
- }
- return strndup(buff, 1024);
- }
-
- void pyfcgi_sighandler_drop(int signum)
- {
- pyfcgi_log(LOG_DEBUG, "Catching signal %s", strsignal(signum));
- return;
- }
|