4 * Across-the-wire migration utility for Citadel
6 * Copyright (c) 2009 citadel.org
8 * This program is licensed to you under the terms of the GNU General Public License v3
18 #include <sys/types.h>
20 #include <sys/utsname.h>
28 #include <libcitadel.h>
33 #include "citadel_dirs.h"
41 * Replacement for gets() that doesn't throw a compiler warning.
42 * We're only using it for some simple prompts, so we don't need
43 * to worry about attackers exploiting it.
45 void getz(char *buf) {
48 ptr = fgets(buf, 32767, stdin);
54 ptr = strchr(buf, '\n');
62 int main(int argc, char *argv[])
66 char relhome[PATH_MAX]="";
67 char ctdldir[PATH_MAX]=CTDLDIR;
69 char sendcommand[PATH_MAX];
73 char socket_path[PATH_MAX];
74 char remote_user[256];
75 char remote_host[256];
76 char remote_sendcommand[PATH_MAX];
80 char spinning[4] = "-\\|/" ;
83 calc_dirs_n_files(relh, home, relhome, ctdldir, 0);
84 CtdlMakeTempFileName(socket_path, sizeof socket_path);
87 printf( "-------------------------------------------\n"
88 "Over-the-wire migration utility for Citadel\n"
89 "-------------------------------------------\n"
91 "This utility is designed to migrate your Citadel installation\n"
92 "to a new host system via a network connection, without disturbing\n"
93 "the source system. The target may be a different CPU architecture\n"
94 "and/or operating system. The source system should be running\n"
95 "Citadel %d.%02d or newer, and the target system should be running\n"
96 "either the same version or a newer version. You will also need\n"
97 "the 'rsync' utility, and OpenSSH v4 or newer.\n"
99 "You must run this utility on the TARGET SYSTEM. Any existing data\n"
100 "on this system will be ERASED.\n"
102 "Do you wish to continue? "
104 EXPORT_REV_MIN / 100,
108 if ((fgets(yesno, sizeof yesno, stdin) == NULL) || (tolower(yesno[0]) != 'y')) {
112 printf("\n\nGreat! First we will check some things out here on our target\n"
113 "system to make sure it is ready to receive data.\n\n");
115 printf("Locating 'sendcommand' and checking connectivity to Citadel...\n");
116 snprintf(sendcommand, sizeof sendcommand, "%s/sendcommand", ctdl_utilbin_dir);
117 snprintf(cmd, sizeof cmd, "%s 'NOOP'", sendcommand);
118 cmdexit = system(cmd);
120 printf("\nctdlmigrate was unable to attach to the Citadel server\n"
121 "here on the target system. Is Citadel running?\n\n");
124 printf("\nOK, this side is ready to go. Now we must connect to the source system.\n\n");
126 printf("Enter the host name or IP address of the source system\n"
127 "(example: ctdl.foo.org)\n"
130 printf("\nEnter the name of a user on %s who has full access to Citadel files\n"
131 "(usually root)\n--> ",
135 printf("\nEstablishing an SSH connection to the source system...\n\n");
137 snprintf(cmd, sizeof cmd, "ssh -MNf -S %s %s@%s", socket_path, remote_user, remote_host);
138 cmdexit = system(cmd);
140 printf("\nctdlmigrate was unable to establish an SSH connection to the\n"
141 "source system, and cannot continue.\n\n");
146 printf("\nTesting a command over the connection...\n\n");
147 snprintf(cmd, sizeof cmd, "ssh -S %s %s@%s 'echo Remote commands are executing successfully.'",
148 socket_path, remote_user, remote_host);
149 cmdexit = system(cmd);
152 printf("Remote commands are not succeeding.\n\n");
157 printf("\nLocating the remote 'sendcommand' and Citadel installation...\n");
158 snprintf(remote_sendcommand, sizeof remote_sendcommand, "/usr/local/citadel/sendcommand");
159 snprintf(cmd, sizeof cmd, "ssh -S %s %s@%s %s NOOP",
160 socket_path, remote_user, remote_host, remote_sendcommand);
161 cmdexit = system(cmd);
163 snprintf(remote_sendcommand, sizeof remote_sendcommand, "/usr/sbin/sendcommand");
164 snprintf(cmd, sizeof cmd, "ssh -S %s %s@%s %s NOOP",
165 socket_path, remote_user, remote_host, remote_sendcommand);
166 cmdexit = system(cmd);
169 printf("\nUnable to locate Citadel programs on the remote system. Please enter\n"
170 "the name of the directory on %s which contains the 'sendcommand' program.\n"
171 "(example: /opt/foo/citadel)\n"
172 "--> ", remote_host);
174 snprintf(remote_sendcommand, sizeof remote_sendcommand, "%s/sendcommand", buf);
175 snprintf(cmd, sizeof cmd, "ssh -S %s %s@%s %s NOOP",
176 socket_path, remote_user, remote_host, remote_sendcommand);
177 cmdexit = system(cmd);
181 printf("ctdlmigrate was unable to attach to the remote Citadel system.\n\n");
186 printf("ctdlmigrate will now begin a database migration...\n");
188 snprintf(cmd, sizeof cmd, "ssh -S %s %s@%s %s -w3600 MIGR export",
189 socket_path, remote_user, remote_host, remote_sendcommand);
190 source_artv = popen(cmd, "r");
192 printf("\n%s\n\n", strerror(errno));
197 snprintf(cmd, sizeof cmd, "%s -w3600 MIGR import", sendcommand);
198 target_artv = popen(cmd, "w");
200 printf("\n%s\n\n", strerror(errno));
205 while (fgets(buf, sizeof buf, source_artv) != NULL) {
206 if (fwrite(buf, strlen(buf), 1, target_artv) < 1) {
208 printf("%s\n", strerror(errno));
212 if ((linecount % 100) == 0) {
213 printf("%c\r", spinning[((linecount / 100) % 4)]);
218 FAIL: pclose(source_artv);
221 // FIXME handle -h on both sides
222 // FIXME kill the master ssh session
223 printf("If this program was finished we would do more. FIXME\n");
225 THEEND: unlink(socket_path);