//check lines of the map void check_line(MapData *m, int r) { int c; for (c = 0; c < m->width; ++c) { char p = m->mapForAgents[r][c]; if (!(p == ' ' || p == '#')) { agent_error(4); } } }
//read the positions from the handler void read_positions(MapData *m) { char buff[80]; for (int r = 0; r < m->total; r++) { char c = fgetc(stdin); ungetc(c, stdin); if(feof(stdin)) { agent_error(4); } int a, b; fgets(buff, 80, stdin); char d; if(sscanf(buff, "%d %d%1[^\n]\n", &a, &b, &d) != 2) { agent_error(4); } m->positions[r][0] = a; m->positions[r][1] = b; } }
//read the data from the handler void read_pipe(MapData *m) { int total; char d; if(fscanf(stdin, "%d%[^\n]\n", &total, &d) != 1) { agent_error(4); } m->total = total; m->agents = malloc(sizeof(char)*(m->total+2)); char bbuff[m->total+2]; if(fscanf(stdin, "%s%[^\n]\n", m->agents, &d) != 1) { agent_error(4); } int len = strlen(m->agents); if(m->total != len) { agent_error(4); } int current; if(fscanf(stdin, "%d%[^\n]\n", ¤t, &d) != 1) { agent_error(4); } m->current = current; int h, w; if(fscanf(stdin, "%d %d%[^\n]\n", &h, &w, &d) != 2) { agent_error(4); } m->height = h; m->width = w; fgets(bbuff, 2, stdin); read_agent_map(m); }
//read the map in the agent file void read_agent_map(MapData *m) { m->mapForAgents = malloc(m->height * sizeof(char *)); for (int r = 0; r < m->height; ++r) { m->mapForAgents[r] = calloc(m->width + 2, sizeof(char)); if(fgets(m->mapForAgents[r], m->width+2, stdin) == NULL || m->mapForAgents[r][m->width] != '\n') { agent_error(4); } check_line(m, r); } }
int LIBAGENT_PUBLIC_API agent_log_python_error(char *log_prefix) { PyObject *ptype; PyObject *pvalue; PyObject *ptraceback; /* Acquire GIL */ PyGILState_STATE gstate = PyGILState_Ensure(); PyErr_Fetch(&ptype, &pvalue, &ptraceback); if (ptype == NULL) { agent_error("%s: No python error available", log_prefix); /* Just in case */ Py_XDECREF(pvalue); Py_XDECREF(ptraceback); /* Release GIL */ PyGILState_Release(gstate); return -1; } if (ptraceback == NULL) { PyObject *obj; agent_error("%s: A python exception has occurred:", log_prefix); if (pvalue != NULL) { obj = PyObject_Str(pvalue); } else { obj = PyObject_Str(ptype); } agent_error("[EXC] %s", PyString_AsString(obj)); Py_DECREF(obj); Py_DECREF(ptype); Py_XDECREF(pvalue); /* Release GIL */ PyGILState_Release(gstate); return 0; } PyObject *tb_mod = PyImport_AddModule("traceback"); if (tb_mod == NULL) { PyErr_Clear(); Py_DECREF(ptype); Py_XDECREF(pvalue); Py_XDECREF(ptraceback); agent_error("%s: [Couldn't find traceback module " "to print the error]", log_prefix); /* Release GIL */ PyGILState_Release(gstate); return -1; } /* * Call traceback.format_exception(ptype, pvalue, ptraceback) */ PyObject *pobj_list = PyObject_CallMethod(tb_mod, "format_exception", "OOO", ptype, pvalue, ptraceback); if (pobj_list == NULL) { PyErr_Clear(); Py_DECREF(ptype); Py_XDECREF(pvalue); Py_XDECREF(ptraceback); agent_error("%s: [Couldn't format traceback]", log_prefix); /* Release GIL */ PyGILState_Release(gstate); return -1; } Py_DECREF(ptype); Py_XDECREF(pvalue); Py_XDECREF(ptraceback); /* * Now we have a list of 'lines'. Each 'line' might actually be * multiple lines, however ('line' might contain '\n's). So, we * need to go through every list entry and log each real line * (looking for \n separator) */ agent_error("%s: A python exception has occurred:", log_prefix); Py_ssize_t list_sz = PyList_Size(pobj_list); PyObject *pobj_str; Py_ssize_t i; for(i = 0;i < list_sz;i++) { pobj_str = PyList_GetItem(pobj_list, i); char *obj_str = strdup(PyString_AsString(pobj_str)); Py_DECREF(pobj_str); if (obj_str == NULL) { agent_error("Out of memory"); Py_DECREF(pobj_list); /* Release GIL */ PyGILState_Release(gstate); return 0; } char *ptr = strchr(obj_str, '\n'); if (ptr == NULL) { /* No \n... just log this element and go to the next */ agent_error("[EXC] %s", obj_str); free(obj_str); continue; } char *start = obj_str; *(ptr++) = '\0'; agent_error("[EXC] %s", start); while((ptr != NULL) && (*ptr != '\0')) { start = ptr; ptr = strchr(start, '\n'); if (ptr != NULL) { *ptr++ = '\0'; } agent_error("[EXC] %s", start); } free(obj_str); } /* Release GIL */ PyGILState_Release(gstate); return 0; }
int main(int argc, char **argv) { struct option longopts[] = { { "help", no_argument, NULL, 'h' }, { "level", required_argument, NULL, 'l' }, { "logfile", required_argument, NULL, 'o' }, { "nofork", no_argument, NULL, 'n' }, { "pidfile", required_argument, NULL, 'p' }, { "quiet", no_argument, NULL, 'q' }, { "syspython", no_argument, NULL, 'S' }, { "testmode", no_argument, NULL, 't' }, { NULL, 0, NULL, 0 } }; agent_python_info_t *pi; sigset_t mask; int opt; int err; int do_fork = 1; int test_mode = 0; int quiet = 0; int syspython = 0; char *progname = argv[0]; char *logfile = AGENT_DEFAULT_LOG_FILE; char *level = AGENT_DEFAULT_LOG_LEVEL; char *config_file = NULL; char *pid_file = NULL; /* Don't let getopt_long() output to stderr directly */ opterr = 0; while((opt = getopt_long(argc, argv, ":hl:no:p:qSt", longopts, NULL)) != -1) { switch(opt) { case 'h': _usage(stdout, progname, 1); return 0; case 'n': do_fork = 0; break; case 'p': pid_file = optarg; break; case 'o': logfile = optarg; break; case 'l': level = optarg; break; case 't': test_mode = 1; break; case 'q': quiet = 1; break; case 'S': syspython = 1; break; case ':': fprintf(stderr, "Error: Missing argument to option '%c'\n", optopt); _usage(stderr, progname, 0); return 1; case '?': switch(optopt) { case 'h': case 'n': fprintf(stderr, "Error: Unexpected argument to option '%c'\n", optopt); break; default: fprintf(stderr, "Error: Unknown option: '%c'\n", optopt); break; } _usage(stderr, progname, 0); return 1; case 0: /* Reserved for options where 'flag != NULL' in longopts[] */ break; default: fprintf(stderr, "Error: Unknown error: '%c'\n", opt); _usage(stderr, progname, 0); return 1; } } argv += optind; argc -= optind; if ((argc < 1) && !test_mode) { fprintf(stderr, "Error: No python configuration file specified\n"); _usage(stderr, progname, 0); return 1; } config_file = argv[0]; /* * Leave argc and argv alone. We'll pass them into python and * it wants the script name as argv[0]... */ if (!quiet && !do_fork) printf("Agent starting.\n"); pi = agent_python_init(argc, argv, syspython); if (pi == NULL) { return 1; } err = agent_open_log(logfile, level); if (err < 0) { agent_python_deinit(pi); exit(-err); } /* init the plugin system */ err = agent_plugin_init(); if (err < 0) { agent_error("couldn't init the plugin system: %d", err); agent_python_deinit(pi); exit(-err); } if (test_mode) { if (!argc) { err = agent_python_start_interpreter(pi); } else { err = agent_python_run_file(pi, config_file); } agent_python_deinit(pi); exit(err); } sigemptyset(&mask); sigaddset(&mask, SIGINT); sigaddset(&mask, SIGTERM); pthread_sigmask(SIG_BLOCK, &mask, &origsigmask); /* Make sure we restore sigmask when the process forks so child process * don't inherit our signal masking */ pthread_atfork(NULL, NULL, _restore_sigmask); err = agent_python_run_file(pi, config_file); if (err < 0) { agent_error("failed to parse config file '%s'", argv[0]); agent_python_deinit(pi); exit(-err); } test_mode = agent_python_test_mode(pi); if (test_mode < 0) { agent_log_python_error("Error with test_mode in config file"); agent_python_deinit(pi); exit(1); } if (test_mode) { /* Test mode */ if (!quiet) printf("Agent stopping due to test mode.\n"); agent_python_deinit(pi); exit(0); } /* * Fork into the background if set. We need to do this before * we create any threads... as fork() only duplicates 1 thread. */ if (do_fork) { /* Fork into the background */ if (fork()) { exit(0); } /* Child */ /* Create new session */ setsid(); /* Reopen stdin/out/err with /dev/null */ int fd = open("/dev/null", O_RDWR); if (fd < 0) { agent_error("could not open /dev/null: %m"); agent_python_deinit(pi); exit(1); } dup2(fd, 0); dup2(fd, 1); dup2(fd, 2); close(fd); } /* Continue */ err = agent_plugin_run_threads(); if (err < 0) { agent_python_deinit(pi); exit(-err); } if (pid_file != NULL) { int fd = open(pid_file, O_CREAT|O_TRUNC|O_WRONLY, 0600); if (fd > 0) { char buf[20]; snprintf(buf, sizeof(buf), "%d\n", getpid()); if (write(fd, buf, strlen(buf)) < 0) { agent_warn("Couldn't write pid to %s", pid_file); } close(fd); } else { agent_warn("Couldn't open pidfile '%s': %s", pid_file, strerror(errno)); } } agent_info("Agent " AGENT_VERSION " started"); _agent_signal_loop(); agent_info("Agent stopping"); agent_plugin_stop_threads(); agent_plugin_deinit(); agent_python_deinit(pi); if (!quiet && !do_fork) printf("Agent stopping.\n"); if (pid_file != NULL) { unlink(pid_file); } return 0; }