int read_passwd_list() { char *filename; FILE *fp; char *linebuf = NULL; size_t linebuf_len; passwd_entry *passnode; filename = (char*)xmalloc(strlen(current_parsed_root->directory) + strlen("/CVSROOT/passwd") + 1); strcpy (filename, current_parsed_root->directory); strcat (filename, "/CVSROOT/passwd"); init_passwd_list(); fp = CVS_FOPEN (filename, "r"); if (fp != NULL) { while (getline (&linebuf, &linebuf_len, fp) >= 0) { char *user; if(linebuf[strlen(linebuf)-1]=='\n') linebuf[strlen(linebuf)-1]='\0'; if(linebuf[0]=='#') continue; user = cvs_strtok(linebuf,":"); if(!user || !*user) continue; passnode = new_passwd_entry(); passnode->username=xstrdup(user); passnode->password=xstrdup(cvs_strtok(NULL,":")); passnode->real_username=xstrdup(cvs_strtok(NULL,":")); xfree (linebuf); linebuf = NULL; } if (ferror (fp)) { error (1, errno, "cannot read %s", filename); } if (fclose (fp) < 0) error (0, errno, "cannot close %s", filename); } return 0; }
void mydbm_close (DBM *db) { if (db->modified) { FILE *fp; fp = CVS_FOPEN (db->name, FOPEN_BINARY_WRITE); if (fp == NULL) error (1, errno, "cannot write %s", db->name); walklist (db->dbm_list, write_item, fp); if (fclose (fp) < 0) error (0, errno, "cannot close %s", db->name); } free (db->name); dellist (&db->dbm_list); free (db); }
/* * Builds a temporary file using setup_tmpfile() and invokes the user's * editor on the file. The header garbage in the resultant file is then * stripped and the log message is stored in the "message" argument. * * If REPOSITORY is non-NULL, process rcsinfo for that repository; if it * is NULL, use the CVSADM_TEMPLATE file instead. REPOSITORY should be * NULL when running in client mode. * * GLOBALS * Editor Set to a default value by configure and overridable using the * -e option to the CVS executable. */ void do_editor (const char *dir, char **messagep, const char *repository, List *changes) { static int reuse_log_message = 0; char *line; int line_length; size_t line_chars_allocated; char *fname; struct stat pre_stbuf, post_stbuf; int retcode = 0; assert (!current_parsed_root->isremote != !repository); if (noexec || reuse_log_message) return; /* Abort before creation of the temp file if no editor is defined. */ if (strcmp (Editor, "") == 0) error(1, 0, "no editor defined, must use -e or -m"); again: /* Create a temporary file. */ if( ( fp = cvs_temp_file( &fname ) ) == NULL ) error( 1, errno, "cannot create temporary file" ); if (*messagep) { (void) fputs (*messagep, fp); if ((*messagep)[0] == '\0' || (*messagep)[strlen (*messagep) - 1] != '\n') (void) fprintf (fp, "\n"); } else (void) fprintf (fp, "\n"); if (repository != NULL) /* tack templates on if necessary */ (void) Parse_Info (CVSROOTADM_RCSINFO, repository, rcsinfo_proc, PIOPT_ALL, NULL); else { FILE *tfp; char buf[1024]; size_t n; size_t nwrite; /* Why "b"? */ tfp = CVS_FOPEN (CVSADM_TEMPLATE, "rb"); if (tfp == NULL) { if (!existence_error (errno)) error (1, errno, "cannot read %s", CVSADM_TEMPLATE); } else { while (!feof (tfp)) { char *p = buf; n = fread (buf, 1, sizeof buf, tfp); nwrite = n; while (nwrite > 0) { n = fwrite (p, 1, nwrite, fp); nwrite -= n; p += n; } if (ferror (tfp)) error (1, errno, "cannot read %s", CVSADM_TEMPLATE); } if (fclose (tfp) < 0) error (0, errno, "cannot close %s", CVSADM_TEMPLATE); } } (void) fprintf (fp, "%s----------------------------------------------------------------------\n", CVSEDITPREFIX); (void) fprintf (fp, "%sEnter Log. Lines beginning with `%.*s' are removed automatically\n%s\n", CVSEDITPREFIX, CVSEDITPREFIXLEN, CVSEDITPREFIX, CVSEDITPREFIX); if (dir != NULL && *dir) (void) fprintf (fp, "%sCommitting in %s\n%s\n", CVSEDITPREFIX, dir, CVSEDITPREFIX); if (changes != NULL) setup_tmpfile (fp, CVSEDITPREFIX, changes); (void) fprintf (fp, "%s----------------------------------------------------------------------\n", CVSEDITPREFIX); /* finish off the temp file */ if (fclose (fp) == EOF) error (1, errno, "%s", fname); if (stat (fname, &pre_stbuf) == -1) pre_stbuf.st_mtime = 0; /* run the editor */ run_setup (Editor); run_add_arg (fname); if ((retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL | RUN_SIGIGNORE | RUN_UNSETXID)) != 0) error (0, retcode == -1 ? errno : 0, "warning: editor session failed"); /* put the entire message back into the *messagep variable */ fp = xfopen (fname, "r"); if (*messagep) free (*messagep); if (stat (fname, &post_stbuf) != 0) error (1, errno, "cannot find size of temp file %s", fname); if (post_stbuf.st_size == 0) *messagep = NULL; else { /* On NT, we might read less than st_size bytes, but we won't read more. So this works. */ *messagep = (char *) xmalloc (post_stbuf.st_size + 1); (*messagep)[0] = '\0'; } line = NULL; line_chars_allocated = 0; if (*messagep) { size_t message_len = post_stbuf.st_size + 1; size_t offset = 0; while (1) { line_length = getline (&line, &line_chars_allocated, fp); if (line_length == -1) { if (ferror (fp)) error (0, errno, "warning: cannot read %s", fname); break; } if (strncmp (line, CVSEDITPREFIX, CVSEDITPREFIXLEN) == 0) continue; if (offset + line_length >= message_len) expand_string (messagep, &message_len, offset + line_length + 1); (void) strcpy (*messagep + offset, line); offset += line_length; } } if (fclose (fp) < 0) error (0, errno, "warning: cannot close %s", fname); /* canonicalize emply messages */ if (*messagep != NULL && (**messagep == '\0' || strcmp (*messagep, "\n") == 0)) { free (*messagep); *messagep = NULL; } if (pre_stbuf.st_mtime == post_stbuf.st_mtime || *messagep == NULL) { for (;;) { (void) printf ("\nLog message unchanged or not specified\n"); (void) printf ("a)bort, c)ontinue, e)dit, !)reuse this message unchanged for remaining dirs\n"); (void) printf ("Action: (abort) "); (void) fflush (stdout); line_length = getline (&line, &line_chars_allocated, stdin); if (line_length < 0) { error (0, errno, "cannot read from stdin"); if (unlink_file (fname) < 0) error (0, errno, "warning: cannot remove temp file %s", fname); error (1, 0, "aborting"); } else if (line_length == 0 || *line == '\n' || *line == 'a' || *line == 'A') { if (unlink_file (fname) < 0) error (0, errno, "warning: cannot remove temp file %s", fname); error (1, 0, "aborted by user"); } if (*line == 'c' || *line == 'C') break; if (*line == 'e' || *line == 'E') goto again; if (*line == '!') { reuse_log_message = 1; break; } (void) printf ("Unknown input\n"); } } if (line) free (line); if (unlink_file (fname) < 0) error (0, errno, "warning: cannot remove temp file %s", fname); free (fname); }
char *Name_Repository (const char *dir, const char *update_dir) { FILE *fpin; const char *xupdate_dir; char *repos = NULL; size_t repos_allocated = 0; char *tmp=NULL; char *cp; TRACE(3,"Name_Repository(%s,%s)",PATCH_NULL(dir),PATCH_NULL(update_dir)); if (update_dir && *update_dir) xupdate_dir = update_dir; else xupdate_dir = "."; if (dir != NULL) { size_t tmpsz=strlen (dir) + sizeof (CVSADM_REP) + 10; tmp = (char*)xmalloc (tmpsz+sizeof(CVSADM_VIRTREPOS)); sprintf (tmp, "%s/%s", dir, CVSADM_VIRTREPOS); size_t tmplen1 = strlen(tmp); if(!isfile(tmp)) sprintf(tmp, "%s/%s", dir, CVSADM_REP); size_t tmplen2 = strlen(tmp); TRACE(3,"Name_Repository allocate tmp of size %d, len1=%d, len2=%d",(int)tmpsz,(int)tmplen1,(int)tmplen2); } else { tmp = xstrdup (CVSADM_VIRTREPOS); TRACE(3,"Name_Repository dup tmp is len",(int)strlen(tmp)); if(!isfile(tmp)) { xfree(tmp); tmp=NULL; tmp=xstrdup(CVSADM_REP); TRACE(3,"Name_Repository dup tmp is now len",(int)strlen(tmp)); } } /* * The assumption here is that the repository is always contained in the * first line of the "Repository" file. */ TRACE(3,"Name_Repository open %s",tmp); fpin = CVS_FOPEN (tmp, "r"); if (fpin == NULL) { int save_errno = errno; char *cvsadm=NULL; if (dir != NULL) { cvsadm = (char*)xmalloc (strlen (dir) + sizeof (CVSADM) + 100); (void) sprintf (cvsadm, "%s/%s", dir, CVSADM); } else cvsadm = xstrdup (CVSADM); TRACE(3,"Name_Repository failed to open %s so try %s",tmp,cvsadm); if (!isdir (cvsadm)) { error (0, 0, "in directory %s:", xupdate_dir); error (1, 0, "there is no version here; do '%s checkout' first", program_name); } xfree (cvsadm); cvsadm=NULL; if (existence_error (save_errno)) { /* FIXME: This is a very poorly worded error message. It occurs at least in the case where the user manually creates a directory named CVS, so the error message should be more along the lines of "CVS directory found without administrative files; use CVS to create the CVS directory, or rename it to something else if the intention is to store something besides CVS administrative files". */ error (0, 0, "in directory %s:", xupdate_dir); error (1, 0, "CVS directory without administration files present. Cannot continue until this directory is deleted or renamed."); } error (1, save_errno, "cannot open %s", tmp); } TRACE(3,"Name_Repository opened %s ok so read a line",tmp); if (getline (&repos, &repos_allocated, fpin) < 0) { /* FIXME: should be checking for end of file separately. */ error (0, 0, "in directory %s:", xupdate_dir); error (1, errno, "cannot read %s", tmp); } if (fclose (fpin) < 0) error (0, errno, "cannot close %s", tmp); TRACE(3,"Name_Repository closed %s",tmp); xfree (tmp); tmp=NULL; TRACE(3,"Name_Repository read 1 %s",repos); if ((cp = strrchr (repos, '\n')) != NULL) *cp = '\0'; /* strip the newline */ TRACE(3,"Name_Repository read 2 %s",repos); /* * If this is a relative repository pathname, turn it into an absolute * one by tacking on the CVSROOT environment variable. If the CVSROOT * environment variable is not set, die now. */ TRACE(3,"Name_Repository isabsolute( %s )?",repos); char *newrepos=NULL; if (! isabsolute(repos)) { TRACE(3,"Name_Repository isabsolute( %s )!",repos); if (current_parsed_root == NULL) { error (0, 0, "in directory %s:", xupdate_dir); error (0, 0, "must set the CVSROOT environment variable\n"); error (0, 0, "or specify the '-d' option to %s.", program_name); error (1, 0, "illegal repository setting"); } if (pathname_levels (repos) > 0) { error (0, 0, "in directory %s:", xupdate_dir); error (0, 0, "`..'-relative repositories are not supported."); error (1, 0, "illegal source repository"); } newrepos = (char*)xmalloc (strlen (current_parsed_root->directory) + strlen (repos) + 2); (void) sprintf (newrepos, "%s/%s", current_parsed_root->directory, repos); #ifndef HAVE_GETLINE xfree (repos); #else free(repos); #endif repos = newrepos; } else { TRACE(3,"Name_Repository not isabsolute( %s )",repos); newrepos = (char*)xmalloc (strlen (repos) + 2); (void) sprintf (newrepos, "%s", repos); #ifndef HAVE_GETLINE xfree (repos); #else free(repos); #endif repos = newrepos; } TRACE(3,"Name_Repository Sanitize_Repository_Name( %s )!",repos); Sanitize_Repository_Name (&repos); TRACE(3,"Name_Repository return ( %s )!",repos); return repos; }
/* There are at least four functions for generating temporary * filenames. We use mkstemp (BSD 4.3) if possible, else tempnam (SVID 3), * else mktemp (BSD 4.3), and as last resort tmpnam (POSIX). Reason is that * mkstemp, tempnam, and mktemp both allow to specify the directory in which * the temporary file will be created. * * And the _correct_ way to use the deprecated functions probably involves * opening file descriptors using O_EXCL & O_CREAT and even doing the annoying * NFS locking thing, but until I hear of more problems, I'm not going to * bother. */ FILE *cvs_temp_file (char **filename) { char *fn; FILE *fp; /* FIXME - I'd like to be returning NULL here in noexec mode, but I think * some of the rcs & diff functions which rely on a temp file run in * noexec mode too. */ assert (filename != NULL); #ifdef HAVE_MKSTEMP { int fd; fn = (char*)xmalloc (strlen (Tmpdir) + 11); sprintf (fn, "%s/%s", Tmpdir, "cvsXXXXXX" ); fd = mkstemp (fn); /* a NULL return will be interpreted by callers as an error and * errno should still be set */ if (fd == -1) fp = NULL; else if ((fp = CVS_FDOPEN (fd, "w+")) == NULL) { /* attempt to close and unlink the file since mkstemp returned sucessfully and * we believe it's been created and opened */ int save_errno = errno; if (close (fd)) error (0, errno, "Failed to close temporary file %s", fn_root(fn)); if (CVS_UNLINK (fn)) error (0, errno, "Failed to unlink temporary file %s", fn_root(fn)); errno = save_errno; } if (fp == NULL) xfree (fn); /* mkstemp is defined to open mode 0600 using glibc 2.0.7+ */ /* FIXME - configure can probably tell us which version of glibc we are * linking to and not chmod for 2.0.7+ */ else chmod (fn, 0600); } #elif HAVE_TEMPNAM /* tempnam has been deprecated due to under-specification */ fn = tempnam (Tmpdir, "cvs"); if (fn == NULL) fp = NULL; else if ((fp = CVS_FOPEN (fn, "w+")) == NULL) xfree (fn); else chmod (fn, 0600); /* tempnam returns a pointer to a newly malloc'd string, so there's * no need for a xstrdup */ #elif HAVE_MKTEMP /* mktemp has been deprecated due to the BSD 4.3 specification specifying * that XXXXXX will be replaced by a PID and a letter, creating only 26 * possibilities, a security risk, and a race condition. */ { char *ifn; ifn = xmalloc (strlen (Tmpdir) + 11); sprintf (ifn, "%s/%s", Tmpdir, "cvsXXXXXX" ); fn = mktemp (ifn); if (fn == NULL) fp = NULL; else fp = CVS_FOPEN (fn, "w+"); if (fp == NULL) xfree (ifn); else chmod (fn, 0600); } #else /* use tmpnam if all else fails */ /* tmpnam is deprecated */ { char ifn[L_tmpnam + 1]; fn = tmpnam (ifn); if (fn == NULL) fp = NULL; else if ((fp = CVS_FOPEN (ifn, "w+")) != NULL) { fn = xstrdup (ifn); chmod (fn, 0600); } } #endif *filename = fn; return fp; }
/* Rebuild the checked out administrative files in directory DIR. */ int mkmodules (char *dir) { struct saved_cwd cwd; char *temp; char *cp, *last, *fname; #ifdef MY_NDBM DBM *db; #endif FILE *fp; char *line = NULL; size_t line_allocated = 0; const struct admin_file *fileptr; mode_t mode; if (noexec) return 0; if (save_cwd (&cwd)) error_exit (); if ( CVS_CHDIR (dir) < 0) error (1, errno, "cannot chdir to %s", dir); /* * First, do the work necessary to update the "modules" database. */ temp = make_tempfile (); switch (checkout_file (CVSROOTADM_MODULES, dir, temp, NULL)) { case 0: /* everything ok */ #ifdef MY_NDBM /* open it, to generate any duplicate errors */ if ((db = dbm_open (temp, O_RDONLY, 0666)) != NULL) dbm_close (db); #else write_dbmfile (temp); rename_dbmfile (temp); #endif rename_rcsfile (temp, CVSROOTADM_MODULES); break; default: error (0, 0, "'cvs checkout' is less functional without a %s file", CVSROOTADM_MODULES); break; } /* switch on checkout_file() */ if (unlink_file (temp) < 0 && !existence_error (errno)) error (0, errno, "cannot remove %s", temp); xfree (temp); /* Checkout the files that need it in CVSROOT dir */ for (fileptr = filelist; fileptr && fileptr->filename; fileptr++) { if (fileptr->errormsg == NULL) continue; temp = make_tempfile (); if (checkout_file (fileptr->filename, dir, temp, NULL) == 0) rename_rcsfile (temp, fileptr->filename); if (unlink_file (temp) < 0 && !existence_error (errno)) error (0, errno, "cannot remove %s", temp); xfree (temp); } fp = CVS_FOPEN (CVSROOTADM_CHECKOUTLIST, "r"); if (fp) { /* * File format: * [<whitespace>]<filename><whitespace><error message><end-of-line> * * comment lines begin with '#' */ while (getline (&line, &line_allocated, fp) >= 0) { /* skip lines starting with # */ if (line[0] == '#') continue; if ((last = strrchr (line, '\n')) != NULL) *last = '\0'; /* strip the newline */ /* Skip leading white space. */ for (fname = line; *fname && isspace ((unsigned char) *fname); fname++) ; /* Find end of filename. */ for (cp = fname; *cp && !isspace ((unsigned char) *cp); cp++) ; *cp = '\0'; if(isabsolute(fname) || pathname_levels(fname)>0 || !fncmp(fname,"checkoutlist")) { error(0,0,"Invalid filename '%s' in checkoutlist", fname); continue; } temp = make_tempfile (); if (checkout_file (fname, dir, temp, &mode) == 0) { chmod(temp,mode); rename_rcsfile (temp, fname); } else { for (cp++; cp < last && *last && isspace ((unsigned char) *last); cp++) ; if (cp < last && *cp) error (0, 0, cp, fname); } if (unlink_file (temp) < 0 && !existence_error (errno)) error (0, errno, "cannot remove %s", temp); xfree (temp); } if (line) xfree (line); if (ferror (fp)) error (0, errno, "cannot read %s", CVSROOTADM_CHECKOUTLIST); if (fclose (fp) < 0) error (0, errno, "cannot close %s", CVSROOTADM_CHECKOUTLIST); } else { /* Error from CVS_FOPEN. */ if (!existence_error (errno)) error (0, errno, "cannot open %s", CVSROOTADM_CHECKOUTLIST); } if (restore_cwd (&cwd, NULL)) error_exit (); free_cwd (&cwd); return (0); }
/* * Builds a temporary file using setup_tmpfile() and invokes the user's * editor on the file. The header garbage in the resultant file is then * stripped and the log message is stored in the "message" argument. * * If REPOSITORY is non-NULL, process rcsinfo for that repository; if it * is NULL, use the CVSADM_TEMPLATE file instead. */ void do_editor (const char *dir, char **messagep, const char *repository, List *changes) { static int reuse_log_message = 0; char *line; int line_length; size_t line_chars_allocated; char *fname; struct stat pre_stbuf, post_stbuf; int retcode = 0; if (noexec || reuse_log_message) return; /* Abort creation of temp file if no editor is defined */ if (strcmp (Editor, "") == 0) error(1, 0, "no editor defined, must use -e or -m"); /* Create a temporary file */ /* FIXME - It's possible we should be relying on cvs_temp_file to open * the file here - we get race conditions otherwise. */ fname = cvs_temp_name (); again: if ((fp = CVS_FOPEN (fname, "w+")) == NULL) error (1, 0, "cannot create temporary file %s", fname); if (*messagep) { fprintf (fp, "%s", *messagep); if ((*messagep)[0] == '\0' || (*messagep)[strlen (*messagep) - 1] != '\n') fprintf (fp, "\n"); } if (repository != NULL) { rcsinfo_param_t args; args.directory = Short_Repository(repository); args.message=NULL; /* tack templates on if necessary */ TRACE(3,"run rcsinfo trigger"); if(!run_trigger(&args,rcsinfo_proc) && args.message) { fprintf(fp,"%s",args.message); if (args.message[0] == '\0' || args.message[strlen(args.message) - 1] != '\n') fprintf (fp, "\n"); } } else { FILE *tfp; char buf[1024]; size_t n; size_t nwrite; /* Why "b"? */ tfp = CVS_FOPEN (CVSADM_TEMPLATE, "rb"); if (tfp == NULL) { if (!existence_error (errno)) error (1, errno, "cannot read %s", CVSADM_TEMPLATE); } else { while (!feof (tfp)) { char *p = buf; n = fread (buf, 1, sizeof buf, tfp); nwrite = n; while (nwrite > 0) { n = fwrite (p, 1, nwrite, fp); nwrite -= n; p += n; } if (ferror (tfp)) error (1, errno, "cannot read %s", CVSADM_TEMPLATE); } if (fclose (tfp) < 0) error (0, errno, "cannot close %s", CVSADM_TEMPLATE); } } fprintf (fp,"%s----------------------------------------------------------------------\n",CVSEDITPREFIX); #ifdef _WIN32 #if (CVSNT_SPECIAL_BUILD_FLAG != 0) if (strcasecmp(CVSNT_SPECIAL_BUILD,"Suite")!=0) #endif { fprintf (fp,"%s Committed on the Free edition of March Hare Software CVSNT Server\n",CVSEDITPREFIX); fprintf (fp,"%s Upgrade to CVS Suite for more features and support:\n",CVSEDITPREFIX); fprintf (fp,"%s http://march-hare.com/cvsnt/\n",CVSEDITPREFIX); fprintf (fp,"%s----------------------------------------------------------------------\n",CVSEDITPREFIX); } #endif fprintf (fp,"%sEnter Log. Lines beginning with `%.*s' are removed automatically\n%s\n", CVSEDITPREFIX, CVSEDITPREFIXLEN, CVSEDITPREFIX,CVSEDITPREFIX); if (dir != NULL && *dir) fprintf (fp, "%sCommitting in %s\n%s\n", CVSEDITPREFIX, dir, CVSEDITPREFIX); if (changes != NULL) setup_tmpfile (fp, CVSEDITPREFIX, changes); fprintf (fp,"%s----------------------------------------------------------------------\n", CVSEDITPREFIX); /* finish off the temp file */ if (fclose (fp) == EOF) error (1, errno, "%s", fname); if ( CVS_STAT (fname, &pre_stbuf) == -1) pre_stbuf.st_mtime = 0; /* run the editor */ run_setup (Editor); run_arg (fname); if ((retcode = run_exec (true)) != 0) error (0, retcode == -1 ? errno : 0, "warning: editor session failed"); /* put the entire message back into the *messagep variable */ fp = open_file (fname, "r"); if (*messagep) xfree (*messagep); if ( CVS_STAT (fname, &post_stbuf) != 0) error (1, errno, "cannot find size of temp file %s", fname); if (post_stbuf.st_size == 0) *messagep = NULL; else { /* On NT, we might read less than st_size bytes, but we won't read more. So this works. */ *messagep = (char *) xmalloc (post_stbuf.st_size + 1); *messagep[0] = '\0'; } line = NULL; line_chars_allocated = 0; if (*messagep) { size_t message_len = post_stbuf.st_size + 1; size_t offset = 0; while (1) { line_length = getline (&line, &line_chars_allocated, fp); if (line_length == -1) { if (ferror (fp)) error (0, errno, "warning: cannot read %s", fname); break; } if (strncmp (line, CVSEDITPREFIX, CVSEDITPREFIXLEN) == 0) continue; if (offset + line_length >= message_len) expand_string (messagep, &message_len, offset + line_length + 1); strcpy (*messagep + offset, line); offset += line_length; } } if (fclose (fp) < 0) error (0, errno, "warning: cannot close %s", fname); if (pre_stbuf.st_mtime == post_stbuf.st_mtime || *messagep == NULL || strcmp (*messagep, "\n") == 0) { for (;;) { printf ("\nLog message unchanged or not specified\n"); printf ("a)bort, c)ontinue, e)dit, !)reuse this message unchanged for remaining dirs\n"); printf ("Action: (continue) "); fflush (stderr); fflush (stdout); line_length = getline (&line, &line_chars_allocated, stdin); if (line_length < 0) { error (0, errno, "cannot read from stdin"); if (unlink_file (fname) < 0) error (0, errno, "warning: cannot remove temp file %s", fname); error (1, 0, "aborting"); } else if (line_length == 0 || *line == '\n' || *line == 'c' || *line == 'C') break; if (*line == 'a' || *line == 'A') { if (unlink_file (fname) < 0) error (0, errno, "warning: cannot remove temp file %s", fname); error (1, 0, "aborted by user"); } if (*line == 'e' || *line == 'E') goto again; if (*line == '!') { reuse_log_message = 1; break; } printf ("Unknown input\n"); } } if (line) xfree (line); if (unlink_file (fname) < 0) error (0, errno, "warning: cannot remove temp file %s", fname); xfree (fname); }