home *** CD-ROM | disk | FTP | other *** search
- #include <signal.h>
- #include <sys/wait.h>
- #include <sys/time.h>
- #include <sys/resource.h>
-
- #include "edit.h"
- #include "global.h"
- #include "cat.h"
- #include "control.h"
- #include "util.h"
- #include "history.h"
-
- #include <dirent.h>
- #include <ctype.h>
-
- #define DEFAULT_EDITOR "ded"
- #define MIN_AGE 4*60*60 /* minimum age of drivel files in secs */
-
- #define smaller(a,b) a * 10 < b * 7 || b - a > 1700
-
- extern char *strcat(), *rindex(), *strncpy();
- extern int strncmp();
-
- static int editor; /* pid of editor child */
- static byte edit_over = 0; /* flag set by SIGCHLD */
- static char *text_copy; /* file name of text_file's copy */
-
- /* void tidy_up()
- *
- * Routine called on receiving a terminating signal, such as TERM, QUIT or
- * HUP. It releases locks, and removes backup files before quitting. Also
- * kills the editor.
- */
- static void tidy_up()
- {
- (void) kill ( editor, SIGTERM );
- (void) lock ( REMVE );
- (void) unlink ( text_copy );
- (void) fprintf ( stderr, "\r\n\007** %s: received terminating signal - quitting.\n", file );
- exit ( 3 );
- }
-
- /* void force_off()
- *
- * This routine is called when SIGALRM is received. It prints a final
- * warning to the user, and then kills his editor after waiting a further
- * short time. This will cause him to stop using gosip.
- */
- static void force_off()
- {
- puts ( "\r\n\007** Edit session terminating almost immediately. **\r" );
- sleep ( 5 );
- (void) kill ( editor, SIGTERM );
- }
-
- /* void child()
- *
- * Called whenever a SIGCHLD is received. It checks if the editor has
- * actually exit()ed - it might have changed state by being suspended - and
- * sets the global flag edit_over if it has.
- */
- static void child()
- {
- if ( editor == wait3 ( (union wait *) 0, WNOHANG, (struct rusage *) 0 ) )
- edit_over = 1;
- }
-
- /* void do_nothing()
- *
- * This routine does literally nothing. It is needed as you have to call
- * something when you get SIGALRM.
- */
- static void do_nothing()
- {
- }
-
- /* void manifesto()
- *
- * Checks for the file info.gosip and prints its contents.
- * Currently unimplemented.
- */
- /*
- static void manifesto()
- {
- FILE *info_file;
- char info_filename[MAX_LENGTH];
- int c;
-
- (void) strcpy ( info_filename, "info." );
- (void) strcat ( info_filename, file );
- if ( info_file = fopen ( info_filename, "r" ) )
- {
- while ( ( c = getc ( info_file ) ) != EOF )
- (void) putchar ( (char) c );
- (void) fclose ( info_file );
- }
- }
- */
-
- /* char *copy ( source, destination )
- *
- * Copies the source file into the destination file. If destination is null,
- * a filename in /tmp is generated and used as destination. Returns the
- * destination file on success, otherwise a null pointer.
- *
- * source : filename from which to copy.
- * destination : filename to which to copy.
- */
- static char *copy ( source, destination )
- char *source, *destination;
- {
- FILE *sp, *dp;
- int c;
-
- if ( ! destination )
- {
- char temp[6];
-
- (void) strncpy ( temp, file, 5 );
- temp[5] = '\0';
- destination = tempnam ( "/tmp", temp );
- }
- if ( ! destination )
- {
- perror ( "Couldn't get a temp file" );
- return (char *) 0;
- }
- if ( ! ( sp = fopen ( source, "r" ) ) )
- {
- perror ( "Couldn't open source file" );
- return (char *) 0;
- }
- if ( ! ( dp = fopen ( destination, "w" ) ) )
- {
- perror ( "Couldn't open destination file" );
- (void) fclose ( sp );
- return (char *) 0;
- }
- while ( ( c = getc ( sp ) ) != EOF )
- if ( putc ( (char) c, dp ) == EOF )
- {
- puts ( "Couldn't copy to destination file." );
- (void) fclose ( dp );
- (void) fclose ( sp );
- return (char *) 0;
- }
- (void) fclose ( sp );
- if ( fclose ( dp ) == EOF )
- {
- perror ( "Error closing destination file" );
- return (char *) 0;
- }
- return destination;
- }
-
- /* byte changed ( i_size )
- *
- * This will compare the text_file against the copy, and returns 0 if they
- * are identical in content, otherwise 1. That is, it also returns 1 if
- * either file couldn't be read or some other error occured. It also
- * contains code checking for an excessive reduction in the size of the copy,
- * which asks the user to confirm that he wants to keep the smaller file.
- *
- * i_size : inital size of text_file.
- */
- static byte changed ( i_size )
- int i_size;
- {
- FILE *tp, *cp;
- int c;
- byte result = 0;
- struct stat final;
-
- if ( stat ( text_copy, &final ) == 0 )
- if ( smaller ( final.st_size, i_size ) )
- {
- char ans[10];
-
- while ( 1 ) /* leave loop by 'break' */
- {
- (void) printf ( "The %s file is now somewhat smaller - from %d down to %d bytes.\nDo you want to keep it like this? ", file, i_size, final.st_size );
- result = 1;
- if ( ! fgets ( ans, 10, stdin ) )
- *ans = '\0';
- if ( ! strncmp ( "no", ans, 2 ) )
- {
- (void) unlink ( text_copy );
- (void) free ( text_copy );
- result = 0;
- break;
- }
- if ( ! strncmp ( "yes", ans, 3 ) )
- {
- result = 2; /* flag proceed as normal */
- break;
- }
- puts ( "Answer 'yes' or 'no'.\n" );
- }
- if ( result < 2 )
- {
- (void) unlink ( text_copy );
- (void) free ( text_copy );
- return result;
- }
- }
-
- if ( result < 2 )
- {
- if ( ! ( tp = fopen ( text_file, "r" ) ) )
- result = 1;
- else
- {
- if ( ! ( cp = fopen ( text_copy, "r" ) ) )
- result = 1;
- else
- {
- do
- {
- if ( ( c = getc ( tp ) ) != getc ( cp ) )
- {
- result = 1;
- break;
- }
- }
- while ( c != EOF );
- (void) fclose ( cp );
- }
- (void) fclose ( tp );
- }
- }
-
- if ( ! copy ( text_copy, text_file ) )
- result = 0;
- (void) unlink ( text_copy );
- (void) free ( text_copy );
- return result;
- }
-
- /* void do_edit ( kind, extra_file )
- *
- * This is the routine that actually lets you edit the gosip file. It
- * fork()s off a process which becomes the editor. While that is running it
- * check every ten seconds whether the DOWN_FILE exists, and stops the edit
- * if it does.
- *
- * It also updates last_file & history_file, checks for files that shouldn't
- * be in the directory and removes them, prints info about the file (not yet
- * implemented), and deals with the file already being edited - normally by
- * calling catfile(), but see desciption of 'kind' below.
- *
- * kind : specifes the type of edit. It is an enumerated type
- * covering
- * normal - straight edit
- * abort - do not invoke catfile() if gosip is being edited.
- * cflag - use emacs with extra_file as editor.
- * extra_file : this file is passed to emacs as well as text_file if kind
- * is cflag. This is only used by Geoff's program.
- */
- void do_edit ( kind, extra_file )
- enum edit_type kind;
- char *extra_file;
- {
- int mask, init_size = -1;
- FILE *fp;
- time_t now;
- struct stat info;
- byte lock_status;
-
- mask = sigblock ( sigmask ( SIGALRM ) | sigmask ( SIGCHLD ) );
- (void) signal ( SIGINT, SIG_IGN );
- (void) signal ( SIGCHLD, child );
- (void) signal ( SIGTERM, tidy_up );
- (void) signal ( SIGHUP, tidy_up );
- (void) signal ( SIGQUIT, tidy_up );
- if ( ( lock_status = lock ( CREAT ) ) == -1 )
- { /* error creating lock */
- (void) printf ( "Please refer to your local %s maintainer.\n", file );
- exit ( 2 );
- }
- if ( lock_status )
- { /* gosip is already being edited */
- if ( kind == abort || kind == cflag )
- {
- lastedit ( EDIT );
- exit ( 1 );
- }
- else
- catfile ( being_edited );
- }
- lastedit ( INFO );
- (void) putchar ( '\n' );
-
- if ( fp = fopen ( last_file , "w" ) )
- { /* put user into last_file */
- (void) fprintf ( fp, "%s (%s)\n", gosname(), usercode() );
- if ( fclose ( fp ) == -1 )
- perror ( "Problem closing last file" );
- }
- else
- perror ( "Couldn't write last usage info" );
-
- (void) time ( &now );
- #if 0
- manifesto(); /* print info about this gosip file */
- #endif
- if ( stat ( text_file, &info ) == 0 )
- init_size = info.st_size; /* store initial size for history info. */
- if ( ! ( text_copy = copy ( text_file, (char *) 0 ) ) )
- exit ( 2 ); /* make copy which is actually edited */
-
- if ( ( editor = fork() ) == -1 )
- {
- perror ( "Fork failed" );
- (void) lock ( REMVE );
- (void) unlink ( text_copy );
- exit ( 2 );
- }
- if ( editor == 0 )
- {
- char *visual;
-
- if ( ! ( visual = getenv ( "VISUAL" ) ) )
- if ( ! ( visual = getenv ( "EDITOR" ) ) )
- visual = DEFAULT_EDITOR;
- if ( kind == cflag )
- execlp ( visual, visual, extra_file, text_copy, (char *) 0 );
- else
- execlp ( visual, visual, text_copy, (char *) 0 );
- (void) fprintf ( stderr, "Couldn't invoke your editor.\n" );
- perror ( visual );
- exit ( 2 );
- }
-
- (void) signal ( SIGALRM, do_nothing );
- while ( ! edit_over ) /* wait for child to die */
- {
- static byte mes_delivered = 0;
- FILE *fp;
-
- if ( ! mes_delivered )
- (void) alarm ( 10 );
- (void) sigpause ( mask );
- if ( ! ( mes_delivered || edit_over ) )
- if ( fp = fopen ( DOWN_FILE, "r" ) )
- {
- char mes[80], *temp;
-
- (void) fgets ( mes, 79, fp );
- if ( temp = rindex ( mes, '\n' ) )
- *temp = '\0';
- (void) fclose ( fp );
- (void) printf ( "\r\n\007** %s is going down for maintenance. **\r\n", file );
- (void) printf ( " ... %s. \r\n", mes );
- puts ( "** Please stop editing now. **\r" );
- (void) printf ( "** You will probably be informed when %s is available again. **\r\n", file );
- mes_delivered = 1;
- (void) add_user();
- (void) signal ( SIGALRM, force_off );
- (void) alarm ( 50 );
- }
- }
-
- (void) alarm ( 0 );
- (void) sigsetmask ( mask );
- update_history ( now, init_size, changed ( init_size ) ? edit : no_change );
- (void) lock ( REMVE );
-
- exit ( 0 );
- }
-