]> code.citadel.org Git - citadel.git/blobdiff - citadel/ctdlmigrate.c
* If running 7.60 code for the first time, serv_upgrade erases any existing LDAP...
[citadel.git] / citadel / ctdlmigrate.c
index 7a53a8fb98d0df1b55940355e952480a1ec3f35a..ad50ea9d9dfec03bdced89ef60b2b306985b3d09 100644 (file)
@@ -1,12 +1,18 @@
 /*
- * $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
  *
+ * FIXME handle -h on both sides
+ *
  */
 
 #include <stdlib.h>
 
 
 
+/*
+ * 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[])
 {
@@ -46,16 +73,24 @@ 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 *sourcefp = NULL;
+       FILE *targetfp = NULL;
+       int linecount = 0;
+       char spinning[4] = "-\\|/" ;
+       int exitcode = 0;
+       pid_t sshpid;
        
        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"
@@ -87,8 +122,8 @@ int main(int argc, char *argv[])
        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);
@@ -98,35 +133,182 @@ int main(int argc, char *argv[])
        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);
+       sshpid = fork();
+       if (sshpid < 0)
+       {
+               printf("\n%s\n", strerror(errno));
+               exitcode = errno;
+               goto THEEND;
+       }
+       else if (sshpid == 0)
+       {
+               printf("\nEstablishing an SSH connection to the source system...\n\n");
+               unlink(socket_path);
+               snprintf(cmd, sizeof cmd, "%s@%s", remote_user, remote_host);
+               execlp("ssh", "ssh", "-MNf", "-S", socket_path, cmd, NULL);
+               cmdexit = errno;
+               printf("\n%s\n", strerror(cmdexit));
+               exit(cmdexit);          /* child process exits */
+       }
+
+       /* If we get here we are the parent process */
+       if (waitpid(sshpid, &cmdexit, 0) <= 0) {
+               exitcode = errno;
+               printf("\n%s\n", strerror(errno));
+               goto THEEND;
+       }
+
+       if (WIFSIGNALED(cmdexit)) {
+               exitcode = errno;
+               printf("\n%s\n", strerror(errno));
+               goto THEEND;
+       }
+
+       if ((WIFEXITED(cmdexit)) && (WEXITSTATUS(cmdexit) != 0)) {
+               exitcode = WEXITSTATUS(cmdexit);
+               printf("\n%s\n", strerror(errno));
+               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);
+       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);
+               cmdexit = system(cmd);
+       }
+       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);
+               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);
+               cmdexit = system(cmd);
+       }
+       printf("\n");
+       if (cmdexit != 0) {
+               printf("ctdlmigrate was unable to attach to the remote Citadel system.\n\n");
+               exitcode = cmdexit;
+               goto THEEND;
+       }
+
+       printf("ctdlmigrate will now begin a database migration...\n");
+
+       snprintf(cmd, sizeof cmd, "ssh -S %s %s@%s %s -w3600 MIGR export",
+               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;
        }
 
+       snprintf(cmd, sizeof cmd, "%s -w3600 MIGR import", sendcommand);
+       targetfp = popen(cmd, "w");
+       if (!targetfp) {
+               printf("\n%s\n\n", strerror(errno));
+               exitcode = 3;
+               goto THEEND;
+       }
+
+       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)]);
+                       fflush(stdout);
+               }
+       }
 
+FAIL:  if (sourcefp) pclose(sourcefp);
+       if (targetfp) pclose(targetfp);
+       if (exitcode != 0) goto THEEND;
 
-       // FIXME kill the master ssh session
-       printf("If this program was finished we would do more.  FIXME\n");
-       exit(0);
+       /* 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:        kill(sshpid, SIGKILL);
+       unlink(socket_path);
+       exit(exitcode);
 }