SQLite

Check-in [38d4c94d8c]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Enhance sqlite3_rsync so that if the first attempt to invoke a copy of itself on the remote system using ssh fails, try again after augmenting the PATH. This enables sqlite3_rsync to work without the --exe option when the remote system is a Mac.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | trunk
Files: files | file ages | folders
SHA3-256: 38d4c94d8c7802101ef3bfb411002f9497fdbbbd2b4d3514cef5b76ffd66f75b
User & Date: drh 2025-05-03 15:17:21.853
Context
2025-05-03
15:17
Enhance sqlite3_rsync so that if the first attempt to invoke a copy of itself on the remote system using ssh fails, try again after augmenting the PATH. This enables sqlite3_rsync to work without the --exe option when the remote system is a Mac. (Leaf check-in: 38d4c94d8c user: drh tags: trunk)
10:55
Fix a harmless redundant variable declaration in sqlite3_rsync. (check-in: f8f15eff6a user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to tool/sqlite3_rsync.c.
518
519
520
521
522
523
524















































525
526
527
528
529
530
531
      sqlite3_str_appendall(pStr, zIn);
      sqlite3_str_appendchar(pStr, 1, '\'');
    }
#endif
  }
  return 0;
}















































/*****************************************************************************
** End of the append_escaped_arg() routine, adapted from the Fossil         **
*****************************************************************************/

/*****************************************************************************
** The Hash Engine
**







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
      sqlite3_str_appendall(pStr, zIn);
      sqlite3_str_appendchar(pStr, 1, '\'');
    }
#endif
  }
  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         **
*****************************************************************************/

/*****************************************************************************
** The Hash Engine
**
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
#endif
  while( zIn<zPath ){
    if( zIn[0]=='/' ) return 0;
    if( zIn[0]=='\\' ) return 0;
    zIn++;
  }
  return zPath;

}

/*
** Parse command-line arguments.  Dispatch subroutines to do the
** requested work.
**
** Input formats:
**







|
|







2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
#endif
  while( zIn<zPath ){
    if( zIn[0]=='/' ) return 0;
    if( zIn[0]=='\\' ) return 0;
    zIn++;
  }
  return zPath;
}


/*
** Parse command-line arguments.  Dispatch subroutines to do the
** requested work.
**
** Input formats:
**
2171
2172
2173
2174
2175
2176
2177

2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188





2189

2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208



2209
2210
2211

2212
2213
2214





2215



2216
2217
2218
2219
2220
2221




2222

2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236



2237
2238



2239
2240
2241

2242
2243


2244


2245



2246
2247
2248
2249
2250
2251
2252
  if( ctx.zReplica==0 ){
    fprintf(stderr, "missing REPLICA database filename\n");
    return 1;
  }
  tmStart = currentTime();
  zDiv = hostSeparator(ctx.zOrigin);
  if( zDiv ){

    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;
    }





    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");
    *(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;


    }


    originSide(&ctx);



  }else{
    /* Local ORIGIN and REPLICA */
    sqlite3_str *pStr = sqlite3_str_new(0);
    append_escaped_arg(pStr, argv[0], 1);
    append_escaped_arg(pStr, "--replica", 0);
    if( ctx.bCommCheck ){
      append_escaped_arg(pStr, "--commcheck", 0);







>






<
<
<
<

>
>
>
>
>
|
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
>
>
>
|
|
|
>
|
|
|
>
>
>
>
>
|
>
>
>


|
<
<

>
>
>
>
|
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
>
>
>
|
|
>
>
>
|
|
|
>
|
|
>
>
|
>
>
|
>
>
>







2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231




2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280


2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
  if( ctx.zReplica==0 ){
    fprintf(stderr, "missing REPLICA database filename\n");
    return 1;
  }
  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;
    }




    *(zDiv++) = 0;
    /* 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;
    }
  }else if( (zDiv = hostSeparator(ctx.zReplica))!=0 ){
    /* Local ORIGIN and remote REPLICA */
    int iRetry;


    *(zDiv++) = 0;
    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;
    }
  }else{
    /* Local ORIGIN and REPLICA */
    sqlite3_str *pStr = sqlite3_str_new(0);
    append_escaped_arg(pStr, argv[0], 1);
    append_escaped_arg(pStr, "--replica", 0);
    if( ctx.bCommCheck ){
      append_escaped_arg(pStr, "--commcheck", 0);