/*
- * $Id: $
+ * $Id$
*
* Across-the-wire migration utility for Citadel
*
+ * Yes, we used goto, and gets(), and committed all sorts of other heinous sins here.
+ * The scope of this program isn't wide enough to make a difference. If you don't like
+ * it you can rewrite it.
+ *
* Copyright (c) 2009 citadel.org
*
- * This program is licensed to you under the terms of the GNU General Public License v3
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * (Note: a useful future enhancement might be to support "-h" on both sides)
*
*/
+/*
+ * Replacement for gets() that doesn't throw a compiler warning.
+ * We're only using it for some simple prompts, so we don't need
+ * to worry about attackers exploiting it.
+ */
+void getz(char *buf) {
+ char *ptr;
+
+ ptr = fgets(buf, 32767, stdin);
+ if (!ptr) {
+ buf[0] = 0;
+ return;
+ }
+
+ ptr = strchr(buf, '\n');
+ if (ptr) *ptr = 0;
+}
+
+
+
+
int main(int argc, char *argv[])
{
char ctdldir[PATH_MAX]=CTDLDIR;
char yesno[5];
char sendcommand[PATH_MAX];
- int exitcode;
+ int cmdexit;
char cmd[PATH_MAX];
char buf[PATH_MAX];
char socket_path[PATH_MAX];
char remote_user[256];
char remote_host[256];
char remote_sendcommand[PATH_MAX];
- FILE *source_artv;
- FILE *target_artv;
+ FILE *sourcefp = NULL;
+ FILE *targetfp = NULL;
int linecount = 0;
char spinning[4] = "-\\|/" ;
+ int exitcode = 0;
calc_dirs_n_files(relh, home, relhome, ctdldir, 0);
CtdlMakeTempFileName(socket_path, sizeof socket_path);
- system("clear");
+ cmdexit = system("clear");
printf( "-------------------------------------------\n"
"Over-the-wire migration utility for Citadel\n"
"-------------------------------------------\n"
printf("Locating 'sendcommand' and checking connectivity to Citadel...\n");
snprintf(sendcommand, sizeof sendcommand, "%s/sendcommand", ctdl_utilbin_dir);
snprintf(cmd, sizeof cmd, "%s 'NOOP'", sendcommand);
- exitcode = system(cmd);
- if (exitcode != 0) {
+ cmdexit = system(cmd);
+ if (cmdexit != 0) {
printf("\nctdlmigrate was unable to attach to the Citadel server\n"
"here on the target system. Is Citadel running?\n\n");
exit(1);
printf("Enter the host name or IP address of the source system\n"
"(example: ctdl.foo.org)\n"
"--> ");
- gets(remote_host);
+ getz(remote_host);
printf("\nEnter the name of a user on %s who has full access to Citadel files\n"
"(usually root)\n--> ",
remote_host);
- gets(remote_user);
+ getz(remote_user);
printf("\nEstablishing an SSH connection to the source system...\n\n");
unlink(socket_path);
snprintf(cmd, sizeof cmd, "ssh -MNf -S %s %s@%s", socket_path, remote_user, remote_host);
- exitcode = system(cmd);
- if (exitcode != 0) {
- printf("\nctdlmigrate was unable to establish an SSH connection to the\n"
- "source system, and cannot continue.\n\n");
- exit(exitcode);
+ cmdexit = system(cmd);
+ printf("\n");
+ if (cmdexit != 0) {
+ printf("This program was unable to establish an SSH session to the source system.\n\n");
+ exitcode = cmdexit;
+ goto THEEND;
}
printf("\nTesting a command over the connection...\n\n");
snprintf(cmd, sizeof cmd, "ssh -S %s %s@%s 'echo Remote commands are executing successfully.'",
socket_path, remote_user, remote_host);
- exitcode = system(cmd);
+ cmdexit = system(cmd);
printf("\n");
- if (exitcode != 0) {
+ if (cmdexit != 0) {
printf("Remote commands are not succeeding.\n\n");
- exit(exitcode);
+ exitcode = cmdexit;
+ goto THEEND;
}
printf("\nLocating the remote 'sendcommand' and Citadel installation...\n");
snprintf(remote_sendcommand, sizeof remote_sendcommand, "/usr/local/citadel/sendcommand");
snprintf(cmd, sizeof cmd, "ssh -S %s %s@%s %s NOOP",
socket_path, remote_user, remote_host, remote_sendcommand);
- exitcode = system(cmd);
- if (exitcode != 0) {
+ cmdexit = system(cmd);
+ if (cmdexit != 0) {
snprintf(remote_sendcommand, sizeof remote_sendcommand, "/usr/sbin/sendcommand");
snprintf(cmd, sizeof cmd, "ssh -S %s %s@%s %s NOOP",
socket_path, remote_user, remote_host, remote_sendcommand);
- exitcode = system(cmd);
+ cmdexit = system(cmd);
}
- if (exitcode != 0) {
+ if (cmdexit != 0) {
printf("\nUnable to locate Citadel programs on the remote system. Please enter\n"
"the name of the directory on %s which contains the 'sendcommand' program.\n"
"(example: /opt/foo/citadel)\n"
"--> ", remote_host);
- gets(buf);
+ getz(buf);
snprintf(remote_sendcommand, sizeof remote_sendcommand, "%s/sendcommand", buf);
snprintf(cmd, sizeof cmd, "ssh -S %s %s@%s %s NOOP",
socket_path, remote_user, remote_host, remote_sendcommand);
- exitcode = system(cmd);
+ cmdexit = system(cmd);
}
printf("\n");
- if (exitcode != 0) {
+ if (cmdexit != 0) {
printf("ctdlmigrate was unable to attach to the remote Citadel system.\n\n");
- exit(exitcode);
+ exitcode = cmdexit;
+ goto THEEND;
}
printf("ctdlmigrate will now begin a database migration...\n");
- snprintf(cmd, sizeof cmd, "ssh -S %s %s@%s %s MIGR export",
+ snprintf(cmd, sizeof cmd, "ssh -S %s %s@%s %s -w3600 MIGR export",
socket_path, remote_user, remote_host, remote_sendcommand);
- source_artv = popen(cmd, "r");
- if (!source_artv) {
+ sourcefp = popen(cmd, "r");
+ if (!sourcefp) {
printf("\n%s\n\n", strerror(errno));
- exit(2);
+ exitcode = 2;
+ goto THEEND;
}
- snprintf(cmd, sizeof cmd, "%s MIGR import", sendcommand);
- target_artv = popen(cmd, "w");
- if (!target_artv) {
+ snprintf(cmd, sizeof cmd, "%s -w3600 MIGR import", sendcommand);
+ targetfp = popen(cmd, "w");
+ if (!targetfp) {
printf("\n%s\n\n", strerror(errno));
- exit(3);
+ exitcode = 3;
+ goto THEEND;
}
- while (fgets(buf, sizeof buf, source_artv) != NULL) {
- fwrite(buf, strlen(buf), 1, target_artv);
+ while (fgets(buf, sizeof buf, sourcefp) != NULL) {
+ if (fwrite(buf, strlen(buf), 1, targetfp) < 1) {
+ exitcode = 4;
+ printf("%s\n", strerror(errno));
+ goto FAIL;
+ }
++linecount;
if ((linecount % 100) == 0) {
printf("%c\r", spinning[((linecount / 100) % 4)]);
}
}
- pclose(source_artv);
- pclose(target_artv);
+FAIL: if (sourcefp) pclose(sourcefp);
+ if (targetfp) pclose(targetfp);
+ if (exitcode != 0) goto THEEND;
+
+ /* We need to copy a bunch of other stuff, and will do so using rsync */
+
+ snprintf(cmd, sizeof cmd, "ssh -S %s %s@%s %s MIGR listdirs",
+ socket_path, remote_user, remote_host, remote_sendcommand);
+ sourcefp = popen(cmd, "r");
+ if (!sourcefp) {
+ printf("\n%s\n\n", strerror(errno));
+ exitcode = 2;
+ goto THEEND;
+ }
+ while ((fgets(buf, sizeof buf, sourcefp)) && (strcmp(buf, "000"))) {
+ buf[strlen(buf)-1] = 0;
+
+ if (!strncasecmp(buf, "bio|", 4)) {
+ snprintf(cmd, sizeof cmd, "rsync -va --rsh='ssh -S %s' %s@%s:%s/ %s/",
+ socket_path, remote_user, remote_host, &buf[4], ctdl_bio_dir);
+ }
+ else if (!strncasecmp(buf, "files|", 6)) {
+ snprintf(cmd, sizeof cmd, "rsync -va --rsh='ssh -S %s' %s@%s:%s/ %s/",
+ socket_path, remote_user, remote_host, &buf[6], ctdl_file_dir);
+ }
+ else if (!strncasecmp(buf, "userpics|", 9)) {
+ snprintf(cmd, sizeof cmd, "rsync -va --rsh='ssh -S %s' %s@%s:%s/ %s/",
+ socket_path, remote_user, remote_host, &buf[9], ctdl_usrpic_dir);
+ }
+ else if (!strncasecmp(buf, "messages|", 9)) {
+ snprintf(cmd, sizeof cmd, "rsync -va --rsh='ssh -S %s' %s@%s:%s/ %s/",
+ socket_path, remote_user, remote_host, &buf[9], ctdl_message_dir);
+ }
+ else if (!strncasecmp(buf, "netconfigs|", 11)) {
+ snprintf(cmd, sizeof cmd, "rsync -va --rsh='ssh -S %s' %s@%s:%s/ %s/",
+ socket_path, remote_user, remote_host, &buf[11], ctdl_netcfg_dir);
+ }
+ else if (!strncasecmp(buf, "keys|", 5)) {
+ snprintf(cmd, sizeof cmd, "rsync -va --rsh='ssh -S %s' %s@%s:%s/ %s/",
+ socket_path, remote_user, remote_host, &buf[5], ctdl_key_dir);
+ }
+ else if (!strncasecmp(buf, "images|", 7)) {
+ snprintf(cmd, sizeof cmd, "rsync -va --rsh='ssh -S %s' %s@%s:%s/ %s/",
+ socket_path, remote_user, remote_host, &buf[7], ctdl_image_dir);
+ }
+ else if (!strncasecmp(buf, "info|", 5)) {
+ snprintf(cmd, sizeof cmd, "rsync -va --rsh='ssh -S %s' %s@%s:%s/ %s/",
+ socket_path, remote_user, remote_host, &buf[5], ctdl_info_dir);
+ }
+ else {
+ strcpy(cmd, "false"); /* cheap and sleazy way to throw an error */
+ }
+ printf("%s\n", cmd);
+ cmdexit = system(cmd);
+ if (cmdexit != 0) {
+ exitcode += cmdexit;
+ }
+ }
+ pclose(sourcefp);
+
+THEEND: if (exitcode == 0) {
+ printf("\n\n *** Citadel migration was successful! *** \n\n");
+ }
+ else {
+ printf("\n\n *** Citadel migration was unsuccessful. *** \n\n");
+ }
+ printf("\nShutting down the socket connection...\n\n");
+ snprintf(cmd, sizeof cmd, "ssh -S %s -N -O exit %s@%s",
+ socket_path, remote_user, remote_host);
+ cmdexit = system(cmd);
+ printf("\n");
+ if (cmdexit != 0) {
+ printf("There was an error shutting down the socket.\n\n");
+ exitcode = cmdexit;
+ }
- // FIXME handle -h on both sides
- // FIXME kill the master ssh session
- printf("If this program was finished we would do more. FIXME\n");
- exit(0);
+ unlink(socket_path);
+ exit(exitcode);
}