/*-------------------------------------------------------------------+ | Main | +-------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) { register int i; int (*rtn) (); struct cmdentry *c; int retcode; int ntokens; char writefilename[PATH_LEN + 1]; char *cptr; int start_engine_main(); int check_for_engine(); int check_dir_rw ( char *, char * ); configp = &config; strncpy2(heyuprogname, argv[0], sizeof(heyuprogname) - 10); /* Record if heyu was executed downstream of the heyu state engine or relay */ heyu_parent = D_CMDLINE; if ( (cptr = getenv("HEYU_PARENT")) != NULL ) { if ( strcmp(cptr, "RELAY") == 0 ) { heyu_parent = D_RELAY; i_am_state = 0; } else if ( strcmp(cptr, "ENGINE") == 0 ) { heyu_parent = D_ENGINE; i_am_state = 0; } else if ( strcmp(cptr, "AUXDEV") == 0 ) { heyu_parent = D_AUXDEV; i_am_state = 0; } } fdsout = fprfxo = stdout; fdserr = fprfxe = stderr; rtn = NULL; /* Check for and store options in options structure */ /* Return number of tokens used for options, or -1 */ /* if a usage error. */ ntokens = heyu_getopt(argc, argv, optptr); if ( ntokens < 0 || (argc - ntokens) < 2 ) { fprintf(stderr, "Heyu version %s\n", VERSION ); fprintf(stderr, "X10 Automation for Linux, Unix, and Mac OS X\n"); fprintf(stderr, "Copyright Charles W. Sullivan and Daniel B. Suthers\n"); fprintf(stderr, "Usage: heyu [options] <command> (Enter 'heyu help' for commands.)\n"); return 1; } verbose = optptr->verbose; if( verbose ) printf( "Version:%4s\n", VERSION ); /* Remove the tokens used for options from the argument list */ for ( i = 1; i < (argc - ntokens); i++ ) { argv[i] = argv[i + ntokens]; } argc -= ntokens; if ( strcmp(argv[1], "list") == 0 ) { c_list(); return 0; } if ( strcmp(argv[1], "help") == 0 || strcmp(argv[1], "syn") == 0 || strcmp(argv[1], "linewidth") == 0 ) { c_command(argc, argv); return 0; } if ( strcmp(argv[1], "utility") == 0 ) { c_utility(argc, argv); return 0; } if ( strcmp(argv[1], "modlist") == 0 ) { return c_modlist(argc, argv); } else if ( strcmp(argv[1], "conflist") == 0 ) { return c_conflist(argc, argv); } else if ( strcmp(argv[1], "stateflaglist") == 0 ) { return c_stateflaglist(argc, argv); } else if ( strcmp(argv[1], "masklist") == 0 ) { return c_masklist(argc, argv); } #if 0 if ( strcmp(argv[1], "webhook") == 0 ) { c_webhook(argc, argv); return 0; } #endif if ( strcmp(argv[1], "show") == 0 ) { retcode = c_show1(argc, argv); if ( retcode == 0 ) { free_all_arrays(configp); return 0; } } /* Commands other than those handled above require */ /* a configuration file and file locking. */ if ( strcmp(argv[1], "stop") == 0 ) read_minimal_config ( CONFIG_INIT, SRC_STOP ); else read_config(CONFIG_INIT); if ( is_heyu_cmd(argv[1]) ) { /* This is a direct command */ c = cmdtab; rtn = c->cmd_routine; } else { /* This is an administrative or state command */ for (c = cmdtab + 1; c->cmd_routine != NULL; c++) { if (strcmp(argv[1], c->cmd_name) == 0) { if ( !(configp->device_type & DEV_DUMMY) || c->internal_cmd ) { rtn = c->cmd_routine; break; } else { fprintf(stderr, "Command '%s' is not valid for TTY dummy\n", c->cmd_name); return 1; } } } } if ( rtn == NULL ) { fprintf(stderr, "Usage: heyu [options] <command> (Enter 'heyu help' for commands.)\n"); return 1; } if ( (strcmp("stop", c->cmd_name) == 0 ) || (strcmp("version", c->cmd_name) == 0) || (strcmp("help", c->cmd_name) == 0) ) { retcode = (*rtn)(); /* exits */ free_all_arrays(configp); return retcode; } /* Check read/write permissions for spoolfile directory */ if ( check_dir_rw(SPOOLDIR, "SPOOL") != 0 ) { fprintf(stderr, "%s\n", error_message()); return 1; } if ( quick_ports_check() != 0 ) { fprintf(stderr, "Serial port %s is in use by another program.\n", configp->ttyaux); return 1; } if ( c->lock_needed == 1 ) { if ( lock_for_write() < 0 ) error("Program exiting.\n"); port_locked = 1; } argptr = argv[0]; /* Setup alert command arrays */ create_alerts(); /* Check for and start relay if not already running */ start_relay(configp->tty); if ( ! i_am_relay ) { setup_sp_tty(); } if ( strcmp("start", c->cmd_name) == 0 && check_for_engine() != 0 && configp->start_engine == AUTOMATIC ) { if ( heyu_parent == D_CMDLINE ) printf("starting heyu_engine\n"); init("engine"); c_start_engine(argc, argv); } if ( strcmp("start", c->cmd_name) == 0 && check_for_aux() != 0 && configp->ttyaux[0] != '\0' ) { if ( heyu_parent == D_CMDLINE ) printf("starting heyu_aux\n"); init("aux"); c_start_aux(argc, argv); } #ifdef MINIEXCH mxconnect(MINIXPORT); #endif init(c->cmd_name); retcode = (*rtn) (argc, argv); if ( port_locked == 1 ) { sprintf(writefilename, "%s%s", WRITEFILE, configp->suffix); munlock(writefilename); } free_all_arrays(configp); return retcode; }
int main(int argc, char ** argv) { options_t options; int master_fd, slave_fd; pid_t relay_pid, timer_pid, solution_pid, pid; int status; if (!options_get(argc, argv, &options)) return EXITCODE_USAGE_ERROR; options_display(stderr, &options); /* Open a pseudo terminal. Start the child in a new process; it uses the * pseudo terminal for its stdin, stdout, and stderr. Start a process whose * job it is to relay data bidirectionally between our stdin/out and the * child's. Start a timer to enforce the user time limit. */ if ( !pty_open_raw(&master_fd, &slave_fd) || !start_child(&solution_pid, master_fd, slave_fd, &options) || !start_relay(&relay_pid, master_fd, slave_fd) || !start_timer(&timer_pid, master_fd, slave_fd, options.resource_limits.max_user_time_in_seconds) ) return EXITCODE_INTERNAL_ERROR; close(master_fd); close(slave_fd); /* Wait for a child to end, but wait again if the first we see happens to * be the relay (seeing the relay end is inconclusive). The real race is * between the timer and child processes. */ do { pid = wait(&status); if (pid == -1) return EXITCODE_INTERNAL_ERROR; } while (pid == relay_pid); if (pid == timer_pid) { /* The timer ended first, which means the child took too much user * time. */ process_destroy(solution_pid); process_destroy(relay_pid); return EXITCODE_USER_TIME_LIMIT_EXCEEDED; } if (pid == solution_pid) { process_destroy(timer_pid); process_destroy(relay_pid); /* The child ended first. If it exited normally, communicate that to * the caller. */ if (WIFEXITED(status)) return EXITCODE_PROGRAM_EXITED; /* It didn't exit normally. Maybe it got killed by the kernel with * SIGKILL for taking too much CPU time, or killed by some other signal * we didn't expect. */ if (WIFSIGNALED(status)) return WTERMSIG(status) == SIGKILL ? EXITCODE_CPU_TIME_LIMIT_EXCEEDED : exitcode_for_fatal_signal(WTERMSIG(status)); } /* Something strange happened. */ return EXITCODE_INTERNAL_ERROR; }