aboutsummaryrefslogtreecommitdiff
path: root/tool/sqlite3_rsync.c
diff options
context:
space:
mode:
Diffstat (limited to 'tool/sqlite3_rsync.c')
-rw-r--r--tool/sqlite3_rsync.c193
1 files changed, 136 insertions, 57 deletions
diff --git a/tool/sqlite3_rsync.c b/tool/sqlite3_rsync.c
index 819975f02..a6b4d6135 100644
--- a/tool/sqlite3_rsync.c
+++ b/tool/sqlite3_rsync.c
@@ -522,6 +522,53 @@ int append_escaped_arg(sqlite3_str *pStr, const char *zIn, int isFilename){
}
return 0;
}
+
+/* Add an approprate PATH= argument to the SSH command under construction
+** in pStr
+**
+** About This Feature
+** ==================
+**
+** On some ssh servers (Macs in particular are guilty of this) the PATH
+** variable in the shell that runs the command that is sent to the remote
+** host contains a limited number of read-only system directories:
+**
+** /usr/bin:/bin:/usr/sbin:/sbin
+**
+** The sqlite3_rsync executable cannot be installed into any of those
+** directories because they are locked down, and so the "sqlite3_rsync"
+** command cannot run.
+**
+** To work around this, the sqlite3_rsync command is prefixed with a PATH=
+** argument, inserted by this function, to augment the PATH with additional
+** directories in which the sqlite3_rsync executable can be installed.
+**
+** But other ssh servers are confused by this initial PATH= argument.
+** Some ssh servers have a list of programs that they are allowed to run
+** and will fail if the first argument is not on that list, and PATH=....
+** is not on that list.
+**
+** So that sqlite3_rsync can invoke itself on a remote system using ssh
+** on a variety of platforms, the following algorithm is used:
+**
+** * First try running the sqlite3_rsync without any PATH= argument.
+** If that works (and it does on a majority of systems) then we are
+** done.
+**
+** * If the first attempt fails, then try again after adding the
+** PATH= prefix argument. (This function is what adds that
+** argument.)
+**
+** A consequence of this is that if the remote system is a Mac, the
+** "ssh" command always ends up being invoked twice. If anybody knows a
+** way around that problem, please bring it to the attention of the
+** developers.
+*/
+void add_path_argument(sqlite3_str *pStr){
+ append_escaped_arg(pStr,
+ "PATH=$HOME/bin:/usr/local/bin:/opt/homebrew/bin:$PATH", 0);
+}
+
/*****************************************************************************
** End of the append_escaped_arg() routine, adapted from the Fossil **
*****************************************************************************/
@@ -1968,9 +2015,9 @@ static char *hostSeparator(const char *zIn){
zIn++;
}
return zPath;
-
}
+
/*
** Parse command-line arguments. Dispatch subroutines to do the
** requested work.
@@ -2175,74 +2222,106 @@ int main(int argc, char const * const *argv){
tmStart = currentTime();
zDiv = hostSeparator(ctx.zOrigin);
if( zDiv ){
+ int iRetry;
if( hostSeparator(ctx.zReplica)!=0 ){
fprintf(stderr,
"At least one of ORIGIN and REPLICA must be a local database\n"
"You provided two remote databases.\n");
return 1;
}
- /* Remote ORIGIN and local REPLICA */
- sqlite3_str *pStr = sqlite3_str_new(0);
- append_escaped_arg(pStr, zSsh, 1);
- sqlite3_str_appendf(pStr, " -e none");
*(zDiv++) = 0;
- append_escaped_arg(pStr, ctx.zOrigin, 0);
- append_escaped_arg(pStr, zExe, 1);
- append_escaped_arg(pStr, "--origin", 0);
- if( ctx.bCommCheck ){
- append_escaped_arg(pStr, "--commcheck", 0);
- if( ctx.eVerbose==0 ) ctx.eVerbose = 1;
- }
- if( zRemoteErrFile ){
- append_escaped_arg(pStr, "--errorfile", 0);
- append_escaped_arg(pStr, zRemoteErrFile, 1);
- }
- if( zRemoteDebugFile ){
- append_escaped_arg(pStr, "--debugfile", 0);
- append_escaped_arg(pStr, zRemoteDebugFile, 1);
- }
- if( ctx.bWalOnly ){
- append_escaped_arg(pStr, "--wal-only", 0);
- }
- append_escaped_arg(pStr, zDiv, 1);
- append_escaped_arg(pStr, file_tail(ctx.zReplica), 1);
- zCmd = sqlite3_str_finish(pStr);
- if( ctx.eVerbose>=2 ) printf("%s\n", zCmd);
- if( popen2(zCmd, &ctx.pIn, &ctx.pOut, &childPid, 0) ){
- fprintf(stderr, "Could not start auxiliary process: %s\n", zCmd);
- return 1;
+ /* Remote ORIGIN and local REPLICA */
+ for(iRetry=0; 1 /*exit-via-break*/; iRetry++){
+ sqlite3_str *pStr = sqlite3_str_new(0);
+ append_escaped_arg(pStr, zSsh, 1);
+ sqlite3_str_appendf(pStr, " -e none");
+ append_escaped_arg(pStr, ctx.zOrigin, 0);
+ if( iRetry ) add_path_argument(pStr);
+ append_escaped_arg(pStr, zExe, 1);
+ append_escaped_arg(pStr, "--origin", 0);
+ if( ctx.bCommCheck ){
+ append_escaped_arg(pStr, "--commcheck", 0);
+ if( ctx.eVerbose==0 ) ctx.eVerbose = 1;
+ }
+ if( zRemoteErrFile ){
+ append_escaped_arg(pStr, "--errorfile", 0);
+ append_escaped_arg(pStr, zRemoteErrFile, 1);
+ }
+ if( zRemoteDebugFile ){
+ append_escaped_arg(pStr, "--debugfile", 0);
+ append_escaped_arg(pStr, zRemoteDebugFile, 1);
+ }
+ if( ctx.bWalOnly ){
+ append_escaped_arg(pStr, "--wal-only", 0);
+ }
+ append_escaped_arg(pStr, zDiv, 1);
+ append_escaped_arg(pStr, file_tail(ctx.zReplica), 1);
+ if( ctx.eVerbose<2 && iRetry==0 ){
+ append_escaped_arg(pStr, "2>/dev/null", 0);
+ }
+ zCmd = sqlite3_str_finish(pStr);
+ if( ctx.eVerbose>=2 ) printf("%s\n", zCmd);
+ if( popen2(zCmd, &ctx.pIn, &ctx.pOut, &childPid, 0) ){
+ if( iRetry>=1 ){
+ fprintf(stderr, "Could not start auxiliary process: %s\n", zCmd);
+ return 1;
+ }
+ if( ctx.eVerbose>=2 ){
+ printf("ssh FAILED. Retry with a PATH= argument...\n");
+ }
+ continue;
+ }
+ replicaSide(&ctx);
+ if( ctx.nHashSent==0 && iRetry==0 ) continue;
+ break;
}
- replicaSide(&ctx);
}else if( (zDiv = hostSeparator(ctx.zReplica))!=0 ){
/* Local ORIGIN and remote REPLICA */
- sqlite3_str *pStr = sqlite3_str_new(0);
- append_escaped_arg(pStr, zSsh, 1);
- sqlite3_str_appendf(pStr, " -e none");
+ int iRetry;
*(zDiv++) = 0;
- append_escaped_arg(pStr, ctx.zReplica, 0);
- append_escaped_arg(pStr, zExe, 1);
- append_escaped_arg(pStr, "--replica", 0);
- if( ctx.bCommCheck ){
- append_escaped_arg(pStr, "--commcheck", 0);
- if( ctx.eVerbose==0 ) ctx.eVerbose = 1;
- }
- if( zRemoteErrFile ){
- append_escaped_arg(pStr, "--errorfile", 0);
- append_escaped_arg(pStr, zRemoteErrFile, 1);
- }
- if( zRemoteDebugFile ){
- append_escaped_arg(pStr, "--debugfile", 0);
- append_escaped_arg(pStr, zRemoteDebugFile, 1);
- }
- append_escaped_arg(pStr, file_tail(ctx.zOrigin), 1);
- append_escaped_arg(pStr, zDiv, 1);
- zCmd = sqlite3_str_finish(pStr);
- if( ctx.eVerbose>=2 ) printf("%s\n", zCmd);
- if( popen2(zCmd, &ctx.pIn, &ctx.pOut, &childPid, 0) ){
- fprintf(stderr, "Could not start auxiliary process: %s\n", zCmd);
- return 1;
+ for(iRetry=0; 1 /*exit-by-break*/; iRetry++){
+ sqlite3_str *pStr = sqlite3_str_new(0);
+ append_escaped_arg(pStr, zSsh, 1);
+ sqlite3_str_appendf(pStr, " -e none");
+ append_escaped_arg(pStr, ctx.zReplica, 0);
+ if( iRetry==1 ) add_path_argument(pStr);
+ append_escaped_arg(pStr, zExe, 1);
+ append_escaped_arg(pStr, "--replica", 0);
+ if( ctx.bCommCheck ){
+ append_escaped_arg(pStr, "--commcheck", 0);
+ if( ctx.eVerbose==0 ) ctx.eVerbose = 1;
+ }
+ if( zRemoteErrFile ){
+ append_escaped_arg(pStr, "--errorfile", 0);
+ append_escaped_arg(pStr, zRemoteErrFile, 1);
+ }
+ if( zRemoteDebugFile ){
+ append_escaped_arg(pStr, "--debugfile", 0);
+ append_escaped_arg(pStr, zRemoteDebugFile, 1);
+ }
+ if( ctx.bWalOnly ){
+ append_escaped_arg(pStr, "--wal-only", 0);
+ }
+ append_escaped_arg(pStr, file_tail(ctx.zOrigin), 1);
+ append_escaped_arg(pStr, zDiv, 1);
+ if( ctx.eVerbose<2 && iRetry==0 ){
+ append_escaped_arg(pStr, "2>/dev/null", 0);
+ }
+ zCmd = sqlite3_str_finish(pStr);
+ if( ctx.eVerbose>=2 ) printf("%s\n", zCmd);
+ if( popen2(zCmd, &ctx.pIn, &ctx.pOut, &childPid, 0) ){
+ if( iRetry>=1 ){
+ fprintf(stderr, "Could not start auxiliary process: %s\n", zCmd);
+ return 1;
+ }else if( ctx.eVerbose>=2 ){
+ printf("ssh FAILED. Retry with a PATH= argument...\n");
+ }
+ continue;
+ }
+ originSide(&ctx);
+ if( ctx.nHashSent==0 && iRetry==0 ) continue;
+ break;
}
- originSide(&ctx);
}else{
/* Local ORIGIN and REPLICA */
sqlite3_str *pStr = sqlite3_str_new(0);