slattach.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * Stripped down version of net-tools for busybox.
  4. *
  5. * Author: Ignacio Garcia Perez (iggarpe at gmail dot com)
  6. *
  7. * Licensed under GPLv2 or later, see file LICENSE in this source tree.
  8. *
  9. * There are some differences from the standard net-tools slattach:
  10. *
  11. * - The -l option is not supported.
  12. *
  13. * - The -F options allows disabling of RTS/CTS flow control.
  14. */
  15. //config:config SLATTACH
  16. //config: bool "slattach (6.1 kb)"
  17. //config: default y
  18. //config: select PLATFORM_LINUX
  19. //config: help
  20. //config: slattach is a small utility to attach network interfaces to serial
  21. //config: lines.
  22. //applet:IF_SLATTACH(APPLET(slattach, BB_DIR_SBIN, BB_SUID_DROP))
  23. //kbuild:lib-$(CONFIG_SLATTACH) += slattach.o
  24. //usage:#define slattach_trivial_usage
  25. //usage: "[-cehmLF] [-s SPEED] [-p PROTOCOL] DEVICE"
  26. //usage:#define slattach_full_usage "\n\n"
  27. //usage: "Attach network interface(s) to serial line(s)\n"
  28. //usage: "\n -p PROT Set protocol (slip, cslip, slip6, clisp6 or adaptive)"
  29. //usage: "\n -s SPD Set line speed"
  30. //usage: "\n -e Exit after initializing device"
  31. //usage: "\n -h Exit when the carrier is lost"
  32. //usage: "\n -c PROG Run PROG when the line is hung up"
  33. //usage: "\n -m Do NOT initialize the line in raw 8 bits mode"
  34. //usage: "\n -L Enable 3-wire operation"
  35. //usage: "\n -F Disable RTS/CTS flow control"
  36. #include "libbb.h"
  37. #include "common_bufsiz.h"
  38. #include "libiproute/utils.h" /* invarg_1_to_2() */
  39. struct globals {
  40. int handle;
  41. int saved_disc;
  42. struct termios saved_state;
  43. } FIX_ALIASING;
  44. #define G (*(struct globals*)bb_common_bufsiz1)
  45. #define handle (G.handle )
  46. #define saved_disc (G.saved_disc )
  47. #define saved_state (G.saved_state )
  48. #define INIT_G() do { setup_common_bufsiz(); } while (0)
  49. /*
  50. * Save tty state and line discipline
  51. *
  52. * It is fine here to bail out on errors, since we haven modified anything yet
  53. */
  54. static void save_state(void)
  55. {
  56. /* Save line status */
  57. if (tcgetattr(handle, &saved_state) < 0)
  58. bb_perror_msg_and_die("get state");
  59. /* Save line discipline */
  60. xioctl(handle, TIOCGETD, &saved_disc);
  61. }
  62. static int set_termios_state_or_warn(struct termios *state)
  63. {
  64. int ret;
  65. ret = tcsetattr(handle, TCSANOW, state);
  66. if (ret < 0) {
  67. bb_perror_msg("set state");
  68. return 1; /* used as exitcode */
  69. }
  70. return 0;
  71. }
  72. /*
  73. * Restore state and line discipline for ALL managed ttys
  74. *
  75. * Restoring ALL managed ttys is the only way to have a single
  76. * hangup delay.
  77. *
  78. * Go on after errors: we want to restore as many controlled ttys
  79. * as possible.
  80. */
  81. static void restore_state_and_exit(int exitcode) NORETURN;
  82. static void restore_state_and_exit(int exitcode)
  83. {
  84. struct termios state;
  85. /* Restore line discipline */
  86. if (ioctl_or_warn(handle, TIOCSETD, &saved_disc) < 0) {
  87. exitcode = 1;
  88. }
  89. /* Hangup */
  90. memcpy(&state, &saved_state, sizeof(state));
  91. cfsetispeed(&state, B0);
  92. cfsetospeed(&state, B0);
  93. if (set_termios_state_or_warn(&state))
  94. exitcode = 1;
  95. sleep(1);
  96. /* Restore line status */
  97. if (set_termios_state_or_warn(&saved_state))
  98. exit(EXIT_FAILURE);
  99. if (ENABLE_FEATURE_CLEAN_UP)
  100. close(handle);
  101. exit(exitcode);
  102. }
  103. /*
  104. * Set tty state, line discipline and encapsulation
  105. */
  106. static void set_state(struct termios *state, int encap)
  107. {
  108. int disc;
  109. /* Set line status */
  110. if (set_termios_state_or_warn(state))
  111. goto bad;
  112. /* Set line discliple (N_SLIP always) */
  113. disc = N_SLIP;
  114. if (ioctl_or_warn(handle, TIOCSETD, &disc) < 0) {
  115. goto bad;
  116. }
  117. /* Set encapsulation (SLIP, CSLIP, etc) */
  118. if (ioctl_or_warn(handle, SIOCSIFENCAP, &encap) < 0) {
  119. bad:
  120. restore_state_and_exit(EXIT_FAILURE);
  121. }
  122. }
  123. static void sig_handler(int signo UNUSED_PARAM)
  124. {
  125. restore_state_and_exit(EXIT_SUCCESS);
  126. }
  127. int slattach_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  128. int slattach_main(int argc UNUSED_PARAM, char **argv)
  129. {
  130. /* Line discipline code table */
  131. static const char proto_names[] ALIGN1 =
  132. "slip\0" /* 0 */
  133. "cslip\0" /* 1 */
  134. "slip6\0" /* 2 */
  135. "cslip6\0" /* 3 */
  136. "adaptive\0" /* 8 */
  137. ;
  138. int i, encap, opt;
  139. struct termios state;
  140. const char *proto = "cslip";
  141. const char *extcmd; /* Command to execute after hangup */
  142. const char *baud_str;
  143. int baud_code = -1; /* Line baud rate (system code) */
  144. enum {
  145. OPT_p_proto = 1 << 0,
  146. OPT_s_baud = 1 << 1,
  147. OPT_c_extcmd = 1 << 2,
  148. OPT_e_quit = 1 << 3,
  149. OPT_h_watch = 1 << 4,
  150. OPT_m_nonraw = 1 << 5,
  151. OPT_L_local = 1 << 6,
  152. OPT_F_noflow = 1 << 7
  153. };
  154. INIT_G();
  155. /* Parse command line options */
  156. opt = getopt32(argv, "p:s:c:ehmLF", &proto, &baud_str, &extcmd);
  157. /*argc -= optind;*/
  158. argv += optind;
  159. if (!*argv)
  160. bb_show_usage();
  161. encap = index_in_strings(proto_names, proto);
  162. if (encap < 0)
  163. invarg_1_to_2(proto, "protocol");
  164. if (encap > 3)
  165. encap = 8;
  166. /* We want to know if the baud rate is valid before we start touching the ttys */
  167. if (opt & OPT_s_baud) {
  168. baud_code = tty_value_to_baud(xatoi(baud_str));
  169. if (baud_code < 0)
  170. invarg_1_to_2(baud_str, "baud rate");
  171. }
  172. /* Trap signals in order to restore tty states upon exit */
  173. if (!(opt & OPT_e_quit)) {
  174. bb_signals(0
  175. + (1 << SIGHUP)
  176. + (1 << SIGINT)
  177. + (1 << SIGQUIT)
  178. + (1 << SIGTERM)
  179. , sig_handler);
  180. }
  181. /* Open tty */
  182. handle = open(*argv, O_RDWR | O_NDELAY);
  183. if (handle < 0) {
  184. char *buf = concat_path_file("/dev", *argv);
  185. handle = xopen(buf, O_RDWR | O_NDELAY);
  186. /* maybe if (ENABLE_FEATURE_CLEAN_UP) ?? */
  187. free(buf);
  188. }
  189. /* Save current tty state */
  190. save_state();
  191. /* Configure tty */
  192. memcpy(&state, &saved_state, sizeof(state));
  193. if (!(opt & OPT_m_nonraw)) { /* raw not suppressed */
  194. memset(&state.c_cc, 0, sizeof(state.c_cc));
  195. state.c_cc[VMIN] = 1;
  196. state.c_iflag = IGNBRK | IGNPAR;
  197. state.c_oflag = 0;
  198. state.c_lflag = 0;
  199. state.c_cflag = CS8 | HUPCL | CREAD
  200. | ((opt & OPT_L_local) ? CLOCAL : 0)
  201. | ((opt & OPT_F_noflow) ? 0 : CRTSCTS);
  202. cfsetispeed(&state, cfgetispeed(&saved_state));
  203. cfsetospeed(&state, cfgetospeed(&saved_state));
  204. }
  205. if (opt & OPT_s_baud) {
  206. cfsetispeed(&state, baud_code);
  207. cfsetospeed(&state, baud_code);
  208. }
  209. set_state(&state, encap);
  210. /* Exit now if option -e was passed */
  211. if (opt & OPT_e_quit)
  212. return 0;
  213. /* If we're not requested to watch, just keep descriptor open
  214. * until we are killed */
  215. if (!(opt & OPT_h_watch))
  216. while (1)
  217. sleep(24*60*60);
  218. /* Watch line for hangup */
  219. while (1) {
  220. if (ioctl(handle, TIOCMGET, &i) < 0 || !(i & TIOCM_CAR))
  221. goto no_carrier;
  222. sleep(15);
  223. }
  224. no_carrier:
  225. /* Execute command on hangup */
  226. if (opt & OPT_c_extcmd)
  227. system(extcmd);
  228. /* Restore states and exit */
  229. restore_state_and_exit(EXIT_SUCCESS);
  230. }