/* * Copyright (c) 1998 Regents of The University of Michigan. * All Rights Reserved. See COPYRIGHT. */ /*********** publish.c **********/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "nefu.h" #define BUF_LEN 1024 int html_footer( int err_type, FILE *out, int directory_levels ) { char buf[ BUF_LEN + 1 ]; char fname[ MAXPATHLEN ]; FILE *in; int x; struct stat stat_buf; fprintf( out, "
\n" ); fprintf( out, "\n" ); fprintf( out, "\n" ); sprintf( fname, "%s/%s", nefu_html_dir, HTML_LOGO ); fprintf( out, "\n" ); fprintf( out, "\n
\n" ); fprintf( out, "status\n" ); fprintf( out, "dependencies\n" ); fprintf( out, "machines\n" ); fprintf( out, "groups\n", HTML_GROUPS ); fprintf( out, "\n" ); fprintf( out, "nefu %s", nefu_version ); if ( stat( fname, &stat_buf ) == 0 ) { if (( stat_buf.st_mode & S_IROTH ) != 0 ) { fprintf( out, "\"nefu\n", HTML_LOGO ); } } fprintf( out, "
\n" ); sprintf( fname, "%s/%s", nefu_html_dir, HTML_FOOTER ); errno = 0; if (( in = fopen( fname, "r" )) != NULL ) { /* found HTML_FOOTER */ fprintf( out, "\n" ); while ( fgets( buf, BUF_LEN, in ) != NULL ) { fprintf( out, "%s", buf ); } fprintf( out, "\n" ); if ( fclose( in ) != 0 ) { if ( err_type == ERROR_SYSLOG ) { syslog( LOG_ERR, "fclose: %s: %m", fname ); } else if ( err_type == ERROR_STDERR ) { fprintf( stderr, "fclose: %s: ", fname ); perror( NULL ); } return( 1 ); } } else { if ( errno != ENOENT ) { if ( err_type == ERROR_SYSLOG ) { syslog( LOG_ERR, "fopen: %s: %m", fname ); } else if ( err_type == ERROR_STDERR ) { fprintf( stderr, "fopen: %s: ", fname ); perror( NULL ); } return( 1 ); } fprintf( out, "\n" ); } fprintf( out, "\n" ); return( 0 ); } int html_header( int err_type, FILE *out, int directory_levels, char *title ) { char buf[ BUF_LEN + 1 ]; char fname[ MAXPATHLEN ]; FILE *in; int x; struct stat stat_buf; sprintf( fname, "%s/%s", nefu_html_dir, HTML_HEADER ); errno = 0; fprintf( out, "nefu version %s", nefu_version ); if (( title != NULL ) && ( *title != '\0' )) { fprintf( out, ": %s", title ); fprintf( out, "\n" ); if (( strcmp( title, "status" ) == 0 ) && ( nefu_html_reload > 0 )) { fprintf( out, "\n", nefu_html_reload ); } } else { fprintf( out, "\n" ); if ( nefu_html_reload > 0 ) { fprintf( out, "\n", nefu_html_reload ); } } if (( in = fopen( fname, "r" )) != NULL ) { /* found HTML_HEADER */ fprintf( out, "\n" ); while ( fgets( buf, BUF_LEN, in ) != NULL ) { fprintf( out, "%s", buf ); } fprintf( out, "\n" ); if ( fclose( in ) != 0 ) { if ( err_type == ERROR_SYSLOG ) { syslog( LOG_ERR, "fclose: %s: %m", fname ); } else if ( err_type == ERROR_STDERR ) { fprintf( stderr, "fclose: %s: ", fname ); perror( NULL ); } return( 1 ); } } else { if ( errno != ENOENT ) { if ( err_type == ERROR_SYSLOG ) { syslog( LOG_ERR, "fopen: %s: %m", fname ); } else if ( err_type == ERROR_STDERR ) { fprintf( stderr, "fopen: %s: ", fname ); perror( NULL ); } return( 1 ); } fprintf( out, "\n" ); fprintf( out, "\n" ); fprintf( out, "\n" ); } fprintf( out, "\n" ); fprintf( out, "\n" ); sprintf( fname, "%s/%s", nefu_html_dir, HTML_LOGO ); fprintf( out, "\n" ); fprintf( out, "\n
\n" ); fprintf( out, "status\n" ); fprintf( out, "dependencies\n" ); fprintf( out, "machines\n" ); fprintf( out, "groups\n", HTML_GROUPS ); fprintf( out, "\n" ); fprintf( out, "nefu %s", nefu_version ); if ( stat( fname, &stat_buf ) == 0 ) { if (( stat_buf.st_mode & S_IROTH ) != 0 ) { fprintf( out, "\"nefu\n", HTML_LOGO ); } } fprintf( out, "
\n" ); fprintf( out, "
\n" ); return( 0 ); } void html_machine_dns( FILE *f, struct machine *m, u_long pass, int levels ) { int x; if ( m != NULL ) { fprintf( f, "%sIP Address%ld" "%s", m->m_html_name, m->m_name, pass, ctime((time_t *)(&m->m_test->t_time_down.tv_sec))); if ( m->m_dns_status == MACHINE_NO_DNS ) { fprintf( f, "IP Address not found\n" ); } else { fprintf( f, "Multiple IP Addresses found\n" ); } html_machine_dns( f, m->m_next_dns, pass, levels ); } } int html_log_downs( FILE *f, struct test *t, int directory_levels ) { int i; int x; if ( t != NULL ) { if (( t->t_status & T_DOWN_MASK ) != 0 ) { fprintf( f, "%s%s" "%ld%s%s\n", t->t_machine->m_html_name, t->t_machine->m_name, t->t_full_name, t->t_tested - t->t_pass_down, ctime((time_t *)(&t->t_time_down.tv_sec)), (( t->t_report == NULL ) || ( t->t_report->r_buf == NULL )) ? "No report" : t->t_report->r_buf ); i = 1; } else { i = html_log_downs( f, t->t_child, directory_levels ); } return( i + html_log_downs( f, t->t_peer, directory_levels )); } return( 0 ); } void html_default_page( char *fname, struct timeval *tv ) { char html[ MAXPATHLEN ]; int fd; FILE *f; /* build full pathname */ sprintf( html, "%s/%s", nefu_html_dir, fname ); if (( fd = creat( html, 0666 )) < 0 ) { fprintf( stderr, "open: %s: ", html ); perror( NULL ); exit( 1 ); } if (( f = fdopen( fd, "w" )) == NULL ) { perror( "fdopen" ); exit( 1 ); } /* print header */ if ( html_header( ERROR_STDERR, f, 0, NULL ) != 0 ) { exit( 1 ); } /* print startup message */ fprintf( f, "nefu version %s starting %s
", nefu_version, ctime((time_t *)(&(tv->tv_sec )))); /* print footer */ if ( html_footer( ERROR_STDERR, f, 0 ) != 0 ) { exit( 1 ); } if ( fclose( f ) != 0 ) { perror( "fclose" ); exit( 1 ); } } void history_init( struct schedule *s, struct timeval *tv_now ) { struct timeval tv_last_event; int fd_html; int fd_history; FILE *f_html; FILE *f_history; char html[ MAXPATHLEN ]; char history[ MAXPATHLEN ]; char history_tmp[ MAXPATHLEN ]; char history_dir[ MAXPATHLEN ]; if ( nefu_html_history == 0 ) { return; } /* get previous nefu's last published event, or create the history dir */ sprintf( history, "%s/%s/%s", nefu_html_dir, HTML_HISTORY_DIR, NEFU_LAST_EVENT_FILE ); if (( f_history = fopen( history, "r" )) == NULL ) { if ( errno != ENOENT ) { fprintf( stderr, "fopen: %s: ", history ); perror( NULL ); exit( 1 ); } sprintf( history_dir, "%s/%s", nefu_html_dir, HTML_HISTORY_DIR ); if ( directory( history_dir ) != 0 ) { exit( 1 ); } } else { fscanf( f_history, "%ld", &s->s_published.tv_sec ); if ( fclose ( f_history ) != 0 ) { perror( "fclose" ); exit( 1 ); } if ( s->s_published.tv_sec >= tv_now->tv_sec ) { fprintf( stderr, "%s: timestamp is from the future\n", history ); exit( 1 ); } } /* output restart html */ sprintf( html, "%s/%s/%ld.html", nefu_html_dir, HTML_HISTORY_DIR, tv_now->tv_sec ); if (( fd_html = creat( html, 0666 )) < 0 ) { fprintf( stderr, "open: %s: ", html ); perror( NULL ); exit( 1 ); } if (( f_html = fdopen( fd_html, "w" )) == NULL ) { perror( "fdopen" ); exit( 1 ); } if ( html_header( ERROR_SYSLOG, f_html, 1, "history" ) != 0 ) { exit( 1 ); } fprintf( f_html, "
" ); fprintf( f_html, "nefu version %s starting %s \n", nefu_version, ctime((time_t *)( &tv_now->tv_sec ))); fprintf( f_html, "" ); if ( s->s_published.tv_sec > 0 ) { tv_last_event.tv_sec = tv_now->tv_sec - s->s_published.tv_sec; tv_last_event.tv_usec = 0; fprintf( f_html, "last event %s ago\n", s->s_published.tv_sec, time_down( &tv_last_event )); } fprintf( f_html, "
\n" ); if ( html_footer( ERROR_SYSLOG, f_html, 1 ) != 0 ) { exit( 1 ); } if ( fclose( f_html ) != 0 ) { perror( "fclose" ); exit( 1 ); } s->s_published.tv_sec = tv_now->tv_sec; /* update html last event file */ sprintf( history_tmp, "%s.XXXXXX", history ); if (( fd_history = mkstemp( history_tmp )) < 0 ) { fprintf( stderr, "mkstemp: %s: %m", history_tmp ); exit( 1 ); } if ( fchmod( fd_history, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ) != 0 ) { fprintf( stderr, "fchmod: %m" ); exit( 1 ); } if (( f_history = fdopen( fd_history, "w" )) == NULL ) { fprintf( stderr, "fdopen: %m" ); exit( 1 ); } fprintf( f_history, "%ld", s->s_published.tv_sec ); if ( fclose( f_history ) != 0 ) { fprintf( stderr, "fclose: %m" ); exit( 1 ); } if ( rename( history_tmp, history ) < 0 ) { fprintf( stderr, "rename %s %s: %m", history_tmp, history ); exit( 1 ); } } void html_init( struct schedule *s ) { struct timeval tv; if ( nefu_html_dir == NULL ) { return; } if ( gettimeofday( &tv, NULL ) < 0 ) { syslog( LOG_ERR, "gettimeofday: %m" ); exit( 1 ); } html_default_page( HTML_PLAN, &tv ); html_default_page( HTML_DEPMAP_ROOT, &tv ); html_default_page( HTML_MACHINES, &tv ); html_default_page( HTML_GROUPS, &tv ); history_init( s, &tv ); } int html_plan( struct schedule *s ) { int fd; FILE *f; struct timeval tv_now; struct timeval tv_last_event; char html[ MAXPATHLEN ]; char htmltmp[ MAXPATHLEN ]; if ( nefu_html_dir == NULL ) { syslog( LOG_ERR, "html_plan: no html directory" ); return( 1 ); } sprintf( html, "%s/%s", nefu_html_dir, HTML_PLAN ); sprintf( htmltmp, "%s.XXXXXX", html ); if (( fd = mkstemp( htmltmp )) < 0 ) { syslog( LOG_ERR, "mkstemp: %s: %m", htmltmp ); return( 1 ); } if ( fchmod( fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ) != 0 ) { syslog( LOG_ERR, "fchmod: %m" ); return( 1 ); } if (( f = fdopen( fd, "w" )) == NULL ) { syslog( LOG_ERR, "fdopen: %m" ); return( 1 ); } if ( html_header( ERROR_SYSLOG, f, 0, "status" ) != 0 ) { return( 1 ); } if ( gettimeofday( &tv_now, NULL ) < 0 ) { syslog( LOG_ERR, "gettimeofday: %m" ); return( 1 ); } fprintf( f, "
" ); fprintf( f, "%s pass %ld time %s \n", ctime((time_t *)( &tv_now.tv_sec )), s->s_pass, time_down( &s->s_tv_pass )); fprintf( f, "" ); if (( s->s_published.tv_sec > 0 ) && ( nefu_html_history != 0 )) { tv_last_event.tv_sec = tv_now.tv_sec - s->s_published.tv_sec; tv_last_event.tv_usec = 0; fprintf( f, "last event %s ago\n", HTML_HISTORY_DIR, s->s_published.tv_sec, time_down( &tv_last_event )); } fprintf( f, "
\n" ); fprintf( f, "" "\n", "MACHINE", "SERVICE", "PASSES", "TIME", "ERROR" ); html_machine_dns( f, machines_no_dns, s->s_pass, 0 ); if ( html_log_downs( f, root_nodes, 0 ) == 0 ) { if ( machines_no_dns == NULL ) { fprintf( f, "\n" ); } } fprintf( f, "
%s%s%s%s%s
It's all good.
\n" ); if ( html_footer( ERROR_SYSLOG, f, 0 ) != 0 ) { return( 1 ); } if ( fclose( f ) != 0 ) { syslog( LOG_ERR, "fclose: %m" ); return( 1 ); } if ( rename( htmltmp, html ) < 0 ) { syslog( LOG_ERR, "rename %s %s: %m", htmltmp, html ); return( 1 ); } return( 0 ); } void stdout_machine_dns( FILE *f, struct machine *m, u_long pass ) { if ( m != NULL ) { fprintf( f, "%-15s %-7s %6ld %.16s", m->m_name, "IP Address", pass, ctime((time_t *)(&m->m_test->t_time_down.tv_sec))); if ( m->m_dns_status == MACHINE_NO_DNS ) { fprintf( f, "IP Address not found\n" ); } else { fprintf( f, "Multiple IP Addresses found\n" ); } stdout_machine_dns( f, m->m_next_dns, pass ); } } int stdout_log_downs( FILE *f, struct test *t ) { int i; if ( t != NULL ) { if (( t->t_status & T_DOWN_MASK ) != 0 ) { fprintf( f, "%-15s %-7s %6ld %.16s %s\n", t->t_machine->m_name, t->t_full_name, t->t_tested - t->t_pass_down, ctime((time_t *)( &t->t_time_down.tv_sec )), (( t->t_report == NULL ) || ( t->t_report->r_buf == NULL )) ? "No report" : t->t_report->r_buf ); i = 1; } else { i = stdout_log_downs( f, t->t_child ); } return( i + stdout_log_downs( f, t->t_peer )); } return( 0 ); } int unix_plan( struct schedule *s ) { char plan[ MAXPATHLEN ]; char plantmp[ MAXPATHLEN ]; char project[ MAXPATHLEN ]; char projecttmp[ MAXPATHLEN ]; int fd; FILE *f; struct timeval tv; sprintf( plan, "%s/.plan", nefu_user_dir ); sprintf( project, "%s/.project", nefu_user_dir ); sprintf( plantmp, "%s.XXXXXX", plan ); if (( fd = mkstemp( plantmp )) < 0 ) { syslog( LOG_ERR, "mkstemp: %s: %m", plantmp ); return( 1 ); } if ( fchmod( fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ) != 0 ) { syslog( LOG_ERR, "fchmod: %m" ); return( 1 ); } if (( f = fdopen( fd, "w" )) == NULL ) { syslog( LOG_ERR, "fdopen: %m" ); return( 1 ); } fprintf( f, "%-15s %-7s %-6s %-16s %s\n", "MACHINE", "SERVICE", "PASSES", "TIME", "ERROR" ); stdout_machine_dns( f, machines_no_dns, s->s_pass ); if ( stdout_log_downs( f, root_nodes ) == 0 ) { if ( machines_no_dns == NULL ) { fprintf( f, "It's all good.\n" ); } } if ( fclose( f ) != 0 ) { syslog( LOG_ERR, "fclose: %m" ); return( 1 ); } if ( rename( plantmp, plan ) < 0 ) { syslog( LOG_ERR, "rename %s %s: %m", plantmp, plan ); return( 1 ); } if ( gettimeofday( &tv, NULL ) < 0 ) { syslog( LOG_ERR, "gettimeofday: %m" ); return( 1 ); } sprintf( projecttmp, "%s.XXXXXX", project ); if (( fd = mkstemp( projecttmp )) < 0 ) { syslog( LOG_ERR, "mkstemp: %s: %m", projecttmp ); return( 1 ); } if ( fchmod( fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ) != 0 ) { syslog( LOG_ERR, "fchmod: %m" ); return( 1 ); } if (( f = fdopen( fd, "w" )) == NULL ) { syslog( LOG_ERR, "fdopen: %m" ); return( 1 ); } fprintf( f, "%.16s pass %ld time %s\n", ctime((time_t *)( &tv.tv_sec )), s->s_pass, time_down( &s->s_tv_pass )); if ( fclose( f ) != 0 ) { syslog( LOG_ERR, "fclose: %m" ); return( 1 ); } if ( rename( projecttmp, project ) < 0 ) { syslog( LOG_ERR, "rename %s %s: %m", projecttmp, project ); return( 1 ); } return( 0 ); } int publish( struct schedule *s ) { if ( unix_plan( s ) != 0 ) { return( 1 ); } return( html_plan( s )); } /* This function is called by the monitor after a pass is completed * if there was a state change during that pass. */ int history_update( struct schedule *s ) { int fd; int fd_history; FILE *f; FILE *f_history; struct timeval tv_now; struct timeval tv_last_event; char html[ MAXPATHLEN ]; char history[ MAXPATHLEN ]; char history_tmp[ MAXPATHLEN ]; if (( nefu_html_dir == NULL ) || ( nefu_html_history == 0 )) { return( 0 ); } if ( gettimeofday( &tv_now, NULL ) < 0 ) { syslog( LOG_ERR, "gettimeofday: %m" ); return( 1 ); } if ( tv_now.tv_sec == s->s_published.tv_sec ) { /* here if publishing once a second. not good */ do { sleep( 1 ); if ( gettimeofday( &tv_now, NULL ) < 0 ) { syslog( LOG_ERR, "gettimeofday: %m" ); return( 1 ); } } while ( tv_now.tv_sec == s->s_published.tv_sec ); } sprintf( html, "%s/%s/%ld.html", nefu_html_dir, HTML_HISTORY_DIR, tv_now.tv_sec ); if (( fd = creat( html, 0666 )) < 0 ) { syslog( LOG_ERR, "open: %s: %m", html ); return( 1 ); } if (( f = fdopen( fd, "w" )) == NULL ) { syslog( LOG_ERR, "fdopen: %m" ); return( 1 ); } if ( html_header( ERROR_SYSLOG, f, 1, "history" ) != 0 ) { return( 1 ); } fprintf( f, "
" ); fprintf( f, "%s pass %ld time %s \n", ctime((time_t *)( &tv_now.tv_sec )), s->s_pass, time_down( &s->s_tv_pass )); fprintf( f, "" ); tv_last_event.tv_sec = tv_now.tv_sec - s->s_published.tv_sec; tv_last_event.tv_usec = 0; fprintf( f, "last event %s ago\n", s->s_published.tv_sec, time_down( &tv_last_event )); fprintf( f, "
\n" ); fprintf( f, "" "\n", "MACHINE", "SERVICE", "PASSES", "TIME", "ERROR" ); html_machine_dns( f, machines_no_dns, s->s_pass, 1 ); if ( html_log_downs( f, root_nodes, 1 ) == 0 ) { if ( machines_no_dns == NULL ) { fprintf( f, "\n" ); } } fprintf( f, "
%s%s%s%s%s
It's all good.
\n" ); if ( html_footer( ERROR_SYSLOG, f, 1 ) != 0 ) { return( 1 ); } if ( fclose( f ) != 0 ) { syslog( LOG_ERR, "fclose: %m" ); return( 1 ); } s->s_published.tv_sec = tv_now.tv_sec; /* update html last event file */ sprintf( history, "%s/%s/%s", nefu_html_dir, HTML_HISTORY_DIR, NEFU_LAST_EVENT_FILE ); sprintf( history_tmp, "%s.XXXXXX", history ); if (( fd_history = mkstemp( history_tmp )) < 0 ) { syslog( LOG_ERR, "mkstemp: %s: %m", history_tmp ); return( 1 ); } if ( fchmod( fd_history, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ) != 0 ) { syslog( LOG_ERR, "fchmod: %m" ); return( 1 ); } if (( f_history = fdopen( fd_history, "w" )) == NULL ) { syslog( LOG_ERR, "fdopen: %m" ); return( 1 ); } fprintf( f_history, "%ld", s->s_published.tv_sec ); if ( fclose( f_history ) != 0 ) { syslog( LOG_ERR, "fclose: %m" ); return( 1 ); } if ( rename( history_tmp, history ) < 0 ) { syslog( LOG_ERR, "rename %s %s: %m", history_tmp, history ); return( 1 ); } return( 0 ); }