PageRenderTime 1344ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/release/src-rt/wl/exe/shellproc_linux.c

https://gitlab.com/envieidoc/advancedtomato2
C | 714 lines | 484 code | 77 blank | 153 comment | 115 complexity | 23131d6c83b55f8eb117f2f1d5769e35 MD5 | raw file
  1. /*
  2. * Remote shell command execution (common for all transports) for linux
  3. *
  4. * Copyright (C) 2010, Broadcom Corporation
  5. * All Rights Reserved.
  6. *
  7. * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation;
  8. * the contents of this file may not be disclosed to third parties, copied
  9. * or duplicated in any form, in whole or in part, without the prior
  10. * written permission of Broadcom Corporation.
  11. *
  12. * $Id: shellproc_linux.c,v 1.12 2009-08-11 08:51:01 Exp $
  13. */
  14. /* Linux remote shell command execution
  15. *
  16. */
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <ctype.h>
  20. #include <unistd.h>
  21. #include <errno.h>
  22. #include <string.h>
  23. #include <sys/stat.h>
  24. #include <sys/time.h>
  25. #include <sys/socket.h>
  26. #include <sys/select.h>
  27. #include <sys/types.h>
  28. #include <netinet/in.h>
  29. #include <sys/wait.h>
  30. #include <signal.h>
  31. #include <fcntl.h>
  32. #include <typedefs.h>
  33. #include <bcmutils.h>
  34. #include <bcmcdc.h>
  35. #include "wlu_remote.h"
  36. #include <sys/poll.h>
  37. #ifndef MACOSX
  38. #include <malloc.h>
  39. #endif
  40. #include <miniopt.h>
  41. #include <sys/utsname.h>
  42. #define ASYNC_RESP 0
  43. #define MAX_SHELL_ASYNC_RESP 128 /* Support for maximum 5 async process */
  44. #define MAX_ASYNC_FILE_LENGTH 50
  45. #define MAX_PID_CMD_LENGTH 20
  46. #define MAX_PID_RESP_LENTH 50
  47. #define MAX_SHELL_CMD_LENTH 256
  48. #define PID_TOKEN_SIZE 50
  49. #define PID_SEARCH_CMD_SIZE 100
  50. #define ASYNC_SHELL_CHAR "%" /* Async process identifier from the client */
  51. #define FILE_PERMISSION 777
  52. #define DEFAULT_SHELL_TIMEOUT 0 /* Default TimeOut Value for synchronous shell commands */
  53. #define SHELL_RETURNVALUE_SIZE 2 /* Size of Return Value of the shell command */
  54. #define SHELL_ASYNCCMD_ID 1 /* To identify if it is an async command */
  55. #define REBOOT_MSG "Rebooting AP ...\n"
  56. /* Function prototypes */
  57. static int rwl_get_file_size(char *file_name);
  58. static int remote_shell_async_exec(char *buf_ptr);
  59. static int remote_shell_sync_exec(char *cmd_buf_ptr, void *wl);
  60. /* Data structure to hold async shell information */
  61. typedef struct remote_shell_async {
  62. pid_t PID;
  63. char file_name[MAX_ASYNC_FILE_LENGTH];
  64. } remote_shell_async_t;
  65. remote_shell_async_t g_async_resp[MAX_SHELL_ASYNC_RESP];
  66. extern int g_shellsync_pid;
  67. extern unsigned char g_return_stat;
  68. extern void rwl_chld_handler(int num);
  69. extern int set_ctrlc;
  70. extern void handle_ctrlc(int unused);
  71. /* Global variable to store the timeout value for the shell commands */
  72. static int g_shellsync_timeout = DEFAULT_SHELL_TIMEOUT;
  73. char globalbuffer[MAX_SHELL_CMD_LENTH];
  74. /* Wait for process termination.
  75. * This function returns immediately if the child has
  76. * already exited (zombie process)
  77. */
  78. static void
  79. sigchld_handler(int s)
  80. {
  81. UNUSED_PARAMETER(s);
  82. while (waitpid(-1, NULL, WNOHANG) > 0);
  83. }
  84. /* Create a main directory \tmp\RWL\ for the shell response files */
  85. int
  86. rwl_create_dir(void)
  87. {
  88. #ifndef MACOSX
  89. if (mkdir(SHELL_RESP_PATH, FILE_PERMISSION) < 0) {
  90. if (errno != EEXIST)
  91. return BCME_ERROR;
  92. }
  93. #else
  94. system("mkdir -p /tmp/RWL");
  95. #endif /* mkdir linux command doesnot work in MAC, hence using shell */
  96. return SUCCESS;
  97. }
  98. /* Main function for shell command execution */
  99. int
  100. remote_shell_execute(char* buf_ptr, void *wl)
  101. {
  102. char *async_cmd_flag;
  103. int msg_len;
  104. /* Check for the "%" token in the buffer from client
  105. * If "%" token is present, execute asynchronous process
  106. * else, execute synchronous shell process
  107. */
  108. async_cmd_flag = strstr((char*)buf_ptr, ASYNC_SHELL_CHAR);
  109. if ((async_cmd_flag != NULL) && (!strcmp(async_cmd_flag, ASYNC_SHELL_CHAR))) {
  110. g_shellsync_pid = SHELL_ASYNCCMD_ID;
  111. msg_len = remote_shell_async_exec(buf_ptr);
  112. }
  113. else {
  114. msg_len = remote_shell_sync_exec(buf_ptr, wl);
  115. strcpy(buf_ptr, globalbuffer);
  116. }
  117. return msg_len;
  118. }
  119. /* Function to get the shell response from the file */
  120. int
  121. remote_shell_async_get_resp(char* shell_fname, char* buf_ptr, int msg_len)
  122. {
  123. int sts = 0;
  124. FILE *shell_fpt;
  125. shell_fpt = fopen(shell_fname, "rb");
  126. if (shell_fpt == NULL) {
  127. DPRINT_ERR(ERR, "\nShell Cmd:File open error\n");
  128. return sts;
  129. }
  130. /* If there is any response from the shell, Read the file and
  131. * update the buffer for the shell response
  132. * else Just send the return value of the command executed
  133. */
  134. if (g_shellsync_pid != SHELL_ASYNCCMD_ID) {
  135. if (msg_len)
  136. sts = fread(buf_ptr, sizeof(char), msg_len, shell_fpt);
  137. fscanf(shell_fpt, "%2x", &sts);
  138. }
  139. else
  140. sts = fread(buf_ptr, sizeof(char), MAX_SHELL_CMD_LENTH, shell_fpt);
  141. fclose(shell_fpt);
  142. remove(shell_fname);
  143. DPRINT_DBG(OUTPUT, "\n Resp buff from shell cmdis %s\n", buf_ptr);
  144. return sts;
  145. }
  146. /*
  147. * Function to get the shell response length
  148. * by opening the file containing the shell response
  149. * and get the total file size.
  150. * For a given input file name it returns File size.
  151. */
  152. static int
  153. rwl_get_file_size(char *file_name)
  154. {
  155. FILE *shell_fpt;
  156. int filesize = 0;
  157. shell_fpt = fopen(file_name, "rb");
  158. if (shell_fpt == NULL) {
  159. DPRINT_DBG(OUTPUT, "\nShell Cmd:File open error\n");
  160. return filesize;
  161. }
  162. /* obtain file size */
  163. if (fseek(shell_fpt, 0, SEEK_END) < 0)
  164. return filesize;
  165. filesize = ftell(shell_fpt);
  166. fclose(shell_fpt);
  167. return filesize;
  168. }
  169. /*
  170. * Function for executing asynchronous shell comamnd
  171. * Stores the results in async temp file and returns the PID
  172. */
  173. static int
  174. remote_shell_async_exec(char *buf_ptr)
  175. {
  176. int PID_val, val, msg_len, sts;
  177. FILE *fpt;
  178. int async_count = 0; /* counter needs to be initialized */
  179. struct sigaction sa;
  180. char pid_search_cmd[MAX_PID_CMD_LENGTH];
  181. char pid_resp_buf[MAX_PID_RESP_LENTH];
  182. char temp_async_file_name[MAX_ASYNC_FILE_LENGTH];
  183. pid_t pid;
  184. char *pid_token, next_pid[PID_TOKEN_SIZE][PID_TOKEN_SIZE];
  185. struct utsname name;
  186. /* Call the signal handler for reaping defunct or zombie process */
  187. sa.sa_handler = sigchld_handler;
  188. sigemptyset(&sa.sa_mask);
  189. sa.sa_flags = SA_RESTART;
  190. if (sigaction(SIGCHLD, &sa, NULL) == -1) {
  191. perror("sigaction:");
  192. }
  193. /* Store the async file name if that async process is not killed.
  194. * Async file name: async_temp_0...5
  195. */
  196. for (val = 0; val < MAX_SHELL_ASYNC_RESP; val++) {
  197. if (g_async_resp[val].PID > 0) {
  198. async_count++;
  199. } else {
  200. sprintf(g_async_resp[val].file_name, "%s%d", "async_temp_", val);
  201. break;
  202. }
  203. }
  204. sprintf(temp_async_file_name, "%s%s", SHELL_RESP_PATH,
  205. g_async_resp[val].file_name);
  206. DPRINT_DBG(OUTPUT, "\nasync_count:%d\n", async_count);
  207. if (async_count >= MAX_SHELL_ASYNC_RESP) {
  208. sprintf(buf_ptr, "\n%s\n", "Exceeded max async process forking");
  209. return BCME_ERROR;
  210. }
  211. /* Open a child process. The fork will return the PID of the child process
  212. * (i.e) defunct process PID in parent's thread of execution. Zero is returned
  213. * for child's thread of execution.
  214. */
  215. if ((pid = fork()) == 0) {
  216. /* Redirect the async process output to the async file
  217. * Then after the client executes the kill command for that
  218. * async process, the file will give the status of async process
  219. */
  220. strtok(buf_ptr, ASYNC_SHELL_CHAR); /* Remove % character from the command buf */
  221. uname(&name);
  222. /*
  223. * Checking for mips architecture
  224. * different command for mips and x86
  225. */
  226. if (strncmp(name.machine, "mips", sizeof(name.machine)) != 0) {
  227. strcat(buf_ptr, "&> "); /* buf_ptr is now "ping 127.0.0.1&> " */
  228. strcat(buf_ptr, temp_async_file_name); /* Add path \tmp\RWL\async_temp_* */
  229. }
  230. else {
  231. strcat(buf_ptr, " > "); /* buf_ptr is now "ping 127.0.0.1> " */
  232. strcat(buf_ptr, temp_async_file_name); /* Add path \tmp\RWL\async_temp_* */
  233. strcat(buf_ptr, " 2>&1 &");
  234. }
  235. if ((sts = execl(SH_PATH, "sh", "-c", buf_ptr, NULL)) == -1) {
  236. sprintf(buf_ptr, "%s\n", "Not able to execute shell cmd");
  237. return BCME_ERROR;
  238. }
  239. exit(0);
  240. } /* end of fork */
  241. if (pid < 0) {
  242. perror("\nFork error:");
  243. sprintf(buf_ptr, "%s\n", "Forking async process failed");
  244. return BCME_ERROR;
  245. }
  246. /* Find the PID of the running process (for ex: ping)
  247. * pidof -s options returns latest PID of the command.
  248. */
  249. strtok(buf_ptr, " ");
  250. uname(&name);
  251. /* Checking for mips architecture */
  252. if (strncmp(name.machine, "mips", sizeof(name.machine)) != 0)
  253. sprintf(pid_search_cmd, "pidof -s %s", buf_ptr);
  254. else
  255. sprintf(pid_search_cmd, "pidof %s", buf_ptr);
  256. sleep(1);
  257. /* Execute the command e.g "pidof ping" */
  258. if ((fpt = popen(pid_search_cmd, "r")) == NULL) {
  259. sprintf(buf_ptr, "%s\n", "Can't return PID");
  260. return BCME_ERROR;
  261. }
  262. /* Get the PID and copy the PID in buf_ptr to send to the client */
  263. fgets(pid_resp_buf, sizeof(pid_resp_buf), fpt);
  264. /* Checking for mips architecture */
  265. if (strncmp(name.machine, "mips", sizeof(name.machine)) != 0) {
  266. PID_val = atoi(pid_resp_buf);
  267. }
  268. else {
  269. /* code to extract the correct PID */
  270. pid_token = strtok_r(pid_resp_buf, " ", (char **)next_pid);
  271. if (pid_token != NULL) {
  272. while (pid_token != NULL) {
  273. /* the pid buffer will terminate with a '\n'
  274. * It will affect the string tokenizing logic
  275. * To avoid this we're using the if case
  276. */
  277. if (strncmp(pid_token, "\n", sizeof(pid_token)) == 0)
  278. break;
  279. PID_val = atoi(pid_token);
  280. pid_token = strtok_r(NULL, " ", (char **)next_pid);
  281. }
  282. }
  283. else
  284. PID_val = atoi(pid_token);
  285. }
  286. if (PID_val == 0) {
  287. msg_len = rwl_get_file_size(temp_async_file_name);
  288. remote_shell_async_get_resp(temp_async_file_name, buf_ptr, msg_len);
  289. } else {
  290. g_async_resp[val].PID = PID_val;
  291. /* Update PID value in buffer to send it to client */
  292. sprintf(buf_ptr, "%d", PID_val);
  293. msg_len = strlen(buf_ptr);
  294. }
  295. pclose(fpt);
  296. /* In async case, the PID value will be copied to the input buffer only
  297. * and there is no need of getting the response from the file. So return
  298. * value can be -1.
  299. */
  300. return msg_len;
  301. }
  302. /* Process for 'kill' command.
  303. * Kill command can also be used from the client to get the
  304. * result of asynchronous command and actually kill the mentioned process
  305. */
  306. static int
  307. remote_kill_cmd_exec(char *cmd_buf_ptr)
  308. {
  309. char file_name[MAX_ASYNC_FILE_LENGTH];
  310. int PID_val, val, msg_len;
  311. FILE *fpt;
  312. char *pid_token, next_pid[PID_TOKEN_SIZE][PID_TOKEN_SIZE];
  313. system(cmd_buf_ptr);
  314. /* Parse the PID val from the kill command.
  315. */
  316. pid_token = strtok_r(cmd_buf_ptr, " ", (char **)next_pid);
  317. while (pid_token != NULL) {
  318. /* to extract the PID from the kill command */
  319. if (strncmp(pid_token, "\n", sizeof(pid_token)) == 0)
  320. break;
  321. PID_val = atoi(pid_token);
  322. pid_token = strtok_r(NULL, " ", (char **)next_pid);
  323. }
  324. /* Check for the matching PID from the async structure and
  325. * give the last 256 bytes statistics of the async process
  326. * that was running
  327. */
  328. for (val = 0; val < MAX_SHELL_ASYNC_RESP; ++val) {
  329. if (g_async_resp[val].PID == PID_val) {
  330. /* We found a match here. Hence get the response now from the
  331. * corresponding async response file
  332. */
  333. sprintf(file_name, "%s%s", SHELL_RESP_PATH, g_async_resp[val].file_name);
  334. msg_len = rwl_get_file_size(file_name);
  335. if (msg_len > 0) {
  336. if ((fpt = fopen(file_name, "rb")) == NULL) {
  337. DPRINT_DBG(OUTPUT, "\nShell Cmd:File open error\n");
  338. return BCME_ERROR;
  339. }
  340. if (fseek(fpt, 0, SEEK_SET) < 0) {
  341. fclose(fpt);
  342. return BCME_ERROR;
  343. }
  344. if (fread(cmd_buf_ptr, sizeof(char), MAX_SHELL_CMD_LENTH,
  345. fpt) <= 0) {
  346. sprintf(cmd_buf_ptr, "%s\n", "Shell Resp:Reading error");
  347. fclose(fpt);
  348. return BCME_ERROR;
  349. }
  350. fclose(fpt);
  351. }
  352. else
  353. sprintf(cmd_buf_ptr, "ed %d: No Response\n", PID_val);
  354. remove(g_async_resp[val].file_name);
  355. g_async_resp[val].PID = 0;
  356. break;
  357. }
  358. }
  359. return MAX_SHELL_CMD_LENTH;
  360. }
  361. /* Handle --timeout command line option for linux servers */
  362. int
  363. shell_timeout_cmd(char *cmd_buf_ptr, char *sync_file_name)
  364. {
  365. char *token1, *token2, *nexttoken;
  366. FILE* fp;
  367. int msg_len;
  368. token1 = strtok_r(cmd_buf_ptr, "--timeout ", &nexttoken);
  369. if (token1)
  370. token2 = strtok_r(NULL, token1, &nexttoken);
  371. if (token1 == NULL || atoi(token1) <= 0 || token2 == NULL) {
  372. fp = fopen(sync_file_name, "w+");
  373. fprintf(fp, "Usage: ./wl --<transport> <ip/mac> sh"
  374. "--timeout <timeout value> <shell command>\n");
  375. fprintf(fp, "Eg: ./wl --socket 172.22.65.226 sh --timeout 15 ls\n");
  376. fflush(fp);
  377. msg_len = rwl_get_file_size(sync_file_name);
  378. strcpy(cmd_buf_ptr, sync_file_name);
  379. fclose(fp);
  380. strcpy(globalbuffer, sync_file_name);
  381. printf("Fix timeout problem in socket!!!!!\n");
  382. return msg_len;
  383. }
  384. else
  385. g_shellsync_timeout = atoi(token1);
  386. return BCME_OK;
  387. }
  388. /* Handle synchronous shell commands here */
  389. static int
  390. remote_shell_sync_exec(char *cmd_buf_ptr, void *wl)
  391. {
  392. char *kill_cmd_token;
  393. char sync_file_name[] = TEMPLATE;
  394. int fd, msg_len;
  395. char cmd[(strlen(cmd_buf_ptr) + 1)];
  396. int pid, status, pid_final;
  397. char buf[SHELL_RESP_SIZE], cmd_find_lastpid[PID_SEARCH_CMD_SIZE];
  398. int nbytes = 0;
  399. int child_status;
  400. static int sent_once = 0;
  401. struct utsname name;
  402. FILE *fpt;
  403. /* Default Size of Return Value of the shell command is 2bytes */
  404. kill_cmd_token = strstr(cmd_buf_ptr, "kill");
  405. /* Synchronous Kill command processing is handled separately */
  406. if (kill_cmd_token != NULL) {
  407. msg_len = remote_kill_cmd_exec(cmd_buf_ptr);
  408. remote_tx_response(wl, cmd_buf_ptr, msg_len);
  409. return 0;
  410. }
  411. /* Process synchronous command other than kill command */
  412. if ((fd = mkstemp(sync_file_name)) < 0) {
  413. perror("mkstemp failed");
  414. DPRINT_ERR(ERR, "\n errno:%d\n", errno);
  415. sprintf(cmd_buf_ptr, "%s\n", "mkstemp failed");
  416. return BCME_ERROR;
  417. }
  418. close(fd);
  419. strcpy(cmd, cmd_buf_ptr);
  420. /* Synchronous timeout command processing is handled separately */
  421. if (strstr(cmd_buf_ptr, "--timeout") != NULL) {
  422. if ((msg_len = shell_timeout_cmd (cmd, sync_file_name) > 0)) {
  423. /* Signal end of command output */
  424. g_rem_ptr->msg.len = 0;
  425. g_rem_ptr->msg.cmd = g_return_stat;
  426. remote_tx_response(wl, NULL, 0);
  427. return msg_len;
  428. } else {
  429. /* Parse out --timeout <val> since command is successful
  430. * point buffer to the shell command
  431. */
  432. strcpy(cmd, cmd_buf_ptr);
  433. strtok_r(cmd, " ", &cmd_buf_ptr);
  434. strcpy(cmd, cmd_buf_ptr);
  435. strtok_r(cmd, " ", &cmd_buf_ptr);
  436. }
  437. }
  438. /* Schedule an ALARM in case of timeout value of SHELL_TIMEOUT seconds */
  439. /* Defalut time out only in case of Non socket transport */
  440. alarm(g_shellsync_timeout);
  441. /* registering the relevant signals to handle end of child process,
  442. * the ctrl+c event on the server side and the kill command on the
  443. * server process
  444. */
  445. signal(SIGCHLD, rwl_chld_handler);
  446. signal(SIGINT, handle_ctrlc);
  447. signal(SIGTERM, handle_ctrlc);
  448. /* Set g_sig_chld before forking */
  449. g_sig_chld = 1;
  450. if (strcmp("reboot", cmd_buf_ptr) == 0) { /* reboot command */
  451. memset(buf, 0, sizeof(buf));
  452. strncpy(buf, REBOOT_MSG, sizeof(REBOOT_MSG));
  453. remote_tx_response(wl, buf, 0);
  454. /* Signal end of command output */
  455. g_rem_ptr->msg.len = 0;
  456. g_rem_ptr->msg.cmd = 0;
  457. remote_tx_response(wl, NULL, 0);
  458. sleep(1);
  459. /* Clean up the temp file */
  460. remove(sync_file_name);
  461. }
  462. if ((pid = fork()) == 0) {
  463. close(STDOUT_FILENO);
  464. fd = open(sync_file_name, O_WRONLY|O_SYNC);
  465. /* Redirect stdin to dev/null. This handles un usual commands like
  466. * sh cat from the client side
  467. */
  468. close(STDIN_FILENO);
  469. open("/dev/null", O_RDONLY);
  470. close(STDERR_FILENO);
  471. fcntl(fd, F_DUPFD, STDERR_FILENO);
  472. if ((status = execl(SH_PATH, "sh", "-c", cmd_buf_ptr, NULL)) == -1) {
  473. perror("Exec error");
  474. }
  475. } /* end of fork */
  476. g_shellsync_pid = pid;
  477. /* The g_return_stat is being set for short commands */
  478. waitpid(g_shellsync_pid, &child_status, WNOHANG);
  479. if (WIFEXITED(child_status))
  480. g_return_stat = WEXITSTATUS(child_status);
  481. else
  482. g_return_stat = 1;
  483. /* Read file in the interim from a temp file and send back the results */
  484. fd = open(sync_file_name, O_RDONLY|O_SYNC);
  485. while (1) {
  486. /* read file in the interim and send back the results */
  487. nbytes = read(fd, buf, SHELL_RESP_SIZE);
  488. g_rem_ptr->msg.len = nbytes;
  489. if (nbytes > 0) {
  490. remote_tx_response(wl, buf, 0);
  491. #ifdef RWL_SERIAL
  492. /* usleep introduced for flooding of data over serial port */
  493. usleep(1);
  494. #endif
  495. }
  496. if (get_ctrlc_header(wl) >= 0) {
  497. if (g_rem_ptr->msg.flags == (unsigned)CTRLC_FLAG) {
  498. uname(&name);
  499. /* Checking for mips architecture
  500. * The mips machine responds differently to
  501. * execl command. so the pid is incremented
  502. * to kill the right command.
  503. */
  504. if (strncmp(name.machine, "mips", sizeof(name.machine)) == 0)
  505. pid++;
  506. if (strncmp(name.machine, "armv5tel", sizeof(name.machine)) == 0) {
  507. snprintf(cmd_find_lastpid, sizeof(cmd_find_lastpid),
  508. "ps | awk \'PRINT $1\' | tail -n 1");
  509. if ((fpt = popen(cmd_find_lastpid, "r")) == NULL) {
  510. sprintf(buf, "%s\n", "Can't return PID");
  511. return BCME_ERROR;
  512. }
  513. fgets(cmd_find_lastpid, sizeof(cmd_find_lastpid), fpt);
  514. pid_final = atoi(cmd_find_lastpid);
  515. while (pid <= pid_final) {
  516. kill(pid, SIGKILL);
  517. pid++;
  518. }
  519. pclose(fpt);
  520. }
  521. else {
  522. kill(pid, SIGKILL);
  523. }
  524. break;
  525. }
  526. }
  527. if (get_ctrlc_header(wl) >= 0) {
  528. if (g_rem_ptr->msg.flags == (unsigned)CTRLC_FLAG) {
  529. uname(&name);
  530. /* Checking for mips architecture
  531. * The mips machine responds differently to
  532. * execl command. so the pid is incremented
  533. * to kill the right command.
  534. */
  535. if (strncmp(name.machine, "mips", sizeof(name.machine)) == 0) {
  536. pid++;
  537. kill(pid, SIGKILL);
  538. }
  539. /* Checking for arm architecture
  540. * The multiple commands would not work
  541. * for ctrl+C. So we kill the processes
  542. * spawned after the parent. This method has
  543. * its own limitations but the busybox in pxa
  544. * doesnot have many options to implement it better
  545. */
  546. else {
  547. if (strncmp(name.machine, "armv5tel",
  548. sizeof(name.machine)) == 0) {
  549. /* The command below is used to get the
  550. * PIDs and they are killed
  551. */
  552. snprintf(cmd_find_lastpid,
  553. sizeof(cmd_find_lastpid),
  554. "ps | awk \'PRINT $1\' | tail -n 1");
  555. if ((fpt = popen(cmd_find_lastpid, "r")) == NULL) {
  556. sprintf(buf, "%s\n", "Can't return PID");
  557. return BCME_ERROR;
  558. }
  559. fgets(cmd_find_lastpid, sizeof(cmd_find_lastpid),
  560. fpt);
  561. pid_final = atoi(cmd_find_lastpid);
  562. while (pid <= pid_final) {
  563. kill(pid, SIGKILL);
  564. pid++;
  565. }
  566. pclose(fpt);
  567. }
  568. /* In the case of x86, on receiving ctrl+C
  569. * the child PIDs are obtained by searching
  570. * the parent PID to obtain the PIDs of the
  571. * and kill them
  572. */
  573. else {
  574. while (pid != 0) {
  575. /* The commad below is used to get the
  576. * child PIDs by using their parent PID
  577. */
  578. snprintf(cmd_find_lastpid,
  579. sizeof(cmd_find_lastpid),
  580. "ps al | awk \"{ if (\\$4 == %d)"
  581. " {print \\$3}}\"| head -n 1",
  582. g_shellsync_pid);
  583. if ((fpt = popen(cmd_find_lastpid, "r"))
  584. == NULL) {
  585. sprintf(buf, "%s\n",
  586. "Can't return PID");
  587. return BCME_ERROR;
  588. }
  589. fgets(cmd_find_lastpid,
  590. sizeof(cmd_find_lastpid),
  591. fpt);
  592. pid = atoi(cmd_find_lastpid);
  593. if (pid == 0)
  594. kill(g_shellsync_pid, SIGKILL);
  595. else
  596. kill(pid, SIGKILL);
  597. pclose(fpt);
  598. }
  599. }
  600. }
  601. break;
  602. }
  603. }
  604. if (set_ctrlc == 1) {
  605. g_rem_ptr->msg.len = 0;
  606. g_rem_ptr->msg.cmd = g_return_stat;
  607. remote_tx_response(wl, NULL, g_return_stat);
  608. unlink(sync_file_name);
  609. kill(0, SIGKILL);
  610. }
  611. /* It is possible that the child would have exited
  612. * However we did not get a chance to read the file
  613. * In this case go once again and check the file
  614. */
  615. if (!sent_once && !g_sig_chld) {
  616. sent_once = 1;
  617. continue;
  618. }
  619. if (!(g_sig_chld || nbytes))
  620. break;
  621. }
  622. wait(NULL);
  623. close(fd);
  624. /* Signal end of command output */
  625. g_rem_ptr->msg.len = 0;
  626. g_rem_ptr->msg.cmd = g_return_stat;
  627. remote_tx_response(wl, NULL, g_return_stat);
  628. /* Cancel the time out alarm if any */
  629. alarm(0);
  630. sent_once = 0;
  631. /* Clean up the temp file */
  632. unlink(sync_file_name);
  633. g_shellsync_timeout = DEFAULT_SHELL_TIMEOUT;
  634. signal(SIGINT, SIG_DFL);
  635. signal(SIGTERM, SIG_DFL);
  636. return BCME_OK;
  637. }