#include "cvs.h"
#include "save-cwd.h"
#include "getline.h"
#include "yesno.h"
static const char *const release_usage[] =
{
"Usage: %s %s [-d] directories...\n",
"\t-d\tDelete the given directory.\n",
"(Specify the --help global option for a list of other help options)\n",
NULL
};
#ifdef SERVER_SUPPORT
static int release_server (int argc, char **argv);
static int
release_server (int argc, char **argv)
{
int i;
for (i = 1; i < argc; ++i)
history_write ('F', argv[i], "", argv[i], "");
return 0;
}
#endif
static FILE *
setup_update_command (pid_t *child_pid)
{
int tofd, fromfd;
run_setup (program_path);
#if defined (CLIENT_SUPPORT) || defined (SERVER_SUPPORT)
if (cvsauthenticate) run_add_arg ("-a");
if (cvsencrypt) run_add_arg ("-x");
#endif
run_add_arg ("-n");
run_add_arg ("-q");
run_add_arg ("-d");
run_add_arg (original_parsed_root->original);
run_add_arg ("update");
*child_pid = run_piped (&tofd, &fromfd);
if (*child_pid < 0)
error (1, 0, "could not fork server process");
close (tofd);
return fdopen (fromfd, "r");
}
static int
close_update_command (FILE *fp, pid_t child_pid)
{
int status;
pid_t w;
do
w = waitpid (child_pid, &status, 0);
while (w == -1 && errno == EINTR);
if (w == -1)
error (1, errno, "waiting for process %d", child_pid);
return status;
}
int
release (int argc, char **argv)
{
FILE *fp;
int i, c;
char *line = NULL;
size_t line_allocated = 0;
char *thisarg;
int arg_start_idx;
int err = 0;
short delete_flag = 0;
struct saved_cwd cwd;
#ifdef SERVER_SUPPORT
if (server_active)
return release_server (argc, argv);
#endif
if (argc == -1)
usage (release_usage);
optind = 0;
while ((c = getopt (argc, argv, "+Qdq")) != -1)
{
switch (c)
{
case 'Q':
case 'q':
error (1, 0,
"-q or -Q must be specified before \"%s\"",
cvs_cmd_name);
break;
case 'd':
delete_flag++;
break;
case '?':
default:
usage (release_usage);
break;
}
}
argc -= optind;
argv += optind;
#ifdef CLIENT_SUPPORT
if (current_parsed_root->isremote)
{
start_server ();
ign_setup ();
}
#endif
if (save_cwd (&cwd))
error (1, errno, "Failed to save current directory.");
arg_start_idx = 0;
for (i = arg_start_idx; i < argc; i++)
{
thisarg = argv[i];
if (isdir (thisarg))
{
if (CVS_CHDIR (thisarg) < 0)
{
if (!really_quiet)
error (0, errno, "can't chdir to: %s", thisarg);
continue;
}
if (!isdir (CVSADM))
{
if (!really_quiet)
error (0, 0, "no repository directory: %s", thisarg);
if (restore_cwd (&cwd))
error (1, errno,
"Failed to restore current directory, `%s'.",
cwd.name);
continue;
}
}
else
{
if (!really_quiet)
error (0, 0, "no such directory: %s", thisarg);
continue;
}
if (!really_quiet)
{
int line_length, status;
pid_t child_pid;
fp = setup_update_command (&child_pid);
if (fp == NULL)
{
error (0, 0, "cannot run command:");
run_print (stderr);
error (1, 0, "Exiting due to fatal error referenced above.");
}
c = 0;
while ((line_length = getline (&line, &line_allocated, fp)) >= 0)
{
if (strchr ("MARCZ", *line))
c++;
(void) fputs (line, stdout);
}
if (line_length < 0 && !feof (fp))
error (0, errno, "cannot read from subprocess");
status = close_update_command (fp, child_pid);
if (status != 0)
{
error (0, 0, "unable to release `%s' (%d)", thisarg, status);
if (restore_cwd (&cwd))
error (1, errno,
"Failed to restore current directory, `%s'.",
cwd.name);
continue;
}
printf ("You have [%d] altered files in this repository.\n",
c);
if (!noexec)
{
printf ("Are you sure you want to release %sdirectory `%s': ",
delete_flag ? "(and delete) " : "", thisarg);
fflush (stderr);
fflush (stdout);
if (!yesno ())
{
(void) fprintf (stderr,
"** `%s' aborted by user choice.\n",
cvs_cmd_name);
if (restore_cwd (&cwd))
error (1, errno,
"Failed to restore current directory, `%s'.",
cwd.name);
continue;
}
}
else
{
if (restore_cwd (&cwd))
error (1, errno,
"Failed to restore current directory, `%s'.",
cwd.name);
continue;
}
}
if (restore_cwd (&cwd))
error (1, errno, "Failed to restore current directory, `%s'.",
cwd.name);
#ifdef CLIENT_SUPPORT
if (!current_parsed_root->isremote
|| (supported_request ("noop") && supported_request ("Notify")))
#endif
{
int argc = 2;
char *argv[3];
argv[0] = "dummy";
argv[1] = thisarg;
argv[2] = NULL;
err += unedit (argc, argv);
if (restore_cwd (&cwd))
error (1, errno, "Failed to restore current directory, `%s'.",
cwd.name);
}
#ifdef CLIENT_SUPPORT
if (current_parsed_root->isremote)
{
send_to_server ("Argument ", 0);
send_to_server (thisarg, 0);
send_to_server ("\012", 1);
send_to_server ("release\012", 0);
}
else
#endif
{
history_write ('F', thisarg, "", thisarg, "");
}
if (delete_flag)
{
if (unlink_file_dir (thisarg) < 0)
error (0, errno, "deletion of directory %s failed", thisarg);
}
#ifdef CLIENT_SUPPORT
if (current_parsed_root->isremote)
{
err += get_server_responses ();
if (restore_cwd (&cwd))
error (1, errno, "Failed to restore current directory, `%s'.",
cwd.name);
}
#endif
}
if (restore_cwd (&cwd))
error (1, errno, "Failed to restore current directory, `%s'.",
cwd.name);
free_cwd (&cwd);
#ifdef CLIENT_SUPPORT
if (current_parsed_root->isremote)
{
send_to_server ("noop\012", 0);
err += get_responses_and_close ();
}
#endif
if (line != NULL)
free (line);
return err;
}