@@ -110,21 +110,82 @@ static void process_exit_cb(pty_process *process) {
110110
111111static char * * build_args (struct pss_tty * pss ) {
112112 int i , n = 0 ;
113- char * * argv = xmalloc ((server -> argc + pss -> argc + 1 ) * sizeof (char * ));
114-
115- for (i = 0 ; i < server -> argc ; i ++ ) {
116- argv [n ++ ] = server -> argv [i ];
113+ char * * argv ;
114+ bool use_dynamic = (pss -> dynamic_argv != NULL && pss -> dynamic_argc > 0 );
115+
116+ // Use dynamic command if available, otherwise use server default
117+ if (use_dynamic ) {
118+ argv = xmalloc ((pss -> dynamic_argc + 1 ) * sizeof (char * ));
119+ for (i = 0 ; i < pss -> dynamic_argc ; i ++ ) {
120+ argv [n ++ ] = pss -> dynamic_argv [i ];
121+ }
122+ } else {
123+ argv = xmalloc ((server -> argc + pss -> argc + 1 ) * sizeof (char * ));
124+ for (i = 0 ; i < server -> argc ; i ++ ) {
125+ argv [n ++ ] = server -> argv [i ];
126+ }
117127 }
118128
119- for (i = 0 ; i < pss -> argc ; i ++ ) {
120- argv [n ++ ] = pss -> args [i ];
129+ if (!use_dynamic ) {
130+ for (i = 0 ; i < pss -> argc ; i ++ ) {
131+ argv [n ++ ] = pss -> args [i ];
132+ }
121133 }
122134
123135 argv [n ] = NULL ;
124136
125137 return argv ;
126138}
127139
140+ static void free_dynamic_command (struct pss_tty * pss );
141+
142+ // Parse dynamic command string into argv array using /bin/sh -c
143+ // Returns true on success, false on failure (e.g., empty command)
144+ static bool parse_dynamic_command (struct pss_tty * pss , const char * cmd ) {
145+ if (cmd == NULL || strlen (cmd ) == 0 ) {
146+ return false;
147+ }
148+
149+ // Limit command length to prevent excessive memory allocation
150+ size_t cmd_len = strlen (cmd );
151+ if (cmd_len > 8192 ) {
152+ lwsl_warn ("dynamic command too long (max 8192 chars)\n" );
153+ return false;
154+ }
155+
156+ free_dynamic_command (pss );
157+
158+ #ifdef _WIN32
159+ const char * shell = "cmd.exe" ;
160+ const char * flag = "/C" ;
161+ #else
162+ const char * shell = "/bin/sh" ;
163+ const char * flag = "-c" ;
164+ #endif
165+
166+ // Use shell -c to execute the command
167+ pss -> dynamic_argc = 3 ;
168+ pss -> dynamic_argv = xmalloc (4 * sizeof (char * ));
169+ pss -> dynamic_argv [0 ] = strdup (shell );
170+ pss -> dynamic_argv [1 ] = strdup (flag );
171+ pss -> dynamic_argv [2 ] = strdup (cmd );
172+ pss -> dynamic_argv [3 ] = NULL ;
173+
174+ return true;
175+ }
176+
177+ // Free dynamic command argv
178+ static void free_dynamic_command (struct pss_tty * pss ) {
179+ if (pss -> dynamic_argv != NULL ) {
180+ for (int i = 0 ; i < pss -> dynamic_argc ; i ++ ) {
181+ free (pss -> dynamic_argv [i ]);
182+ }
183+ free (pss -> dynamic_argv );
184+ pss -> dynamic_argv = NULL ;
185+ pss -> dynamic_argc = 0 ;
186+ }
187+ }
188+
128189static char * * build_env (struct pss_tty * pss ) {
129190 int i = 0 , n = 2 ;
130191 char * * envp = xmalloc (n * sizeof (char * ));
@@ -231,6 +292,8 @@ int callback_tty(struct lws *wsi, enum lws_callback_reasons reason, void *user,
231292 case LWS_CALLBACK_ESTABLISHED :
232293 pss -> initialized = false;
233294 pss -> authenticated = false;
295+ pss -> dynamic_argv = NULL ;
296+ pss -> dynamic_argc = 0 ;
234297 pss -> wsi = wsi ;
235298 pss -> lws_close_status = LWS_CLOSE_STATUS_NOSTATUS ;
236299
@@ -345,6 +408,19 @@ int callback_tty(struct lws *wsi, enum lws_callback_reasons reason, void *user,
345408 return -1 ;
346409 }
347410 }
411+ // Parse dynamic command if enabled and present
412+ if (server -> allow_dynamic_cmd ) {
413+ struct json_object * cmd_obj = NULL ;
414+ if (json_object_object_get_ex (obj , "command" , & cmd_obj )) {
415+ const char * cmd = json_object_get_string (cmd_obj );
416+ if (cmd != NULL && strlen (cmd ) > 0 ) {
417+ if (!parse_dynamic_command (pss , cmd )) {
418+ lwsl_warn ("failed to parse dynamic command\n" );
419+ // Fall back to server default command
420+ }
421+ }
422+ }
423+ }
348424 json_object_put (obj );
349425 if (!spawn_process (pss , columns , rows )) return 1 ;
350426 break ;
@@ -366,9 +442,13 @@ int callback_tty(struct lws *wsi, enum lws_callback_reasons reason, void *user,
366442 lwsl_notice ("WS closed from %s, clients: %d\n" , pss -> address , server -> client_count );
367443 if (pss -> buffer != NULL ) free (pss -> buffer );
368444 if (pss -> pty_buf != NULL ) pty_buf_free (pss -> pty_buf );
369- for (int i = 0 ; i < pss -> argc ; i ++ ) {
370- free (pss -> args [i ]);
445+ if (pss -> args != NULL ) {
446+ for (int i = 0 ; i < pss -> argc ; i ++ ) {
447+ free (pss -> args [i ]);
448+ }
449+ free (pss -> args );
371450 }
451+ free_dynamic_command (pss );
372452
373453 if (pss -> process != NULL ) {
374454 ((pty_ctx_t * )pss -> process -> ctx )-> ws_closed = true;
0 commit comments