Beispiel #1
0
static void
perror_fatal (char const *msg)
{
  int e = errno;
  checksigs ();
  error (0, e, "%s", msg);
  exiterr ();
}
Beispiel #2
0
static void
exiterr (void)
{
  cleanup (0);
  untrapsig (0);
  checksigs ();
  exit (EXIT_TROUBLE);
}
Beispiel #3
0
/* Fill an exhausted line_filter buffer from its INFILE */
static size_t
lf_refill (struct line_filter *lf)
{
  size_t s = ck_fread (lf->buffer, SDIFF_BUFSIZE, lf->infile);
  lf->bufpos = lf->buffer;
  lf->buflim = lf->buffer + s;
  lf->buflim[0] = '\n';
  checksigs ();
  return s;
}
Beispiel #4
0
static int
skip_white (void)
{
  int c;
  for (;;)
    {
      c = getchar ();
      if (! isspace (c) || c == '\n')
	break;
      checksigs ();
    }
  if (ferror (stdin))
    perror_fatal (_("read failed"));
  return c;
}
Beispiel #5
0
/* interpret an edit command */
static bool
edit (struct line_filter *left, char const *lname, lin lline, lin llen,
      struct line_filter *right, char const *rname, lin rline, lin rlen,
      FILE *outfile)
{
  for (;;)
    {
      int cmd0, cmd1;
      bool gotcmd = false;

      cmd1 = 0; /* Pacify `gcc -W'.  */

      while (! gotcmd)
	{
	  if (putchar ('%') != '%')
	    perror_fatal (_("write failed"));
	  ck_fflush (stdout);

	  cmd0 = skip_white ();
	  switch (cmd0)
	    {
	    case '1': case '2': case 'l': case 'r':
	    case 's': case 'v': case 'q':
	      if (skip_white () != '\n')
		{
		  give_help ();
		  flush_line ();
		  continue;
		}
	      gotcmd = true;
	      break;

	    case 'e':
	      cmd1 = skip_white ();
	      switch (cmd1)
		{
		case '1': case '2': case 'b': case 'd': case 'l': case 'r':
		  if (skip_white () != '\n')
		    {
		      give_help ();
		      flush_line ();
		      continue;
		    }
		  gotcmd = true;
		  break;
		case '\n':
		  gotcmd = true;
		  break;
		default:
		  give_help ();
		  flush_line ();
		  continue;
		}
	      break;

	    case EOF:
	      if (feof (stdin))
		{
		  gotcmd = true;
		  cmd0 = 'q';
		  break;
		}
	      /* Fall through.  */
	    default:
	      flush_line ();
	      /* Fall through.  */
	    case '\n':
	      give_help ();
	      continue;
	    }
	}

      switch (cmd0)
	{
	case '1': case 'l':
	  lf_copy (left, llen, outfile);
	  lf_skip (right, rlen);
	  return true;
	case '2': case 'r':
	  lf_copy (right, rlen, outfile);
	  lf_skip (left, llen);
	  return true;
	case 's':
	  suppress_common_lines = true;
	  break;
	case 'v':
	  suppress_common_lines = false;
	  break;
	case 'q':
	  return false;
	case 'e':
	  {
	    int fd;

	    if (tmpname)
	      tmp = fopen (tmpname, "w");
	    else
	      {
		if ((fd = temporary_file ()) < 0)
		  perror_fatal ("mkstemp");
		tmp = fdopen (fd, "w");
	      }

	    if (! tmp)
	      perror_fatal (tmpname);

	    switch (cmd1)
	      {
	      case 'd':
		if (llen)
		  {
		    if (llen == 1)
		      fprintf (tmp, "--- %s %ld\n", lname, (long int) lline);
		    else
		      fprintf (tmp, "--- %s %ld,%ld\n", lname,
			       (long int) lline,
			       (long int) (lline + llen - 1));
		  }
		/* Fall through.  */
	      case '1': case 'b': case 'l':
		lf_copy (left, llen, tmp);
		break;

	      default:
		lf_skip (left, llen);
		break;
	      }

	    switch (cmd1)
	      {
	      case 'd':
		if (rlen)
		  {
		    if (rlen == 1)
		      fprintf (tmp, "+++ %s %ld\n", rname, (long int) rline);
		    else
		      fprintf (tmp, "+++ %s %ld,%ld\n", rname,
			       (long int) rline,
			       (long int) (rline + rlen - 1));
		  }
		/* Fall through.  */
	      case '2': case 'b': case 'r':
		lf_copy (right, rlen, tmp);
		break;

	      default:
		lf_skip (right, rlen);
		break;
	      }

	    ck_fclose (tmp);

	    {
	      int wstatus;
	      int werrno = 0;
	      ignore_SIGINT = true;
	      checksigs ();

	      {
#if ! (HAVE_WORKING_FORK || HAVE_WORKING_VFORK)
		char *command =
		  xmalloc (quote_system_arg (0, editor_program)
			   + 1 + strlen (tmpname) + 1);
		sprintf (command + quote_system_arg (command, editor_program),
			 " %s", tmpname);
		wstatus = system (command);
		if (wstatus == -1)
		  werrno = errno;
		free (command);
#else
		pid_t pid;

		pid = vfork ();
		if (pid == 0)
		  {
		    char const *argv[3];
		    int i = 0;

		    argv[i++] = editor_program;
		    argv[i++] = tmpname;
		    argv[i] = 0;

		    execvp (editor_program, (char **) argv);
		    _exit (errno == ENOENT ? 127 : 126);
		  }

		if (pid < 0)
		  perror_fatal ("fork");

		while (waitpid (pid, &wstatus, 0) < 0)
		  if (errno == EINTR)
		    checksigs ();
		  else
		    perror_fatal ("waitpid");
#endif
	      }

	      ignore_SIGINT = false;
	      check_child_status (werrno, wstatus, EXIT_SUCCESS,
				  editor_program);
	    }

	    {
	      char buf[SDIFF_BUFSIZE];
	      size_t size;
	      tmp = ck_fopen (tmpname, "r");
	      while ((size = ck_fread (buf, SDIFF_BUFSIZE, tmp)) != 0)
		{
		  checksigs ();
		  ck_fwrite (buf, size, outfile);
		}
	      ck_fclose (tmp);
	    }
	    return true;
	  }
	default:
	  give_help ();
	  break;
	}
    }
}
Beispiel #6
0
int
main (int argc, char *argv[])
{
  int opt;
  char const *prog;

  exit_failure = EXIT_TROUBLE;
  initialize_main (&argc, &argv);
  program_name = argv[0];
  setlocale (LC_ALL, "");
  bindtextdomain (PACKAGE, LOCALEDIR);
  textdomain (PACKAGE);
  c_stack_action (cleanup);

  prog = getenv ("EDITOR");
  if (prog)
    editor_program = prog;

  diffarg (DEFAULT_DIFF_PROGRAM);

  /* parse command line args */
  while ((opt = getopt_long (argc, argv, "abBdEHiI:lo:stvw:W", longopts, 0))
	 != -1)
    {
      switch (opt)
	{
	case 'a':
	  diffarg ("-a");
	  break;

	case 'b':
	  diffarg ("-b");
	  break;

	case 'B':
	  diffarg ("-B");
	  break;

	case 'd':
	  diffarg ("-d");
	  break;

	case 'E':
	  diffarg ("-E");
	  break;

	case 'H':
	  diffarg ("-H");
	  break;

	case 'i':
	  diffarg ("-i");
	  break;

	case 'I':
	  diffarg ("-I");
	  diffarg (optarg);
	  break;

	case 'l':
	  diffarg ("--left-column");
	  break;

	case 'o':
	  output = optarg;
	  break;

	case 's':
	  suppress_common_lines = true;
	  break;

	case 't':
	  diffarg ("-t");
	  break;

	case 'v':
	  version_etc (stdout, "sdiff", PACKAGE_NAME, PACKAGE_VERSION,
		       "Thomas Lord", (char *) 0);
	  check_stdout ();
	  return EXIT_SUCCESS;

	case 'w':
	  diffarg ("-W");
	  diffarg (optarg);
	  break;

	case 'W':
	  diffarg ("-w");
	  break;

	case DIFF_PROGRAM_OPTION:
	  diffargv[0] = optarg;
	  break;

	case HELP_OPTION:
	  usage ();
	  check_stdout ();
	  return EXIT_SUCCESS;

	case STRIP_TRAILING_CR_OPTION:
	  diffarg ("--strip-trailing-cr");
	  break;

	case TABSIZE_OPTION:
	  diffarg ("--tabsize");
	  diffarg (optarg);
	  break;

	default:
	  try_help (0, 0);
	}
    }

  if (argc - optind != 2)
    {
      if (argc - optind < 2)
	try_help ("missing operand after `%s'", argv[argc - 1]);
      else
	try_help ("extra operand `%s'", argv[optind + 2]);
    }

  if (! output)
    {
      /* easy case: diff does everything for us */
      if (suppress_common_lines)
	diffarg ("--suppress-common-lines");
      diffarg ("-y");
      diffarg ("--");
      diffarg (argv[optind]);
      diffarg (argv[optind + 1]);
      diffarg (0);
      execvp (diffargv[0], (char **) diffargv);
      perror_fatal (diffargv[0]);
    }
  else
    {
      char const *lname, *rname;
      FILE *left, *right, *out, *diffout;
      bool interact_ok;
      struct line_filter lfilt;
      struct line_filter rfilt;
      struct line_filter diff_filt;
      bool leftdir = diraccess (argv[optind]);
      bool rightdir = diraccess (argv[optind + 1]);

      if (leftdir & rightdir)
	fatal ("both files to be compared are directories");

      lname = expand_name (argv[optind], leftdir, argv[optind + 1]);
      left = ck_fopen (lname, "r");
      rname = expand_name (argv[optind + 1], rightdir, argv[optind]);
      right = ck_fopen (rname, "r");
      out = ck_fopen (output, "w");

      diffarg ("--sdiff-merge-assist");
      diffarg ("--");
      diffarg (argv[optind]);
      diffarg (argv[optind + 1]);
      diffarg (0);

      trapsigs ();

#if ! (HAVE_WORKING_FORK || HAVE_WORKING_VFORK)
      {
	size_t cmdsize = 1;
	char *p, *command;
	int i;

	for (i = 0;  diffargv[i];  i++)
	  cmdsize += quote_system_arg (0, diffargv[i]) + 1;
	command = p = xmalloc (cmdsize);
	for (i = 0;  diffargv[i];  i++)
	  {
	    p += quote_system_arg (p, diffargv[i]);
	    *p++ = ' ';
	  }
	p[-1] = 0;
	errno = 0;
	diffout = popen (command, "r");
	if (! diffout)
	  perror_fatal (command);
	free (command);
      }
#else
      {
	int diff_fds[2];
# if HAVE_WORKING_VFORK
	sigset_t procmask;
	sigset_t blocked;
# endif

	if (pipe (diff_fds) != 0)
	  perror_fatal ("pipe");

# if HAVE_WORKING_VFORK
	/* Block SIGINT and SIGPIPE.  */
	sigemptyset (&blocked);
	sigaddset (&blocked, SIGINT);
	sigaddset (&blocked, SIGPIPE);
	sigprocmask (SIG_BLOCK, &blocked, &procmask);
# endif
	diffpid = vfork ();
	if (diffpid < 0)
	  perror_fatal ("fork");
	if (! diffpid)
	  {
	    /* Alter the child's SIGINT and SIGPIPE handlers;
	       this may munge the parent.
	       The child ignores SIGINT in case the user interrupts the editor.
	       The child does not ignore SIGPIPE, even if the parent does.  */
	    if (initial_handler (handler_index_of_SIGINT) != SIG_IGN)
	      signal_handler (SIGINT, SIG_IGN);
	    signal_handler (SIGPIPE, SIG_DFL);
# if HAVE_WORKING_VFORK
	    /* Stop blocking SIGINT and SIGPIPE in the child.  */
	    sigprocmask (SIG_SETMASK, &procmask, 0);
# endif
	    close (diff_fds[0]);
	    if (diff_fds[1] != STDOUT_FILENO)
	      {
		dup2 (diff_fds[1], STDOUT_FILENO);
		close (diff_fds[1]);
	      }

	    execvp (diffargv[0], (char **) diffargv);
	    _exit (errno == ENOENT ? 127 : 126);
	  }

# if HAVE_WORKING_VFORK
	/* Restore the parent's SIGINT and SIGPIPE behavior.  */
	if (initial_handler (handler_index_of_SIGINT) != SIG_IGN)
	  signal_handler (SIGINT, catchsig);
	if (initial_handler (handler_index_of_SIGPIPE) != SIG_IGN)
	  signal_handler (SIGPIPE, catchsig);
	else
	  signal_handler (SIGPIPE, SIG_IGN);

	/* Stop blocking SIGINT and SIGPIPE in the parent.  */
	sigprocmask (SIG_SETMASK, &procmask, 0);
# endif

	close (diff_fds[1]);
	diffout = fdopen (diff_fds[0], "r");
	if (! diffout)
	  perror_fatal ("fdopen");
      }
#endif

      lf_init (&diff_filt, diffout);
      lf_init (&lfilt, left);
      lf_init (&rfilt, right);

      interact_ok = interact (&diff_filt, &lfilt, lname, &rfilt, rname, out);

      ck_fclose (left);
      ck_fclose (right);
      ck_fclose (out);

      {
	int wstatus;
	int werrno = 0;

#if ! (HAVE_WORKING_FORK || HAVE_WORKING_VFORK)
	wstatus = pclose (diffout);
	if (wstatus == -1)
	  werrno = errno;
#else
	ck_fclose (diffout);
	while (waitpid (diffpid, &wstatus, 0) < 0)
	  if (errno == EINTR)
	    checksigs ();
	  else
	    perror_fatal ("waitpid");
	diffpid = 0;
#endif

	if (tmpname)
	  {
	    unlink (tmpname);
	    tmpname = 0;
	  }

	if (! interact_ok)
	  exiterr ();

	check_child_status (werrno, wstatus, EXIT_FAILURE, diffargv[0]);
	untrapsig (0);
	checksigs ();
	exit (WEXITSTATUS (wstatus));
      }
    }
  return EXIT_SUCCESS;			/* Fool `-Wall'.  */
}
Beispiel #7
0
/* Alternately reveal bursts of diff output and handle user commands.  */
static bool
interact (struct line_filter *diff,
	  struct line_filter *left, char const *lname,
	  struct line_filter *right, char const *rname,
	  FILE *outfile)
{
  lin lline = 1, rline = 1;

  for (;;)
    {
      char diff_help[256];
      int snarfed = lf_snarf (diff, diff_help, sizeof diff_help);

      if (snarfed <= 0)
	return snarfed != 0;

      checksigs ();

      if (diff_help[0] == ' ')
	puts (diff_help + 1);
      else
	{
	  char *numend;
	  uintmax_t val;
	  lin llen, rlen, lenmax;
	  errno = 0;
	  llen = val = strtoumax (diff_help + 1, &numend, 10);
	  if (llen < 0 || llen != val || errno || *numend != ',')
	    fatal (diff_help);
	  rlen = val = strtoumax (numend + 1, &numend, 10);
	  if (rlen < 0 || rlen != val || errno || *numend)
	    fatal (diff_help);

	  lenmax = MAX (llen, rlen);

	  switch (diff_help[0])
	    {
	    case 'i':
	      if (suppress_common_lines)
		lf_skip (diff, lenmax);
	      else
		lf_copy (diff, lenmax, stdout);

	      lf_copy (left, llen, outfile);
	      lf_skip (right, rlen);
	      break;

	    case 'c':
	      lf_copy (diff, lenmax, stdout);
	      if (! edit (left, lname, lline, llen,
			  right, rname, rline, rlen,
			  outfile))
		return false;
	      break;

	    default:
	      fatal (diff_help);
	    }

	  lline += llen;
	  rline += rlen;
	}
    }
}
Beispiel #8
0
static retvalue extract_signed_data(const char *buffer, size_t bufferlen, const char *filenametoshow, char **chunkread, /*@null@*/ /*@out@*/struct signatures **signatures_p, bool *brokensignature) {
	char *chunk;
	gpg_error_t err;
	gpgme_data_t dh, dh_gpg;
	size_t plain_len;
	char *plain_data;
	retvalue r;
	struct signatures *signatures = NULL;
	bool foundbroken = false;

	r = signature_init(false);
	if (RET_WAS_ERROR(r))
		return r;

	err = gpgme_data_new_from_mem(&dh_gpg, buffer, bufferlen, 0);
	if (err != 0)
		return gpgerror(err);

	err = gpgme_data_new(&dh);
	if (err != 0) {
		gpgme_data_release(dh_gpg);
		return gpgerror(err);
	}
	err = gpgme_op_verify(context, dh_gpg, NULL, dh);
	if (gpg_err_code(err) == GPG_ERR_NO_DATA) {
		if (verbose > 5)
			fprintf(stderr,
"Data seems not to be signed trying to use directly....\n");
		gpgme_data_release(dh);
		gpgme_data_release(dh_gpg);
		return RET_NOTHING;
	} else {
		if (err != 0) {
			gpgme_data_release(dh_gpg);
			gpgme_data_release(dh);
			return gpgerror(err);
		}
		if (signatures_p != NULL || brokensignature != NULL) {
			r = checksigs(filenametoshow,
				(signatures_p!=NULL)?&signatures:NULL,
				(brokensignature!=NULL)?&foundbroken:NULL);
			if (RET_WAS_ERROR(r)) {
				gpgme_data_release(dh_gpg);
				gpgme_data_release(dh);
				return r;
			}
		}
		gpgme_data_release(dh_gpg);
		plain_data = gpgme_data_release_and_get_mem(dh, &plain_len);
		if (plain_data == NULL) {
			fprintf(stderr,
"(not yet fatal) ERROR: libgpgme failed to extract the plain data out of\n"
"'%s'.\n"
"While it did so in a way indicating running out of memory, experience says\n"
"this also happens when gpg returns a error code it does not understand.\n"
"To check this please try running gpg --verify '%s' manually.\n"
"Continuing extracting it ignoring all signatures...",
					filenametoshow, filenametoshow);
			signatures_free(signatures);
			return RET_NOTHING;
		}
		if (signatures != NULL) {
			r = check_primary_keys(signatures);
			if (RET_WAS_ERROR(r)) {
				signatures_free(signatures);
				return r;
			}
		}
	}

	if (FAILEDTOALLOC(plain_data))
		r = RET_ERROR_OOM;
	else {
		size_t len;
		const char *afterchanges;

		chunk = malloc(plain_len + 1);
		len = chunk_extract(chunk, plain_data, plain_len, false,
				&afterchanges);
		if (len == 0) {
			fprintf(stderr,
"Could only find spaces within '%s'!\n",
					filenametoshow);
			free(chunk);
			r = RET_ERROR;
		} else if (afterchanges != plain_data + plain_len) {
			if (*afterchanges == '\0')
				fprintf(stderr,
"Unexpected \\0 character within '%s'!\n",
					filenametoshow);
			else
				fprintf(stderr,
"Unexpected data after ending empty line in '%s'!\n",
					filenametoshow);
			free(chunk);
			r = RET_ERROR;
		} else
			*chunkread = chunk;
	}
#ifdef HAVE_GPGPME_FREE
	gpgme_free(plain_data);
#else
	free(plain_data);
#endif
	if (RET_IS_OK(r)) {
		if (signatures_p != NULL)
			*signatures_p = signatures;
		if (brokensignature != NULL)
			*brokensignature = foundbroken;
	} else {
		signatures_free(signatures);
	}
	return r;
}