| | @@ -2816,13 +2816,19 @@ |
| 2816 | 2816 | ** also present. |
| 2817 | 2817 | ** |
| 2818 | 2818 | ** If the REPOSITORY is a directory name which is the root of a |
| 2819 | 2819 | ** checkout, it will chdir to that directory and, unless overridden by |
| 2820 | 2820 | ** the --page option, select the current checkout version in the |
| 2821 | | -** timeline by default. |
| 2821 | +** timeline by default. This only works for the "fossil ui" command, |
| 2822 | +** not the "fossil server" command. |
| 2823 | +** |
| 2824 | +** If the REPOSITORY argument has a "HOST:" or "USER@HOST:" prefix, then |
| 2825 | +** the command is run on the remote host specified and the results are |
| 2826 | +** tunneled back to the localhost via SSH. This feature only works for |
| 2827 | +** the "fossil ui" command, not the "fossil server" command. |
| 2822 | 2828 | ** |
| 2823 | | -** For the special case REPOSITORY name of "/", the list global configuration |
| 2829 | +** For the special case REPOSITORY name of "/", the global configuration |
| 2824 | 2830 | ** database is consulted for a list of all known repositories. The --repolist |
| 2825 | 2831 | ** option is implied by this special case. See also the "fossil all ui" |
| 2826 | 2832 | ** command. |
| 2827 | 2833 | ** |
| 2828 | 2834 | ** By default, the "ui" command provides full administrative access without |
| | @@ -2892,10 +2898,12 @@ |
| 2892 | 2898 | const char *zFileGlob; /* Static content must match this */ |
| 2893 | 2899 | char *zIpAddr = 0; /* Bind to this IP address */ |
| 2894 | 2900 | int fCreate = 0; /* The --create flag */ |
| 2895 | 2901 | const char *zInitPage = 0; /* Start on this page. --page option */ |
| 2896 | 2902 | int findServerArg = 2; /* argv index for find_server_repository() */ |
| 2903 | + char *zRemote = 0; /* Remote host on which to run "fossil ui" */ |
| 2904 | + |
| 2897 | 2905 | |
| 2898 | 2906 | #if defined(_WIN32) |
| 2899 | 2907 | const char *zStopperFile; /* Name of file used to terminate server */ |
| 2900 | 2908 | zStopperFile = find_option("stopper", 0, 1); |
| 2901 | 2909 | #endif |
| | @@ -2973,16 +2981,30 @@ |
| 2973 | 2981 | fCreate = 0; |
| 2974 | 2982 | g.argv[2] = 0; |
| 2975 | 2983 | --g.argc; |
| 2976 | 2984 | } |
| 2977 | 2985 | } |
| 2986 | + if( isUiCmd && 3==g.argc |
| 2987 | + && (zRemote = (char*)file_skip_userhost(g.argv[2]))!=0 |
| 2988 | + ){ |
| 2989 | + const char *zRepoTail = file_skip_userhost(g.argv[2]); |
| 2990 | + unsigned x; |
| 2991 | + int n; |
| 2992 | + sqlite3_randomness(2,&x); |
| 2993 | + zPort = mprintf("%d", 8100+(x%32000)); |
| 2994 | + n = (int)(zRepoTail - g.argv[2]) - 1; |
| 2995 | + zRemote = mprintf("%.*s", n, g.argv[2]); |
| 2996 | + g.argv[2] = (char*)zRepoTail; |
| 2997 | + } |
| 2978 | 2998 | if( isUiCmd ){ |
| 2979 | 2999 | flags |= HTTP_SERVER_LOCALHOST|HTTP_SERVER_REPOLIST; |
| 2980 | 3000 | g.useLocalauth = 1; |
| 2981 | 3001 | allowRepoList = 1; |
| 2982 | 3002 | } |
| 2983 | | - find_server_repository(findServerArg, fCreate); |
| 3003 | + if( !zRemote ){ |
| 3004 | + find_server_repository(findServerArg, fCreate); |
| 3005 | + } |
| 2984 | 3006 | if( zInitPage==0 ){ |
| 2985 | 3007 | if( isUiCmd && g.localOpen ){ |
| 2986 | 3008 | zInitPage = "timeline?c=current"; |
| 2987 | 3009 | }else{ |
| 2988 | 3010 | zInitPage = ""; |
| | @@ -3004,25 +3026,59 @@ |
| 3004 | 3026 | iPort = mxPort = atoi(zPort); |
| 3005 | 3027 | }else{ |
| 3006 | 3028 | iPort = db_get_int("http-port", 8080); |
| 3007 | 3029 | mxPort = iPort+100; |
| 3008 | 3030 | } |
| 3009 | | -#if !defined(_WIN32) |
| 3010 | | - /* Unix implementation */ |
| 3011 | 3031 | if( isUiCmd ){ |
| 3032 | + char *zBrowserArg; |
| 3012 | 3033 | zBrowser = fossil_web_browser(); |
| 3013 | 3034 | if( zIpAddr==0 ){ |
| 3014 | | - zBrowserCmd = mprintf("%s \"http://localhost:%%d/%s\" &", |
| 3015 | | - zBrowser, zInitPage); |
| 3035 | + zBrowserArg = mprintf("http://localhost:%%d/%s", zInitPage); |
| 3016 | 3036 | }else if( strchr(zIpAddr,':') ){ |
| 3017 | | - zBrowserCmd = mprintf("%s \"http://[%s]:%%d/%s\" &", |
| 3018 | | - zBrowser, zIpAddr, zInitPage); |
| 3037 | + zBrowserArg = mprintf("http://[%s]:%%d/%s", zIpAddr, zInitPage); |
| 3019 | 3038 | }else{ |
| 3020 | | - zBrowserCmd = mprintf("%s \"http://%s:%%d/%s\" &", |
| 3021 | | - zBrowser, zIpAddr, zInitPage); |
| 3039 | + zBrowserArg = mprintf("http://%s:%%d/%s", zIpAddr, zInitPage); |
| 3040 | + } |
| 3041 | +#ifdef _WIN32 |
| 3042 | + zBrowserCmd = mprintf("%s %s &", zBrowser, zBrowserArg); |
| 3043 | +#else |
| 3044 | + zBrowserCmd = mprintf("%s %!$ &", zBrowser, zBrowserArg); |
| 3045 | +#endif |
| 3046 | + fossil_free(zBrowserArg); |
| 3047 | + } |
| 3048 | + if( zRemote && zBrowserCmd ){ |
| 3049 | + FILE *sshIn; |
| 3050 | + Blob ssh; |
| 3051 | + char zLine[1000]; |
| 3052 | + blob_init(&ssh, 0, 0); |
| 3053 | + transport_ssh_command(&ssh); |
| 3054 | + blob_appendf(&ssh, |
| 3055 | + " -t -L127.0.0.1:%d:127.0.0.1:%d -- %!$" |
| 3056 | + " fossil server --nossl --port %d %!$", |
| 3057 | + iPort, iPort, zRemote, iPort, g.argv[2]); |
| 3058 | + fossil_print("%s\n", blob_str(&ssh)); |
| 3059 | + sshIn = popen(blob_str(&ssh), "r"); |
| 3060 | + if( sshIn==0 ){ |
| 3061 | + fossil_fatal("unable to %s", blob_str(&ssh)); |
| 3062 | + } |
| 3063 | + while( fgets(zLine, sizeof(zLine), sshIn) ){ |
| 3064 | + fossil_print("%s", zLine); |
| 3065 | + fflush(stdout); |
| 3066 | + if( zBrowserCmd ){ |
| 3067 | + char *zCmd = mprintf(zBrowserCmd/*works-like:"%d"*/,iPort); |
| 3068 | + fossil_system(zCmd); |
| 3069 | + fossil_free(zCmd); |
| 3070 | + fossil_free(zBrowserCmd); |
| 3071 | + zBrowserCmd = 0; |
| 3072 | + } |
| 3022 | 3073 | } |
| 3074 | + pclose(sshIn); |
| 3075 | + fossil_free(zBrowserCmd); |
| 3076 | + return; |
| 3023 | 3077 | } |
| 3078 | +#if !defined(_WIN32) |
| 3079 | + /* Unix implementation */ |
| 3024 | 3080 | if( g.repositoryOpen ) flags |= HTTP_SERVER_HAD_REPOSITORY; |
| 3025 | 3081 | if( g.localOpen ) flags |= HTTP_SERVER_HAD_CHECKOUT; |
| 3026 | 3082 | db_close(1); |
| 3027 | 3083 | if( cgi_http_server(iPort, mxPort, zBrowserCmd, zIpAddr, flags) ){ |
| 3028 | 3084 | fossil_fatal("unable to listen on TCP socket %d", iPort); |
| | @@ -3069,23 +3125,10 @@ |
| 3069 | 3125 | fprintf(stderr, "/***** Webpage finished in subprocess %d *****/\n", |
| 3070 | 3126 | getpid()); |
| 3071 | 3127 | } |
| 3072 | 3128 | #else |
| 3073 | 3129 | /* Win32 implementation */ |
| 3074 | | - if( isUiCmd ){ |
| 3075 | | - zBrowser = fossil_web_browser(); |
| 3076 | | - if( zIpAddr==0 ){ |
| 3077 | | - zBrowserCmd = mprintf("%s http://localhost:%%d/%s &", |
| 3078 | | - zBrowser, zInitPage); |
| 3079 | | - }else if( strchr(zIpAddr,':') ){ |
| 3080 | | - zBrowserCmd = mprintf("%s http://[%s]:%%d/%s &", |
| 3081 | | - zBrowser, zIpAddr, zInitPage); |
| 3082 | | - }else{ |
| 3083 | | - zBrowserCmd = mprintf("%s http://%s:%%d/%s &", |
| 3084 | | - zBrowser, zIpAddr, zInitPage); |
| 3085 | | - } |
| 3086 | | - } |
| 3087 | 3130 | if( g.repositoryOpen ) flags |= HTTP_SERVER_HAD_REPOSITORY; |
| 3088 | 3131 | if( g.localOpen ) flags |= HTTP_SERVER_HAD_CHECKOUT; |
| 3089 | 3132 | db_close(1); |
| 3090 | 3133 | if( allowRepoList ){ |
| 3091 | 3134 | flags |= HTTP_SERVER_REPOLIST; |
| 3092 | 3135 | |