#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.sock_path = "127.0.0.1:9000"; 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 'l': PyFCGI_conf.sock_path = strdup(optarg); break; 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_iwd_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; }