]> prime8.dev >> repos - ttyd.git/commitdiff
server: add cwd support
authorShuanglei Tao <tsl0922@gmail.com>
Mon, 16 Aug 2021 15:08:05 +0000 (23:08 +0800)
committerShuanglei Tao <tsl0922@gmail.com>
Mon, 16 Aug 2021 15:08:05 +0000 (23:08 +0800)
man/ttyd.1
man/ttyd.man.md
src/protocol.c
src/pty.c
src/pty.h
src/server.c
src/server.h

index 2a7ec97fe1f8d22383bbcc88f349d80a60d38782..c4e76ee4f9579cbb30210b5e08f9ec3e42b4e594 100644 (file)
@@ -62,6 +62,10 @@ Cross platform: macOS, Linux, FreeBSD/OpenBSD, OpenWrt/LEDE, Windows
 \-s, \-\-signal <signal string>
       Signal to send to the command when exit it (default: 1, SIGHUP)
 
+.PP
+\-w, \-\-cwd <path>
+      Working directory to be set for the child program
+
 .PP
 \-a, \-\-url\-arg
       Allow client to send command line arguments in URL (eg: 
index baf8fb45356280859c40af166d0ec79293f4addd..99c39941e1dfa8c3923baf98726edea838c5a41b 100644 (file)
@@ -40,6 +40,9 @@ ttyd 1 "September 2016" ttyd "User Manual"
   -s, --signal <signal string>
       Signal to send to the command when exit it (default: 1, SIGHUP)
 
+  -w, --cwd <path>
+      Working directory to be set for the child program
+
   -a, --url-arg
       Allow client to send command line arguments in URL (eg: http://localhost:7681?arg=foo&arg=bar)
 
index 0cecd26f1e433fa0d60747326ca8cc709b465f39..ca1e08697943b48cdfe743708581433fdd76934c 100644 (file)
@@ -134,6 +134,7 @@ static char **build_env(struct pss_tty *pss) {
 
 static bool spawn_process(struct pss_tty *pss, uint16_t columns, uint16_t rows) {
   pty_process *process = process_init((void *)pss, server->loop, build_args(pss), build_env(pss));
+  if (server->cwd != NULL) process->cwd = strdup(server->cwd);
   if (columns > 0) process->columns = columns;
   if (rows > 0) process->rows = rows;
   if (pty_spawn(process, process_read_cb, process_exit_cb) != 0) {
index 8171ac54682af5e510d2131b25aa642a699ca092..dd10bfd9ac503677fcd0d12ef01484cd59844ecd 100644 (file)
--- a/src/pty.c
+++ b/src/pty.c
@@ -125,6 +125,7 @@ void process_free(pty_process *process) {
 #endif
   if (process->io != NULL) pty_io_free(process->io);
   if (process->argv != NULL) free(process->argv);
+  if (process->cwd != NULL) free(process->cwd);
   char **p = process->envp;
   for (; *p; p++) free(*p);
   free(process->envp);
@@ -366,7 +367,7 @@ int pty_spawn(pty_process *process, pty_read_cb read_cb, pty_exit_cb exit_cb) {
   env = prep_env(process->envp);
   if (env == NULL) goto cleanup;
 
-  if (!CreateProcessW(NULL, cmdline, NULL, NULL, FALSE, flags, env, NULL, &process->si.StartupInfo, &pi)) {
+  if (!CreateProcessW(NULL, cmdline, NULL, NULL, FALSE, flags, env, process->cwd, &process->si.StartupInfo, &pi)) {
     print_error("CreateProcessW");
     goto cleanup;
   }
@@ -461,6 +462,12 @@ int pty_spawn(pty_process *process, pty_read_cb read_cb, pty_exit_cb exit_cb) {
     return status;
   } else if (pid == 0) {
     setsid();
+    if (process->cwd != NULL) {
+      if (chdir(process->cwd) == -1) {
+        perror("chdir failed\n");
+        _exit(1);
+      }
+    }
     int ret = pty_execvpe(process->argv[0], process->argv, process->envp);
     if (ret < 0) {
       perror("execvp failed\n");
index c4de47b0687d74b5de687f1cfe25320df148a86e..dbe5a30a84d82ebce60b12731429515f92c2614e 100644 (file)
--- a/src/pty.h
+++ b/src/pty.h
@@ -51,6 +51,7 @@ struct pty_process_ {
 #endif
   char **argv;
   char **envp;
+  char *cwd;
 
   uv_loop_t *loop;
   uv_async_t async;
index f5b985b61907af756f4ba466ae5ca79cdd1bf96a..f9113afd3f39bd522218a87119788ae18da2ab2b 100644 (file)
@@ -58,6 +58,7 @@ static const struct option options[] = {{"port", required_argument, NULL, 'p'},
                                         {"uid", required_argument, NULL, 'u'},
                                         {"gid", required_argument, NULL, 'g'},
                                         {"signal", required_argument, NULL, 's'},
+                                        {"cwd", required_argument, NULL, 'w'},
                                         {"index", required_argument, NULL, 'I'},
                                         {"base-path", required_argument, NULL, 'b'},
 #if LWS_LIBRARY_VERSION_NUMBER >= 4000000
@@ -80,7 +81,7 @@ static const struct option options[] = {{"port", required_argument, NULL, 'p'},
                                         {"version", no_argument, NULL, 'v'},
                                         {"help", no_argument, NULL, 'h'},
                                         {NULL, 0, 0, 0}};
-static const char *opt_string = "p:i:c:H:u:g:s:I:b:P:6aSC:K:A:Rt:T:Om:oBd:vh";
+static const char *opt_string = "p:i:c:H:u:g:s:w:I:b:P:6aSC:K:A:Rt:T:Om:oBd:vh";
 
 static void print_help() {
   // clang-format off
@@ -97,6 +98,7 @@ static void print_help() {
           "    -u, --uid               User id to run with\n"
           "    -g, --gid               Group id to run with\n"
           "    -s, --signal            Signal to send to the command when exit it (default: 1, SIGHUP)\n"
+          "    -w, --cwd               Working directory to be set for the child program\n"
           "    -a, --url-arg           Allow client to send command line arguments in URL (eg: http://localhost:7681?arg=foo&arg=bar)\n"
           "    -R, --readonly          Do not allow clients to write to the TTY\n"
           "    -t, --client-option     Send option to client (format: key=value), repeat to add more options\n"
@@ -198,6 +200,7 @@ static void server_free(struct server *ts) {
   if (ts->credential != NULL) free(ts->credential);
   if (ts->auth_header != NULL) free(ts->auth_header);
   if (ts->index != NULL) free(ts->index);
+  if (ts->cwd != NULL) free(ts->cwd);
   free(ts->command);
   free(ts->prefs_json);
 
@@ -398,6 +401,9 @@ int main(int argc, char **argv) {
           return -1;
         }
       } break;
+      case 'w':
+        server->cwd = strdup(optarg);
+        break;
       case 'I':
         if (!strncmp(optarg, "~/", 2)) {
           const char *home = getenv("HOME");
index b337536f3369b255532a9286e1f21f39f3f19780..b122d1c151acd9c3064cad3cf0aa6dad890aca16 100644 (file)
@@ -65,6 +65,7 @@ struct server {
   char *command;           // full command line
   char **argv;             // command with arguments
   int argc;                // command + arguments count
+  char *cwd;               // working directory
   int sig_code;            // close signal
   char sig_name[20];       // human readable signal string
   bool url_arg;            // allow client to send cli arguments in URL