/* pass_on() * Is the work loop of the logger. Selects on the pipe to the to_erl * program erlang. If input arrives from to_erl it is passed on to * erlang. */ static void pass_on(pid_t childpid) { int len; fd_set readfds; fd_set writefds; fd_set* writefds_ptr; struct timeval timeout; time_t last_activity; char buf[BUFSIZ]; char log_alive_buffer[ALIVE_BUFFSIZ+1]; int lognum; int rfd, wfd=0, lfd=0; int maxfd; int ready; int got_some = 0; /* from to_erl */ /* Open the to_erl pipe for reading. * We can't open the writing side because nobody is reading and * we'd either hang or get an error. */ if ((rfd = sf_open(fifo2, O_RDONLY|DONT_BLOCK_PLEASE, 0)) < 0) { ERRNO_ERR1(LOG_ERR,"Could not open FIFO '%s' for reading.", fifo2); exit(1); } #ifdef DEBUG status("run_erl: %s opened for reading\n", fifo2); #endif /* Open the log file */ lognum = find_next_log_num(); lfd = open_log(lognum, O_RDWR|O_APPEND|O_CREAT|O_SYNC); /* Enter the work loop */ while (1) { int exit_status; maxfd = MAX(rfd, mfd); maxfd = MAX(wfd, maxfd); FD_ZERO(&readfds); FD_SET(rfd, &readfds); FD_SET(mfd, &readfds); FD_ZERO(&writefds); if (outbuf_size() == 0) { writefds_ptr = NULL; } else { FD_SET(wfd, &writefds); writefds_ptr = &writefds; } time(&last_activity); timeout.tv_sec = log_alive_minutes*60; /* don't assume old BSD bug */ timeout.tv_usec = 0; ready = select(maxfd + 1, &readfds, writefds_ptr, NULL, &timeout); if (ready < 0) { if (errno == EINTR) { if (waitpid(childpid, &exit_status, WNOHANG) == childpid) { /* * The Erlang emulator has terminated. Give us some more * time to write out any pending data before we terminate too. */ alarm(5); } FD_ZERO(&readfds); FD_ZERO(&writefds); } else { /* Some error occured */ ERRNO_ERR0(LOG_ERR,"Error in select."); exit(1); } } else { time_t now; if (waitpid(childpid, &exit_status, WNOHANG) == childpid) { alarm(5); FD_ZERO(&readfds); FD_ZERO(&writefds); } /* Check how long time we've been inactive */ time(&now); if(!ready || now - last_activity > log_activity_minutes*60) { /* Either a time out: 15 minutes without action, */ /* or something is coming in right now, but it's a long time */ /* since last time, so let's write a time stamp this message */ struct tm *tmptr; if (log_alive_in_gmt) { tmptr = gmtime(&now); } else { tmptr = localtime(&now); } if (!strftime(log_alive_buffer, ALIVE_BUFFSIZ, log_alive_format, tmptr)) { strn_cpy(log_alive_buffer, sizeof(log_alive_buffer), "(could not format time in 256 positions " "with current format string.)"); } log_alive_buffer[ALIVE_BUFFSIZ] = '\0'; sn_printf(buf, sizeof(buf), "\n===== %s%s\n", ready?"":"ALIVE ", log_alive_buffer); write_to_log(&lfd, &lognum, buf, strlen(buf)); } } /* * Write any pending output first. */ if (FD_ISSET(wfd, &writefds)) { int written; char* buf = outbuf_first(); len = outbuf_size(); written = sf_write(wfd, buf, len); if (written < 0 && errno == EAGAIN) { /* * Nothing was written - this is really strange because * select() told us we could write. Ignore. */ } else if (written < 0) { /* * A write error. Assume that to_erl has terminated. */ clear_outbuf(); sf_close(wfd); wfd = 0; } else { /* Delete the written part (or all) from the buffer. */ outbuf_delete(written); } } /* * Read master pty and write to FIFO. */ if (FD_ISSET(mfd, &readfds)) { #ifdef DEBUG status("Pty master read; "); #endif if ((len = sf_read(mfd, buf, BUFSIZ)) <= 0) { sf_close(rfd); if(wfd) sf_close(wfd); sf_close(mfd); unlink(fifo1); unlink(fifo2); if (len < 0) { if(errno == EIO) ERROR0(LOG_ERR,"Erlang closed the connection."); else ERRNO_ERR0(LOG_ERR,"Error in reading from terminal"); exit(1); } exit(0); } write_to_log(&lfd, &lognum, buf, len); /* * Save in the output queue. */ if (wfd) { outbuf_append(buf, len); } } /* * Read from FIFO, write to master pty */ if (FD_ISSET(rfd, &readfds)) { #ifdef DEBUG status("FIFO read; "); #endif if ((len = sf_read(rfd, buf, BUFSIZ)) < 0) { sf_close(rfd); if(wfd) sf_close(wfd); sf_close(mfd); unlink(fifo1); unlink(fifo2); ERRNO_ERR0(LOG_ERR,"Error in reading from FIFO."); exit(1); } if(!len) { /* to_erl closed its end of the pipe */ sf_close(rfd); rfd = sf_open(fifo2, O_RDONLY|DONT_BLOCK_PLEASE, 0); if (rfd < 0) { ERRNO_ERR1(LOG_ERR,"Could not open FIFO '%s' for reading.", fifo2); exit(1); } got_some = 0; /* reset for next session */ } else { if(!wfd) { /* Try to open the write pipe to to_erl. Now that we got some data * from to_erl, to_erl should already be reading this pipe - open * should succeed. But in case of error, we just ignore it. */ if ((wfd = sf_open(fifo1, O_WRONLY|DONT_BLOCK_PLEASE, 0)) < 0) { status("Client expected on FIFO %s, but can't open (len=%d)\n", fifo1, len); sf_close(rfd); rfd = sf_open(fifo2, O_RDONLY|DONT_BLOCK_PLEASE, 0); if (rfd < 0) { ERRNO_ERR1(LOG_ERR,"Could not open FIFO '%s' for reading.", fifo2); exit(1); } wfd = 0; } else { #ifdef DEBUG status("run_erl: %s opened for writing\n", fifo1); #endif } } if (!got_some && wfd && buf[0] == '\014') { char wbuf[30]; int wlen = sn_printf(wbuf,sizeof(wbuf),"[run_erl v%u-%u]\n", RUN_ERL_HI_VER, RUN_ERL_LO_VER); outbuf_append(wbuf,wlen); } got_some = 1; /* Write the message */ #ifdef DEBUG status("Pty master write; "); #endif len = extract_ctrl_seq(buf, len); if(len==1 && buf[0] == '\003') { kill(childpid,SIGINT); } else if (len>0 && write_all(mfd, buf, len) != len) { ERRNO_ERR0(LOG_ERR,"Error in writing to terminal."); sf_close(rfd); if(wfd) sf_close(wfd); sf_close(mfd); exit(1); } } #ifdef DEBUG status("OK\n"); #endif } } } /* pass_on() */
int main( int argc, char **argv ) { int i; QString m1,n1,o1; struct args pargs; QApplication *a; InitWidget *b; ScreenWidget *c; TextWidget *textOut; QProgressDialog *qProg; QPixmap *qpxMeshIcon=NULL; struct model_error model1,model2; int rcode; struct outbuf *log; struct prog_reporter pr; /* Initialize application */ a = NULL; b = NULL; c = NULL; qProg = NULL; memset(&model1,0,sizeof(model1)); memset(&model2,0,sizeof(model2)); memset(&pr,0,sizeof(pr)); log = NULL; i = 0; while (i<argc) { if (strcmp(argv[i],"-t") == 0) /* text version requested */ break; if (strcmp(argv[i],"-h") == 0) /* just asked for command line help */ break; i++; } if (i == argc) { /* no text version requested, initialize QT */ a = new QApplication( argc, argv ); /* Load pixmap for icon */ qpxMeshIcon = new QPixmap((const char**)meshIcon); if (a != NULL) a->connect( a, SIGNAL(lastWindowClosed()), a, SLOT(quit()) ); } else { a = NULL; /* No QT app needed */ } /* Parse arguments */ parse_args(argc,argv,&pargs); /* Display starting dialog if insufficient arguments */ if (pargs.m1_fname != NULL || pargs.m2_fname != NULL) { if (pargs.m1_fname == NULL || pargs.m2_fname == NULL) { fprintf(stderr,"ERROR: missing file name(s) in command line\n"); exit(1); } if (!pargs.do_wlog) { log = outbuf_new(stdio_puts,stdout); } else { textOut = new TextWidget(); textOut->setIcon(*qpxMeshIcon); log = outbuf_new(TextWidget_puts,textOut); textOut->show(); } if (pargs.no_gui) { pr.prog = stdio_prog; pr.cb_out = stdout; } else { qProg = new QProgressDialog("Calculating distance",0,100); qProg->setIcon(*qpxMeshIcon); qProg->setMinimumDuration(1500); pr.prog = QT_prog; pr.cb_out = qProg; } mesh_run(&pargs, &model1, &model2, log, &pr); } else { b = new InitWidget(pargs, &model1, &model2); b->setIcon(*qpxMeshIcon); b->show(); } if (a != NULL) { if (pargs.m1_fname != NULL || pargs.m2_fname != NULL) { c = new ScreenWidget(&model1, &model2, &pargs); c->setIcon(*qpxMeshIcon); a->setMainWidget(c); c->show(); } rcode = a->exec(); } else { rcode = 0; } /* Free widgets */ outbuf_delete(log); delete qProg; delete qpxMeshIcon; delete b; delete c; delete a; // QApplication must be last QT thing to delete /* Free model data */ if (model1.mesh != NULL) __free_raw_model(model1.mesh); free(model1.verror); free(model1.info); free_face_error(model1.fe); if (model2.mesh != NULL) __free_raw_model(model2.mesh); free(model2.verror); free(model2.info); /* Return exit code */ return rcode; }