stty.c 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * stty -- change and print terminal line settings
  4. * Copyright (C) 1990-1999 Free Software Foundation, Inc.
  5. *
  6. * Licensed under GPLv2 or later, see file LICENSE in this source tree.
  7. */
  8. /* David MacKenzie <djm@gnu.ai.mit.edu>
  9. *
  10. * Special for busybox ported by Vladimir Oleynik <dzo@simtreas.ru> 2001
  11. */
  12. //config:config STTY
  13. //config: bool "stty (8.9 kb)"
  14. //config: default y
  15. //config: help
  16. //config: stty is used to change and print terminal line settings.
  17. //applet:IF_STTY(APPLET_NOEXEC(stty, stty, BB_DIR_BIN, BB_SUID_DROP, stty))
  18. //kbuild:lib-$(CONFIG_STTY) += stty.o
  19. //usage:#define stty_trivial_usage
  20. //usage: "[-a|g] [-F DEVICE] [SETTING]..."
  21. //usage:#define stty_full_usage "\n\n"
  22. //usage: "Without arguments, prints baud rate, line discipline,\n"
  23. //usage: "and deviations from stty sane\n"
  24. //usage: "\n -F DEVICE Open device instead of stdin"
  25. //usage: "\n -a Print all current settings in human-readable form"
  26. //usage: "\n -g Print in stty-readable form"
  27. //usage: "\n [SETTING] See manpage"
  28. /* If no args are given, write to stdout the baud rate and settings that
  29. * have been changed from their defaults. Mode reading and changes
  30. * are done on the specified device, or stdin if none was specified.
  31. */
  32. #include "libbb.h"
  33. #include "common_bufsiz.h"
  34. #ifndef _POSIX_VDISABLE
  35. # define _POSIX_VDISABLE ((unsigned char) 0)
  36. #endif
  37. #define Control(c) ((c) & 0x1f)
  38. /* Canonical values for control characters */
  39. #ifndef CINTR
  40. # define CINTR Control('c')
  41. #endif
  42. #ifndef CQUIT
  43. # define CQUIT 28
  44. #endif
  45. #ifndef CERASE
  46. # define CERASE 127
  47. #endif
  48. #ifndef CKILL
  49. # define CKILL Control('u')
  50. #endif
  51. #ifndef CEOF
  52. # define CEOF Control('d')
  53. #endif
  54. #ifndef CEOL
  55. # define CEOL _POSIX_VDISABLE
  56. #endif
  57. #ifndef CSTART
  58. # define CSTART Control('q')
  59. #endif
  60. #ifndef CSTOP
  61. # define CSTOP Control('s')
  62. #endif
  63. #ifndef CSUSP
  64. # define CSUSP Control('z')
  65. #endif
  66. #if defined(VEOL2) && !defined(CEOL2)
  67. # define CEOL2 _POSIX_VDISABLE
  68. #endif
  69. /* glibc-2.12.1 uses only VSWTC name */
  70. #if defined(VSWTC) && !defined(VSWTCH)
  71. # define VSWTCH VSWTC
  72. #endif
  73. /* ISC renamed swtch to susp for termios, but we'll accept either name */
  74. #if defined(VSUSP) && !defined(VSWTCH)
  75. # define VSWTCH VSUSP
  76. # define CSWTCH CSUSP
  77. #endif
  78. #if defined(VSWTCH) && !defined(CSWTCH)
  79. # define CSWTCH _POSIX_VDISABLE
  80. #endif
  81. /* SunOS 5.3 loses (^Z doesn't work) if 'swtch' is the same as 'susp'.
  82. So the default is to disable 'swtch.' */
  83. #if defined(__sparc__) && defined(__svr4__)
  84. # undef CSWTCH
  85. # define CSWTCH _POSIX_VDISABLE
  86. #endif
  87. #if defined(VWERSE) && !defined(VWERASE) /* AIX-3.2.5 */
  88. # define VWERASE VWERSE
  89. #endif
  90. #if defined(VDSUSP) && !defined(CDSUSP)
  91. # define CDSUSP Control('y')
  92. #endif
  93. #if !defined(VREPRINT) && defined(VRPRNT) /* Irix 4.0.5 */
  94. # define VREPRINT VRPRNT
  95. #endif
  96. #if defined(VREPRINT) && !defined(CRPRNT)
  97. # define CRPRNT Control('r')
  98. #endif
  99. #if defined(VWERASE) && !defined(CWERASE)
  100. # define CWERASE Control('w')
  101. #endif
  102. #if defined(VLNEXT) && !defined(CLNEXT)
  103. # define CLNEXT Control('v')
  104. #endif
  105. #if defined(VDISCARD) && !defined(VFLUSHO)
  106. # define VFLUSHO VDISCARD
  107. #endif
  108. #if defined(VFLUSH) && !defined(VFLUSHO) /* Ultrix 4.2 */
  109. # define VFLUSHO VFLUSH
  110. #endif
  111. #if defined(CTLECH) && !defined(ECHOCTL) /* Ultrix 4.3 */
  112. # define ECHOCTL CTLECH
  113. #endif
  114. #if defined(TCTLECH) && !defined(ECHOCTL) /* Ultrix 4.2 */
  115. # define ECHOCTL TCTLECH
  116. #endif
  117. #if defined(CRTKIL) && !defined(ECHOKE) /* Ultrix 4.2 and 4.3 */
  118. # define ECHOKE CRTKIL
  119. #endif
  120. #if defined(VFLUSHO) && !defined(CFLUSHO)
  121. # define CFLUSHO Control('o')
  122. #endif
  123. #if defined(VSTATUS) && !defined(CSTATUS)
  124. # define CSTATUS Control('t')
  125. #endif
  126. /* Save us from #ifdef forest plague */
  127. #ifndef BSDLY
  128. # define BSDLY 0
  129. #endif
  130. #ifndef CIBAUD
  131. # define CIBAUD 0
  132. #endif
  133. #ifndef CRDLY
  134. # define CRDLY 0
  135. #endif
  136. #ifndef CMSPAR
  137. # define CMSPAR 0
  138. #endif
  139. #ifndef CRTSCTS
  140. # define CRTSCTS 0
  141. #endif
  142. #ifndef ECHOCTL
  143. # define ECHOCTL 0
  144. #endif
  145. #ifndef ECHOKE
  146. # define ECHOKE 0
  147. #endif
  148. #ifndef ECHOPRT
  149. # define ECHOPRT 0
  150. #endif
  151. #ifndef FFDLY
  152. # define FFDLY 0
  153. #endif
  154. #ifndef IEXTEN
  155. # define IEXTEN 0
  156. #endif
  157. #ifndef IMAXBEL
  158. # define IMAXBEL 0
  159. #endif
  160. #ifndef IUCLC
  161. # define IUCLC 0
  162. #endif
  163. #ifndef IXANY
  164. # define IXANY 0
  165. #endif
  166. #ifndef NLDLY
  167. # define NLDLY 0
  168. #endif
  169. #ifndef OCRNL
  170. # define OCRNL 0
  171. #endif
  172. #ifndef OFDEL
  173. # define OFDEL 0
  174. #endif
  175. #ifndef OFILL
  176. # define OFILL 0
  177. #endif
  178. #ifndef OLCUC
  179. # define OLCUC 0
  180. #endif
  181. #ifndef ONLCR
  182. # define ONLCR 0
  183. #endif
  184. #ifndef ONLRET
  185. # define ONLRET 0
  186. #endif
  187. #ifndef ONOCR
  188. # define ONOCR 0
  189. #endif
  190. #ifndef OXTABS
  191. # define OXTABS 0
  192. #endif
  193. #ifndef TABDLY
  194. # define TABDLY 0
  195. #endif
  196. #ifndef TAB1
  197. # define TAB1 0
  198. #endif
  199. #ifndef TAB2
  200. # define TAB2 0
  201. #endif
  202. #ifndef TOSTOP
  203. # define TOSTOP 0
  204. #endif
  205. #ifndef VDSUSP
  206. # define VDSUSP 0
  207. #endif
  208. #ifndef VEOL2
  209. # define VEOL2 0
  210. #endif
  211. #ifndef VFLUSHO
  212. # define VFLUSHO 0
  213. #endif
  214. #ifndef VLNEXT
  215. # define VLNEXT 0
  216. #endif
  217. #ifndef VREPRINT
  218. # define VREPRINT 0
  219. #endif
  220. #ifndef VSTATUS
  221. # define VSTATUS 0
  222. #endif
  223. #ifndef VSWTCH
  224. # define VSWTCH 0
  225. #endif
  226. #ifndef VTDLY
  227. # define VTDLY 0
  228. #endif
  229. #ifndef VWERASE
  230. # define VWERASE 0
  231. #endif
  232. #ifndef XCASE
  233. # define XCASE 0
  234. #endif
  235. #ifndef IUTF8
  236. # define IUTF8 0
  237. #endif
  238. /* Which speeds to set */
  239. enum speed_setting {
  240. input_speed, output_speed, both_speeds
  241. };
  242. /* Which member(s) of 'struct termios' a mode uses */
  243. enum {
  244. control, input, output, local, combination
  245. };
  246. static tcflag_t *get_ptr_to_tcflag(unsigned type, const struct termios *mode)
  247. {
  248. static const uint8_t tcflag_offsets[] ALIGN1 = {
  249. offsetof(struct termios, c_cflag), /* control */
  250. offsetof(struct termios, c_iflag), /* input */
  251. offsetof(struct termios, c_oflag), /* output */
  252. offsetof(struct termios, c_lflag) /* local */
  253. };
  254. if (type <= local) {
  255. return (tcflag_t*) (((char*)mode) + tcflag_offsets[type]);
  256. }
  257. return NULL;
  258. }
  259. /* Flags for 'struct mode_info' */
  260. #define SANE_SET 1 /* Set in 'sane' mode */
  261. #define SANE_UNSET 2 /* Unset in 'sane' mode */
  262. #define REV 4 /* Can be turned off by prepending '-' */
  263. #define OMIT 8 /* Don't display value */
  264. /* Each mode.
  265. * This structure should be kept as small as humanly possible.
  266. */
  267. struct mode_info {
  268. const uint8_t type; /* Which structure element to change */
  269. const uint8_t flags; /* Setting and display options */
  270. /* only these values are ever used, so... */
  271. #if (CSIZE | NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY) < 0x100
  272. const uint8_t mask;
  273. #elif (CSIZE | NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY) < 0x10000
  274. const uint16_t mask;
  275. #else
  276. const tcflag_t mask; /* Other bits to turn off for this mode */
  277. #endif
  278. /* was using short here, but ppc32 was unhappy */
  279. const tcflag_t bits; /* Bits to set for this mode */
  280. };
  281. enum {
  282. /* Must match mode_name[] and mode_info[] order! */
  283. IDX_evenp = 0,
  284. IDX_parity,
  285. IDX_oddp,
  286. IDX_nl,
  287. IDX_ek,
  288. IDX_sane,
  289. IDX_cooked,
  290. IDX_raw,
  291. IDX_pass8,
  292. IDX_litout,
  293. IDX_cbreak,
  294. IDX_crt,
  295. IDX_dec,
  296. #if IXANY
  297. IDX_decctlq,
  298. #endif
  299. #if TABDLY || OXTABS
  300. IDX_tabs,
  301. #endif
  302. #if XCASE && IUCLC && OLCUC
  303. IDX_lcase,
  304. IDX_LCASE,
  305. #endif
  306. };
  307. #define MI_ENTRY(N,T,F,B,M) N "\0"
  308. /* Mode names given on command line */
  309. static const char mode_name[] ALIGN1 =
  310. MI_ENTRY("evenp", combination, REV | OMIT, 0, 0 )
  311. MI_ENTRY("parity", combination, REV | OMIT, 0, 0 )
  312. MI_ENTRY("oddp", combination, REV | OMIT, 0, 0 )
  313. MI_ENTRY("nl", combination, REV | OMIT, 0, 0 )
  314. MI_ENTRY("ek", combination, OMIT, 0, 0 )
  315. MI_ENTRY("sane", combination, OMIT, 0, 0 )
  316. MI_ENTRY("cooked", combination, REV | OMIT, 0, 0 )
  317. MI_ENTRY("raw", combination, REV | OMIT, 0, 0 )
  318. MI_ENTRY("pass8", combination, REV | OMIT, 0, 0 )
  319. MI_ENTRY("litout", combination, REV | OMIT, 0, 0 )
  320. MI_ENTRY("cbreak", combination, REV | OMIT, 0, 0 )
  321. MI_ENTRY("crt", combination, OMIT, 0, 0 )
  322. MI_ENTRY("dec", combination, OMIT, 0, 0 )
  323. #if IXANY
  324. MI_ENTRY("decctlq", combination, REV | OMIT, 0, 0 )
  325. #endif
  326. #if TABDLY || OXTABS
  327. MI_ENTRY("tabs", combination, REV | OMIT, 0, 0 )
  328. #endif
  329. #if XCASE && IUCLC && OLCUC
  330. MI_ENTRY("lcase", combination, REV | OMIT, 0, 0 )
  331. MI_ENTRY("LCASE", combination, REV | OMIT, 0, 0 )
  332. #endif
  333. MI_ENTRY("parenb", control, REV, PARENB, 0 )
  334. MI_ENTRY("parodd", control, REV, PARODD, 0 )
  335. #if CMSPAR
  336. MI_ENTRY("cmspar", control, REV, CMSPAR, 0 )
  337. #endif
  338. MI_ENTRY("cs5", control, 0, CS5, CSIZE)
  339. MI_ENTRY("cs6", control, 0, CS6, CSIZE)
  340. MI_ENTRY("cs7", control, 0, CS7, CSIZE)
  341. MI_ENTRY("cs8", control, 0, CS8, CSIZE)
  342. MI_ENTRY("hupcl", control, REV, HUPCL, 0 )
  343. MI_ENTRY("hup", control, REV | OMIT, HUPCL, 0 )
  344. MI_ENTRY("cstopb", control, REV, CSTOPB, 0 )
  345. MI_ENTRY("cread", control, SANE_SET | REV, CREAD, 0 )
  346. MI_ENTRY("clocal", control, REV, CLOCAL, 0 )
  347. #if CRTSCTS
  348. MI_ENTRY("crtscts", control, REV, CRTSCTS, 0 )
  349. #endif
  350. MI_ENTRY("ignbrk", input, SANE_UNSET | REV, IGNBRK, 0 )
  351. MI_ENTRY("brkint", input, SANE_SET | REV, BRKINT, 0 )
  352. MI_ENTRY("ignpar", input, REV, IGNPAR, 0 )
  353. MI_ENTRY("parmrk", input, REV, PARMRK, 0 )
  354. MI_ENTRY("inpck", input, REV, INPCK, 0 )
  355. MI_ENTRY("istrip", input, REV, ISTRIP, 0 )
  356. MI_ENTRY("inlcr", input, SANE_UNSET | REV, INLCR, 0 )
  357. MI_ENTRY("igncr", input, SANE_UNSET | REV, IGNCR, 0 )
  358. MI_ENTRY("icrnl", input, SANE_SET | REV, ICRNL, 0 )
  359. MI_ENTRY("ixon", input, REV, IXON, 0 )
  360. MI_ENTRY("ixoff", input, SANE_UNSET | REV, IXOFF, 0 )
  361. MI_ENTRY("tandem", input, OMIT | REV, IXOFF, 0 )
  362. #if IUCLC
  363. MI_ENTRY("iuclc", input, SANE_UNSET | REV, IUCLC, 0 )
  364. #endif
  365. #if IXANY
  366. MI_ENTRY("ixany", input, SANE_UNSET | REV, IXANY, 0 )
  367. #endif
  368. #if IMAXBEL
  369. MI_ENTRY("imaxbel", input, SANE_SET | REV, IMAXBEL, 0 )
  370. #endif
  371. #if IUTF8
  372. MI_ENTRY("iutf8", input, SANE_UNSET | REV, IUTF8, 0 )
  373. #endif
  374. MI_ENTRY("opost", output, SANE_SET | REV, OPOST, 0 )
  375. #if OLCUC
  376. MI_ENTRY("olcuc", output, SANE_UNSET | REV, OLCUC, 0 )
  377. #endif
  378. #if OCRNL
  379. MI_ENTRY("ocrnl", output, SANE_UNSET | REV, OCRNL, 0 )
  380. #endif
  381. #if ONLCR
  382. MI_ENTRY("onlcr", output, SANE_SET | REV, ONLCR, 0 )
  383. #endif
  384. #if ONOCR
  385. MI_ENTRY("onocr", output, SANE_UNSET | REV, ONOCR, 0 )
  386. #endif
  387. #if ONLRET
  388. MI_ENTRY("onlret", output, SANE_UNSET | REV, ONLRET, 0 )
  389. #endif
  390. #if OFILL
  391. MI_ENTRY("ofill", output, SANE_UNSET | REV, OFILL, 0 )
  392. #endif
  393. #if OFDEL
  394. MI_ENTRY("ofdel", output, SANE_UNSET | REV, OFDEL, 0 )
  395. #endif
  396. #if NLDLY
  397. MI_ENTRY("nl1", output, SANE_UNSET, NL1, NLDLY)
  398. MI_ENTRY("nl0", output, SANE_SET, NL0, NLDLY)
  399. #endif
  400. #if CRDLY
  401. MI_ENTRY("cr3", output, SANE_UNSET, CR3, CRDLY)
  402. MI_ENTRY("cr2", output, SANE_UNSET, CR2, CRDLY)
  403. MI_ENTRY("cr1", output, SANE_UNSET, CR1, CRDLY)
  404. MI_ENTRY("cr0", output, SANE_SET, CR0, CRDLY)
  405. #endif
  406. #if TABDLY
  407. MI_ENTRY("tab3", output, SANE_UNSET, TAB3, TABDLY)
  408. # if TAB2
  409. MI_ENTRY("tab2", output, SANE_UNSET, TAB2, TABDLY)
  410. # endif
  411. # if TAB1
  412. MI_ENTRY("tab1", output, SANE_UNSET, TAB1, TABDLY)
  413. # endif
  414. MI_ENTRY("tab0", output, SANE_SET, TAB0, TABDLY)
  415. #else
  416. # if OXTABS
  417. MI_ENTRY("tab3", output, SANE_UNSET, OXTABS, 0 )
  418. # endif
  419. #endif
  420. #if BSDLY
  421. MI_ENTRY("bs1", output, SANE_UNSET, BS1, BSDLY)
  422. MI_ENTRY("bs0", output, SANE_SET, BS0, BSDLY)
  423. #endif
  424. #if VTDLY
  425. MI_ENTRY("vt1", output, SANE_UNSET, VT1, VTDLY)
  426. MI_ENTRY("vt0", output, SANE_SET, VT0, VTDLY)
  427. #endif
  428. #if FFDLY
  429. MI_ENTRY("ff1", output, SANE_UNSET, FF1, FFDLY)
  430. MI_ENTRY("ff0", output, SANE_SET, FF0, FFDLY)
  431. #endif
  432. MI_ENTRY("isig", local, SANE_SET | REV, ISIG, 0 )
  433. MI_ENTRY("icanon", local, SANE_SET | REV, ICANON, 0 )
  434. #if IEXTEN
  435. MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 )
  436. #endif
  437. MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 )
  438. MI_ENTRY("echoe", local, SANE_SET | REV, ECHOE, 0 )
  439. MI_ENTRY("crterase", local, OMIT | REV, ECHOE, 0 )
  440. MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 )
  441. MI_ENTRY("echonl", local, SANE_UNSET | REV, ECHONL, 0 )
  442. MI_ENTRY("noflsh", local, SANE_UNSET | REV, NOFLSH, 0 )
  443. #if XCASE
  444. MI_ENTRY("xcase", local, SANE_UNSET | REV, XCASE, 0 )
  445. #endif
  446. #if TOSTOP
  447. MI_ENTRY("tostop", local, SANE_UNSET | REV, TOSTOP, 0 )
  448. #endif
  449. #if ECHOPRT
  450. MI_ENTRY("echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 )
  451. MI_ENTRY("prterase", local, OMIT | REV, ECHOPRT, 0 )
  452. #endif
  453. #if ECHOCTL
  454. MI_ENTRY("echoctl", local, SANE_SET | REV, ECHOCTL, 0 )
  455. MI_ENTRY("ctlecho", local, OMIT | REV, ECHOCTL, 0 )
  456. #endif
  457. #if ECHOKE
  458. MI_ENTRY("echoke", local, SANE_SET | REV, ECHOKE, 0 )
  459. MI_ENTRY("crtkill", local, OMIT | REV, ECHOKE, 0 )
  460. #endif
  461. MI_ENTRY("flusho", local, SANE_UNSET | REV, FLUSHO, 0 )
  462. #ifdef EXTPROC
  463. MI_ENTRY("extproc", local, SANE_UNSET | REV, EXTPROC, 0 )
  464. #endif
  465. ;
  466. #undef MI_ENTRY
  467. #define MI_ENTRY(N,T,F,B,M) { T, F, M, B },
  468. static const struct mode_info mode_info[] = {
  469. /* This should be verbatim cut-n-paste copy of the above MI_ENTRYs */
  470. MI_ENTRY("evenp", combination, REV | OMIT, 0, 0 )
  471. MI_ENTRY("parity", combination, REV | OMIT, 0, 0 )
  472. MI_ENTRY("oddp", combination, REV | OMIT, 0, 0 )
  473. MI_ENTRY("nl", combination, REV | OMIT, 0, 0 )
  474. MI_ENTRY("ek", combination, OMIT, 0, 0 )
  475. MI_ENTRY("sane", combination, OMIT, 0, 0 )
  476. MI_ENTRY("cooked", combination, REV | OMIT, 0, 0 )
  477. MI_ENTRY("raw", combination, REV | OMIT, 0, 0 )
  478. MI_ENTRY("pass8", combination, REV | OMIT, 0, 0 )
  479. MI_ENTRY("litout", combination, REV | OMIT, 0, 0 )
  480. MI_ENTRY("cbreak", combination, REV | OMIT, 0, 0 )
  481. MI_ENTRY("crt", combination, OMIT, 0, 0 )
  482. MI_ENTRY("dec", combination, OMIT, 0, 0 )
  483. #if IXANY
  484. MI_ENTRY("decctlq", combination, REV | OMIT, 0, 0 )
  485. #endif
  486. #if TABDLY || OXTABS
  487. MI_ENTRY("tabs", combination, REV | OMIT, 0, 0 )
  488. #endif
  489. #if XCASE && IUCLC && OLCUC
  490. MI_ENTRY("lcase", combination, REV | OMIT, 0, 0 )
  491. MI_ENTRY("LCASE", combination, REV | OMIT, 0, 0 )
  492. #endif
  493. MI_ENTRY("parenb", control, REV, PARENB, 0 )
  494. MI_ENTRY("parodd", control, REV, PARODD, 0 )
  495. #if CMSPAR
  496. MI_ENTRY("cmspar", control, REV, CMSPAR, 0 )
  497. #endif
  498. MI_ENTRY("cs5", control, 0, CS5, CSIZE)
  499. MI_ENTRY("cs6", control, 0, CS6, CSIZE)
  500. MI_ENTRY("cs7", control, 0, CS7, CSIZE)
  501. MI_ENTRY("cs8", control, 0, CS8, CSIZE)
  502. MI_ENTRY("hupcl", control, REV, HUPCL, 0 )
  503. MI_ENTRY("hup", control, REV | OMIT, HUPCL, 0 )
  504. MI_ENTRY("cstopb", control, REV, CSTOPB, 0 )
  505. MI_ENTRY("cread", control, SANE_SET | REV, CREAD, 0 )
  506. MI_ENTRY("clocal", control, REV, CLOCAL, 0 )
  507. #if CRTSCTS
  508. MI_ENTRY("crtscts", control, REV, CRTSCTS, 0 )
  509. #endif
  510. MI_ENTRY("ignbrk", input, SANE_UNSET | REV, IGNBRK, 0 )
  511. MI_ENTRY("brkint", input, SANE_SET | REV, BRKINT, 0 )
  512. MI_ENTRY("ignpar", input, REV, IGNPAR, 0 )
  513. MI_ENTRY("parmrk", input, REV, PARMRK, 0 )
  514. MI_ENTRY("inpck", input, REV, INPCK, 0 )
  515. MI_ENTRY("istrip", input, REV, ISTRIP, 0 )
  516. MI_ENTRY("inlcr", input, SANE_UNSET | REV, INLCR, 0 )
  517. MI_ENTRY("igncr", input, SANE_UNSET | REV, IGNCR, 0 )
  518. MI_ENTRY("icrnl", input, SANE_SET | REV, ICRNL, 0 )
  519. MI_ENTRY("ixon", input, REV, IXON, 0 )
  520. MI_ENTRY("ixoff", input, SANE_UNSET | REV, IXOFF, 0 )
  521. MI_ENTRY("tandem", input, OMIT | REV, IXOFF, 0 )
  522. #if IUCLC
  523. MI_ENTRY("iuclc", input, SANE_UNSET | REV, IUCLC, 0 )
  524. #endif
  525. #if IXANY
  526. MI_ENTRY("ixany", input, SANE_UNSET | REV, IXANY, 0 )
  527. #endif
  528. #if IMAXBEL
  529. MI_ENTRY("imaxbel", input, SANE_SET | REV, IMAXBEL, 0 )
  530. #endif
  531. #if IUTF8
  532. MI_ENTRY("iutf8", input, SANE_UNSET | REV, IUTF8, 0 )
  533. #endif
  534. MI_ENTRY("opost", output, SANE_SET | REV, OPOST, 0 )
  535. #if OLCUC
  536. MI_ENTRY("olcuc", output, SANE_UNSET | REV, OLCUC, 0 )
  537. #endif
  538. #if OCRNL
  539. MI_ENTRY("ocrnl", output, SANE_UNSET | REV, OCRNL, 0 )
  540. #endif
  541. #if ONLCR
  542. MI_ENTRY("onlcr", output, SANE_SET | REV, ONLCR, 0 )
  543. #endif
  544. #if ONOCR
  545. MI_ENTRY("onocr", output, SANE_UNSET | REV, ONOCR, 0 )
  546. #endif
  547. #if ONLRET
  548. MI_ENTRY("onlret", output, SANE_UNSET | REV, ONLRET, 0 )
  549. #endif
  550. #if OFILL
  551. MI_ENTRY("ofill", output, SANE_UNSET | REV, OFILL, 0 )
  552. #endif
  553. #if OFDEL
  554. MI_ENTRY("ofdel", output, SANE_UNSET | REV, OFDEL, 0 )
  555. #endif
  556. #if NLDLY
  557. MI_ENTRY("nl1", output, SANE_UNSET, NL1, NLDLY)
  558. MI_ENTRY("nl0", output, SANE_SET, NL0, NLDLY)
  559. #endif
  560. #if CRDLY
  561. MI_ENTRY("cr3", output, SANE_UNSET, CR3, CRDLY)
  562. MI_ENTRY("cr2", output, SANE_UNSET, CR2, CRDLY)
  563. MI_ENTRY("cr1", output, SANE_UNSET, CR1, CRDLY)
  564. MI_ENTRY("cr0", output, SANE_SET, CR0, CRDLY)
  565. #endif
  566. #if TABDLY
  567. MI_ENTRY("tab3", output, SANE_UNSET, TAB3, TABDLY)
  568. # if TAB2
  569. MI_ENTRY("tab2", output, SANE_UNSET, TAB2, TABDLY)
  570. # endif
  571. # if TAB1
  572. MI_ENTRY("tab1", output, SANE_UNSET, TAB1, TABDLY)
  573. # endif
  574. MI_ENTRY("tab0", output, SANE_SET, TAB0, TABDLY)
  575. #else
  576. # if OXTABS
  577. MI_ENTRY("tab3", output, SANE_UNSET, OXTABS, 0 )
  578. # endif
  579. #endif
  580. #if BSDLY
  581. MI_ENTRY("bs1", output, SANE_UNSET, BS1, BSDLY)
  582. MI_ENTRY("bs0", output, SANE_SET, BS0, BSDLY)
  583. #endif
  584. #if VTDLY
  585. MI_ENTRY("vt1", output, SANE_UNSET, VT1, VTDLY)
  586. MI_ENTRY("vt0", output, SANE_SET, VT0, VTDLY)
  587. #endif
  588. #if FFDLY
  589. MI_ENTRY("ff1", output, SANE_UNSET, FF1, FFDLY)
  590. MI_ENTRY("ff0", output, SANE_SET, FF0, FFDLY)
  591. #endif
  592. MI_ENTRY("isig", local, SANE_SET | REV, ISIG, 0 )
  593. MI_ENTRY("icanon", local, SANE_SET | REV, ICANON, 0 )
  594. #if IEXTEN
  595. MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 )
  596. #endif
  597. MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 )
  598. MI_ENTRY("echoe", local, SANE_SET | REV, ECHOE, 0 )
  599. MI_ENTRY("crterase", local, OMIT | REV, ECHOE, 0 )
  600. MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 )
  601. MI_ENTRY("echonl", local, SANE_UNSET | REV, ECHONL, 0 )
  602. MI_ENTRY("noflsh", local, SANE_UNSET | REV, NOFLSH, 0 )
  603. #if XCASE
  604. MI_ENTRY("xcase", local, SANE_UNSET | REV, XCASE, 0 )
  605. #endif
  606. #if TOSTOP
  607. MI_ENTRY("tostop", local, SANE_UNSET | REV, TOSTOP, 0 )
  608. #endif
  609. #if ECHOPRT
  610. MI_ENTRY("echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 )
  611. MI_ENTRY("prterase", local, OMIT | REV, ECHOPRT, 0 )
  612. #endif
  613. #if ECHOCTL
  614. MI_ENTRY("echoctl", local, SANE_SET | REV, ECHOCTL, 0 )
  615. MI_ENTRY("ctlecho", local, OMIT | REV, ECHOCTL, 0 )
  616. #endif
  617. #if ECHOKE
  618. MI_ENTRY("echoke", local, SANE_SET | REV, ECHOKE, 0 )
  619. MI_ENTRY("crtkill", local, OMIT | REV, ECHOKE, 0 )
  620. #endif
  621. MI_ENTRY("flusho", local, SANE_UNSET | REV, FLUSHO, 0 )
  622. #ifdef EXTPROC
  623. MI_ENTRY("extproc", local, SANE_UNSET | REV, EXTPROC, 0 )
  624. #endif
  625. };
  626. enum {
  627. NUM_mode_info = ARRAY_SIZE(mode_info)
  628. };
  629. /* Control characters */
  630. struct control_info {
  631. const uint8_t saneval; /* Value to set for 'stty sane' */
  632. const uint8_t offset; /* Offset in c_cc */
  633. };
  634. enum {
  635. /* Must match control_name[] and control_info[] order! */
  636. CIDX_intr = 0,
  637. CIDX_quit,
  638. CIDX_erase,
  639. CIDX_kill,
  640. CIDX_eof,
  641. CIDX_eol,
  642. #if VEOL2
  643. CIDX_eol2,
  644. #endif
  645. #if VSWTCH
  646. CIDX_swtch,
  647. #endif
  648. CIDX_start,
  649. CIDX_stop,
  650. CIDX_susp,
  651. #if VDSUSP
  652. CIDX_dsusp,
  653. #endif
  654. #if VREPRINT
  655. CIDX_rprnt,
  656. #endif
  657. #if VWERASE
  658. CIDX_werase,
  659. #endif
  660. #if VLNEXT
  661. CIDX_lnext,
  662. #endif
  663. #if VFLUSHO
  664. CIDX_flush,
  665. #endif
  666. #if VSTATUS
  667. CIDX_status,
  668. #endif
  669. CIDX_min,
  670. CIDX_time,
  671. };
  672. #define CI_ENTRY(n,s,o) n "\0"
  673. /* Name given on command line */
  674. static const char control_name[] ALIGN1 =
  675. CI_ENTRY("intr", CINTR, VINTR )
  676. CI_ENTRY("quit", CQUIT, VQUIT )
  677. CI_ENTRY("erase", CERASE, VERASE )
  678. CI_ENTRY("kill", CKILL, VKILL )
  679. CI_ENTRY("eof", CEOF, VEOF )
  680. CI_ENTRY("eol", CEOL, VEOL )
  681. #if VEOL2
  682. CI_ENTRY("eol2", CEOL2, VEOL2 )
  683. #endif
  684. #if VSWTCH
  685. CI_ENTRY("swtch", CSWTCH, VSWTCH )
  686. #endif
  687. CI_ENTRY("start", CSTART, VSTART )
  688. CI_ENTRY("stop", CSTOP, VSTOP )
  689. CI_ENTRY("susp", CSUSP, VSUSP )
  690. #if VDSUSP
  691. CI_ENTRY("dsusp", CDSUSP, VDSUSP )
  692. #endif
  693. #if VREPRINT
  694. CI_ENTRY("rprnt", CRPRNT, VREPRINT)
  695. #endif
  696. #if VWERASE
  697. CI_ENTRY("werase", CWERASE, VWERASE )
  698. #endif
  699. #if VLNEXT
  700. CI_ENTRY("lnext", CLNEXT, VLNEXT )
  701. #endif
  702. #if VFLUSHO
  703. CI_ENTRY("flush", CFLUSHO, VFLUSHO )
  704. #endif
  705. #if VSTATUS
  706. CI_ENTRY("status", CSTATUS, VSTATUS )
  707. #endif
  708. /* These must be last because of the display routines */
  709. CI_ENTRY("min", 1, VMIN )
  710. CI_ENTRY("time", 0, VTIME )
  711. ;
  712. #undef CI_ENTRY
  713. #define CI_ENTRY(n,s,o) { s, o },
  714. static const struct control_info control_info[] ALIGN2 = {
  715. /* This should be verbatim cut-n-paste copy of the above CI_ENTRYs */
  716. CI_ENTRY("intr", CINTR, VINTR )
  717. CI_ENTRY("quit", CQUIT, VQUIT )
  718. CI_ENTRY("erase", CERASE, VERASE )
  719. CI_ENTRY("kill", CKILL, VKILL )
  720. CI_ENTRY("eof", CEOF, VEOF )
  721. CI_ENTRY("eol", CEOL, VEOL )
  722. #if VEOL2
  723. CI_ENTRY("eol2", CEOL2, VEOL2 )
  724. #endif
  725. #if VSWTCH
  726. CI_ENTRY("swtch", CSWTCH, VSWTCH )
  727. #endif
  728. CI_ENTRY("start", CSTART, VSTART )
  729. CI_ENTRY("stop", CSTOP, VSTOP )
  730. CI_ENTRY("susp", CSUSP, VSUSP )
  731. #if VDSUSP
  732. CI_ENTRY("dsusp", CDSUSP, VDSUSP )
  733. #endif
  734. #if VREPRINT
  735. CI_ENTRY("rprnt", CRPRNT, VREPRINT)
  736. #endif
  737. #if VWERASE
  738. CI_ENTRY("werase", CWERASE, VWERASE )
  739. #endif
  740. #if VLNEXT
  741. CI_ENTRY("lnext", CLNEXT, VLNEXT )
  742. #endif
  743. #if VFLUSHO
  744. CI_ENTRY("flush", CFLUSHO, VFLUSHO )
  745. #endif
  746. #if VSTATUS
  747. CI_ENTRY("status", CSTATUS, VSTATUS )
  748. #endif
  749. /* These must be last because of the display routines */
  750. CI_ENTRY("min", 1, VMIN )
  751. CI_ENTRY("time", 0, VTIME )
  752. };
  753. enum {
  754. NUM_control_info = ARRAY_SIZE(control_info)
  755. };
  756. struct globals {
  757. const char *device_name;
  758. /* The width of the screen, for output wrapping */
  759. unsigned max_col;
  760. /* Current position, to know when to wrap */
  761. unsigned current_col;
  762. } FIX_ALIASING;
  763. #define G (*(struct globals*)bb_common_bufsiz1)
  764. #define INIT_G() do { \
  765. setup_common_bufsiz(); \
  766. G.device_name = bb_msg_standard_input; \
  767. G.max_col = 80; \
  768. G.current_col = 0; /* we are noexec, must clear */ \
  769. } while (0)
  770. static void set_speed_or_die(enum speed_setting type, const char *arg,
  771. struct termios *mode)
  772. {
  773. speed_t baud;
  774. baud = tty_value_to_baud(xatou(arg));
  775. if (type != output_speed) { /* either input or both */
  776. cfsetispeed(mode, baud);
  777. }
  778. if (type != input_speed) { /* either output or both */
  779. cfsetospeed(mode, baud);
  780. }
  781. }
  782. static NORETURN void perror_on_device_and_die(const char *fmt)
  783. {
  784. bb_perror_msg_and_die(fmt, G.device_name);
  785. }
  786. static void perror_on_device(const char *fmt)
  787. {
  788. bb_perror_msg(fmt, G.device_name);
  789. }
  790. /* Print format string MESSAGE and optional args.
  791. Wrap to next line first if it won't fit.
  792. Print a space first unless MESSAGE will start a new line */
  793. static void wrapf(const char *message, ...)
  794. {
  795. char buf[128];
  796. va_list args;
  797. unsigned buflen;
  798. va_start(args, message);
  799. buflen = vsnprintf(buf, sizeof(buf), message, args);
  800. va_end(args);
  801. /* We seem to be called only with suitable lengths, but check if
  802. somebody failed to adhere to this assumption just to be sure. */
  803. if (!buflen || buflen >= sizeof(buf)) return;
  804. if (G.current_col > 0) {
  805. G.current_col++;
  806. if (buf[0] != '\n') {
  807. if (G.current_col + buflen >= G.max_col) {
  808. G.current_col = 0;
  809. bb_putchar('\n');
  810. } else {
  811. bb_putchar(' ');
  812. }
  813. }
  814. }
  815. fputs(buf, stdout);
  816. G.current_col += buflen;
  817. if (buf[buflen-1] == '\n')
  818. G.current_col = 0;
  819. }
  820. static void newline(void)
  821. {
  822. if (G.current_col != 0)
  823. wrapf("\n");
  824. }
  825. #ifdef TIOCGWINSZ
  826. static void set_window_size(int rows, int cols)
  827. {
  828. struct winsize win = { 0, 0, 0, 0 };
  829. if (ioctl(STDIN_FILENO, TIOCGWINSZ, &win)) {
  830. if (errno != EINVAL) {
  831. goto bail;
  832. }
  833. memset(&win, 0, sizeof(win));
  834. }
  835. if (rows >= 0)
  836. win.ws_row = rows;
  837. if (cols >= 0)
  838. win.ws_col = cols;
  839. if (ioctl(STDIN_FILENO, TIOCSWINSZ, (char *) &win))
  840. bail:
  841. perror_on_device("%s");
  842. }
  843. #endif
  844. static void display_window_size(int fancy)
  845. {
  846. const char *fmt_str = "%s\0%s: no size information for this device";
  847. unsigned width, height;
  848. if (get_terminal_width_height(STDIN_FILENO, &width, &height)) {
  849. if ((errno != EINVAL) || ((fmt_str += 2), !fancy)) {
  850. perror_on_device(fmt_str);
  851. }
  852. } else {
  853. wrapf(fancy ? "rows %u; columns %u;" : "%u %u\n",
  854. height, width);
  855. }
  856. }
  857. static const struct suffix_mult stty_suffixes[] = {
  858. { "b", 512 },
  859. { "k", 1024 },
  860. { "B", 1024 },
  861. { "", 0 }
  862. };
  863. static const struct mode_info *find_mode(const char *name)
  864. {
  865. int i = index_in_strings(mode_name, name);
  866. return i >= 0 ? &mode_info[i] : NULL;
  867. }
  868. static const struct control_info *find_control(const char *name)
  869. {
  870. int i = index_in_strings(control_name, name);
  871. return i >= 0 ? &control_info[i] : NULL;
  872. }
  873. enum {
  874. param_need_arg = 0x80,
  875. param_line = 1 | 0x80,
  876. param_rows = 2 | 0x80,
  877. param_cols = 3 | 0x80,
  878. param_columns = 4 | 0x80,
  879. param_size = 5,
  880. param_speed = 6,
  881. param_ispeed = 7 | 0x80,
  882. param_ospeed = 8 | 0x80,
  883. };
  884. static int find_param(const char *name)
  885. {
  886. static const char params[] ALIGN1 =
  887. "line\0" /* 1 */
  888. "rows\0" /* 2 */
  889. "cols\0" /* 3 */
  890. "columns\0" /* 4 */
  891. "size\0" /* 5 */
  892. "speed\0" /* 6 */
  893. "ispeed\0"
  894. "ospeed\0";
  895. int i = index_in_strings(params, name) + 1;
  896. if (i == 0)
  897. return 0;
  898. if (i != 5 && i != 6)
  899. i |= 0x80;
  900. return i;
  901. }
  902. static int recover_mode(const char *arg, struct termios *mode)
  903. {
  904. int i, n;
  905. unsigned chr;
  906. unsigned long iflag, oflag, cflag, lflag;
  907. /* Scan into temporaries since it is too much trouble to figure out
  908. the right format for 'tcflag_t' */
  909. if (sscanf(arg, "%lx:%lx:%lx:%lx%n",
  910. &iflag, &oflag, &cflag, &lflag, &n) != 4)
  911. return 0;
  912. mode->c_iflag = iflag;
  913. mode->c_oflag = oflag;
  914. mode->c_cflag = cflag;
  915. mode->c_lflag = lflag;
  916. arg += n;
  917. for (i = 0; i < NCCS; ++i) {
  918. if (sscanf(arg, ":%x%n", &chr, &n) != 1)
  919. return 0;
  920. mode->c_cc[i] = chr;
  921. arg += n;
  922. }
  923. /* Fail if there are too many fields */
  924. if (*arg != '\0')
  925. return 0;
  926. return 1;
  927. }
  928. static void display_recoverable(const struct termios *mode,
  929. int UNUSED_PARAM dummy)
  930. {
  931. int i;
  932. printf("%lx:%lx:%lx:%lx",
  933. (unsigned long) mode->c_iflag, (unsigned long) mode->c_oflag,
  934. (unsigned long) mode->c_cflag, (unsigned long) mode->c_lflag);
  935. for (i = 0; i < NCCS; ++i)
  936. printf(":%x", (unsigned int) mode->c_cc[i]);
  937. bb_putchar('\n');
  938. }
  939. static void display_speed(const struct termios *mode, int fancy)
  940. {
  941. //____________________ 01234567 8 9
  942. const char *fmt_str = "%lu %lu\n\0ispeed %lu baud; ospeed %lu baud;";
  943. unsigned long ispeed, ospeed;
  944. ispeed = cfgetispeed(mode);
  945. ospeed = cfgetospeed(mode);
  946. if (ispeed == 0 || ispeed == ospeed) {
  947. ispeed = ospeed; /* in case ispeed was 0 */
  948. //________ 0123 4 5 6 7 8 9
  949. fmt_str = "%lu\n\0\0\0\0\0speed %lu baud;";
  950. }
  951. if (fancy) fmt_str += 9;
  952. wrapf(fmt_str, tty_baud_to_value(ispeed), tty_baud_to_value(ospeed));
  953. }
  954. static void do_display(const struct termios *mode, int all)
  955. {
  956. int i;
  957. tcflag_t *bitsp;
  958. unsigned long mask;
  959. int prev_type = control;
  960. display_speed(mode, 1);
  961. if (all)
  962. display_window_size(1);
  963. #ifdef __linux__
  964. wrapf("line = %u;\n", mode->c_line);
  965. #else
  966. newline();
  967. #endif
  968. for (i = 0; i != CIDX_min; ++i) {
  969. char ch;
  970. char buf10[10];
  971. /* If swtch is the same as susp, don't print both */
  972. #if VSWTCH == VSUSP
  973. if (i == CIDX_swtch)
  974. continue;
  975. #endif
  976. /* If eof uses the same slot as min, only print whichever applies */
  977. #if VEOF == VMIN
  978. if (!(mode->c_lflag & ICANON)
  979. && (i == CIDX_eof || i == CIDX_eol)
  980. ) {
  981. continue;
  982. }
  983. #endif
  984. ch = mode->c_cc[control_info[i].offset];
  985. if (ch == _POSIX_VDISABLE)
  986. strcpy(buf10, "<undef>");
  987. else
  988. visible(ch, buf10, 0);
  989. wrapf("%s = %s;", nth_string(control_name, i), buf10);
  990. }
  991. #if VEOF == VMIN
  992. if ((mode->c_lflag & ICANON) == 0)
  993. #endif
  994. wrapf("min = %u; time = %u;", mode->c_cc[VMIN], mode->c_cc[VTIME]);
  995. newline();
  996. for (i = 0; i < NUM_mode_info; ++i) {
  997. if (mode_info[i].flags & OMIT)
  998. continue;
  999. if (mode_info[i].type != prev_type) {
  1000. newline();
  1001. prev_type = mode_info[i].type;
  1002. }
  1003. bitsp = get_ptr_to_tcflag(mode_info[i].type, mode);
  1004. mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
  1005. if ((*bitsp & mask) == mode_info[i].bits) {
  1006. if (all || (mode_info[i].flags & SANE_UNSET))
  1007. wrapf("-%s"+1, nth_string(mode_name, i));
  1008. } else {
  1009. if ((all && mode_info[i].flags & REV)
  1010. || (!all && (mode_info[i].flags & (SANE_SET | REV)) == (SANE_SET | REV))
  1011. ) {
  1012. wrapf("-%s", nth_string(mode_name, i));
  1013. }
  1014. }
  1015. }
  1016. newline();
  1017. }
  1018. static void sane_mode(struct termios *mode)
  1019. {
  1020. int i;
  1021. for (i = 0; i < NUM_control_info; ++i) {
  1022. #if VMIN == VEOF
  1023. if (i == CIDX_min)
  1024. break;
  1025. #endif
  1026. mode->c_cc[control_info[i].offset] = control_info[i].saneval;
  1027. }
  1028. for (i = 0; i < NUM_mode_info; ++i) {
  1029. tcflag_t val;
  1030. tcflag_t *bitsp = get_ptr_to_tcflag(mode_info[i].type, mode);
  1031. if (!bitsp)
  1032. continue;
  1033. val = *bitsp & ~((unsigned long)mode_info[i].mask);
  1034. if (mode_info[i].flags & SANE_SET) {
  1035. *bitsp = val | mode_info[i].bits;
  1036. } else
  1037. if (mode_info[i].flags & SANE_UNSET) {
  1038. *bitsp = val & ~mode_info[i].bits;
  1039. }
  1040. }
  1041. }
  1042. static void set_mode(const struct mode_info *info, int reversed,
  1043. struct termios *mode)
  1044. {
  1045. tcflag_t *bitsp;
  1046. bitsp = get_ptr_to_tcflag(info->type, mode);
  1047. if (bitsp) {
  1048. tcflag_t val = *bitsp & ~info->mask;
  1049. if (reversed)
  1050. *bitsp = val & ~info->bits;
  1051. else
  1052. *bitsp = val | info->bits;
  1053. return;
  1054. }
  1055. /* !bitsp - it's a "combination" mode */
  1056. if (info == &mode_info[IDX_evenp] || info == &mode_info[IDX_parity]) {
  1057. if (reversed)
  1058. mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
  1059. else
  1060. mode->c_cflag = (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7;
  1061. } else if (info == &mode_info[IDX_oddp]) {
  1062. if (reversed)
  1063. mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
  1064. else
  1065. mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB;
  1066. } else if (info == &mode_info[IDX_nl]) {
  1067. if (reversed) {
  1068. mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR;
  1069. mode->c_oflag = (mode->c_oflag | ONLCR) & ~OCRNL & ~ONLRET;
  1070. } else {
  1071. mode->c_iflag = mode->c_iflag & ~ICRNL;
  1072. if (ONLCR) mode->c_oflag = mode->c_oflag & ~ONLCR;
  1073. }
  1074. } else if (info == &mode_info[IDX_ek]) {
  1075. mode->c_cc[VERASE] = CERASE;
  1076. mode->c_cc[VKILL] = CKILL;
  1077. } else if (info == &mode_info[IDX_sane]) {
  1078. sane_mode(mode);
  1079. } else if (info == &mode_info[IDX_cbreak]) {
  1080. if (reversed)
  1081. mode->c_lflag |= ICANON;
  1082. else
  1083. mode->c_lflag &= ~ICANON;
  1084. } else if (info == &mode_info[IDX_pass8]) {
  1085. if (reversed) {
  1086. mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
  1087. mode->c_iflag |= ISTRIP;
  1088. } else {
  1089. mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
  1090. mode->c_iflag &= ~ISTRIP;
  1091. }
  1092. } else if (info == &mode_info[IDX_litout]) {
  1093. if (reversed) {
  1094. mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
  1095. mode->c_iflag |= ISTRIP;
  1096. mode->c_oflag |= OPOST;
  1097. } else {
  1098. mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
  1099. mode->c_iflag &= ~ISTRIP;
  1100. mode->c_oflag &= ~OPOST;
  1101. }
  1102. } else if (info == &mode_info[IDX_raw] || info == &mode_info[IDX_cooked]) {
  1103. if ((info == &mode_info[IDX_raw] && reversed)
  1104. || (info == &mode_info[IDX_cooked] && !reversed)
  1105. ) {
  1106. /* Cooked mode */
  1107. mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
  1108. mode->c_oflag |= OPOST;
  1109. mode->c_lflag |= ISIG | ICANON;
  1110. #if VMIN == VEOF
  1111. mode->c_cc[VEOF] = CEOF;
  1112. #endif
  1113. #if VTIME == VEOL
  1114. mode->c_cc[VEOL] = CEOL;
  1115. #endif
  1116. } else {
  1117. /* Raw mode */
  1118. mode->c_iflag = 0;
  1119. mode->c_oflag &= ~OPOST;
  1120. mode->c_lflag &= ~(ISIG | ICANON | XCASE);
  1121. mode->c_cc[VMIN] = 1;
  1122. mode->c_cc[VTIME] = 0;
  1123. }
  1124. }
  1125. #if IXANY
  1126. else if (info == &mode_info[IDX_decctlq]) {
  1127. if (reversed)
  1128. mode->c_iflag |= IXANY;
  1129. else
  1130. mode->c_iflag &= ~IXANY;
  1131. }
  1132. #endif
  1133. #if TABDLY
  1134. else if (info == &mode_info[IDX_tabs]) {
  1135. if (reversed)
  1136. mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3;
  1137. else
  1138. mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0;
  1139. }
  1140. #endif
  1141. #if OXTABS
  1142. else if (info == &mode_info[IDX_tabs]) {
  1143. if (reversed)
  1144. mode->c_oflag |= OXTABS;
  1145. else
  1146. mode->c_oflag &= ~OXTABS;
  1147. }
  1148. #endif
  1149. #if XCASE && IUCLC && OLCUC
  1150. else if (info==&mode_info[IDX_lcase] || info==&mode_info[IDX_LCASE]) {
  1151. if (reversed) {
  1152. mode->c_lflag &= ~XCASE;
  1153. mode->c_iflag &= ~IUCLC;
  1154. mode->c_oflag &= ~OLCUC;
  1155. } else {
  1156. mode->c_lflag |= XCASE;
  1157. mode->c_iflag |= IUCLC;
  1158. mode->c_oflag |= OLCUC;
  1159. }
  1160. }
  1161. #endif
  1162. else if (info == &mode_info[IDX_crt]) {
  1163. mode->c_lflag |= ECHOE | ECHOCTL | ECHOKE;
  1164. } else if (info == &mode_info[IDX_dec]) {
  1165. mode->c_cc[VINTR] = 3; /* ^C */
  1166. mode->c_cc[VERASE] = 127; /* DEL */
  1167. mode->c_cc[VKILL] = 21; /* ^U */
  1168. mode->c_lflag |= ECHOE | ECHOCTL | ECHOKE;
  1169. if (IXANY) mode->c_iflag &= ~IXANY;
  1170. }
  1171. }
  1172. static void set_control_char_or_die(const struct control_info *info,
  1173. const char *arg, struct termios *mode)
  1174. {
  1175. unsigned char value;
  1176. if (info == &control_info[CIDX_min] || info == &control_info[CIDX_time])
  1177. value = xatoul_range_sfx(arg, 0, 0xff, stty_suffixes);
  1178. else if (arg[0] == '\0' || arg[1] == '\0')
  1179. value = arg[0];
  1180. else if (strcmp(arg, "^-") == 0 || strcmp(arg, "undef") == 0)
  1181. value = _POSIX_VDISABLE;
  1182. else if (arg[0] == '^') { /* Ignore any trailing junk (^Cjunk) */
  1183. value = arg[1] & 0x1f; /* Non-letters get weird results */
  1184. if (arg[1] == '?')
  1185. value = 127;
  1186. } else
  1187. value = xatoul_range_sfx(arg, 0, 0xff, stty_suffixes);
  1188. mode->c_cc[info->offset] = value;
  1189. }
  1190. #define STTY_require_set_attr (1 << 0)
  1191. #define STTY_speed_was_set (1 << 1)
  1192. #define STTY_verbose_output (1 << 2)
  1193. #define STTY_recoverable_output (1 << 3)
  1194. #define STTY_noargs (1 << 4)
  1195. int stty_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  1196. int stty_main(int argc UNUSED_PARAM, char **argv)
  1197. {
  1198. struct termios mode;
  1199. void (*output_func)(const struct termios *, int);
  1200. const char *file_name = NULL;
  1201. int display_all = 0;
  1202. int stty_state;
  1203. int k;
  1204. INIT_G();
  1205. stty_state = STTY_noargs;
  1206. output_func = do_display;
  1207. /* First pass: only parse/verify command line params */
  1208. k = 0;
  1209. while (argv[++k]) {
  1210. const struct mode_info *mp;
  1211. const struct control_info *cp;
  1212. const char *arg = argv[k];
  1213. const char *argnext = argv[k+1];
  1214. int param;
  1215. if (arg[0] == '-') {
  1216. int i;
  1217. mp = find_mode(arg+1);
  1218. if (mp) {
  1219. if (!(mp->flags & REV))
  1220. goto invalid_argument;
  1221. stty_state &= ~STTY_noargs;
  1222. continue;
  1223. }
  1224. /* It is an option - parse it */
  1225. i = 0;
  1226. while (arg[++i]) {
  1227. switch (arg[i]) {
  1228. case 'a':
  1229. stty_state |= STTY_verbose_output;
  1230. output_func = do_display;
  1231. display_all = 1;
  1232. break;
  1233. case 'g':
  1234. stty_state |= STTY_recoverable_output;
  1235. output_func = display_recoverable;
  1236. break;
  1237. case 'F':
  1238. if (file_name)
  1239. bb_error_msg_and_die("only one device may be specified");
  1240. file_name = &arg[i+1]; /* "-Fdevice" ? */
  1241. if (!file_name[0]) { /* nope, "-F device" */
  1242. int p = k+1; /* argv[p] is argnext */
  1243. file_name = argnext;
  1244. if (!file_name)
  1245. bb_error_msg_and_die(bb_msg_requires_arg, "-F");
  1246. /* remove -F param from arg[vc] */
  1247. while (argv[p]) {
  1248. argv[p] = argv[p+1];
  1249. ++p;
  1250. }
  1251. }
  1252. goto end_option;
  1253. default:
  1254. goto invalid_argument;
  1255. }
  1256. }
  1257. end_option:
  1258. continue;
  1259. }
  1260. mp = find_mode(arg);
  1261. if (mp) {
  1262. stty_state &= ~STTY_noargs;
  1263. continue;
  1264. }
  1265. cp = find_control(arg);
  1266. if (cp) {
  1267. if (!argnext)
  1268. bb_error_msg_and_die(bb_msg_requires_arg, arg);
  1269. /* called for the side effect of xfunc death only */
  1270. set_control_char_or_die(cp, argnext, &mode);
  1271. stty_state &= ~STTY_noargs;
  1272. ++k;
  1273. continue;
  1274. }
  1275. param = find_param(arg);
  1276. if (param & param_need_arg) {
  1277. if (!argnext)
  1278. bb_error_msg_and_die(bb_msg_requires_arg, arg);
  1279. ++k;
  1280. }
  1281. switch (param) {
  1282. #ifdef __linux__
  1283. case param_line:
  1284. # ifndef TIOCGWINSZ
  1285. xatoul_range_sfx(argnext, 1, INT_MAX, stty_suffixes);
  1286. break;
  1287. # endif /* else fall-through */
  1288. #endif
  1289. #ifdef TIOCGWINSZ
  1290. case param_rows:
  1291. case param_cols:
  1292. case param_columns:
  1293. xatoul_range_sfx(argnext, 1, INT_MAX, stty_suffixes);
  1294. break;
  1295. case param_size:
  1296. #endif
  1297. case param_speed:
  1298. break;
  1299. case param_ispeed:
  1300. /* called for the side effect of xfunc death only */
  1301. set_speed_or_die(input_speed, argnext, &mode);
  1302. break;
  1303. case param_ospeed:
  1304. /* called for the side effect of xfunc death only */
  1305. set_speed_or_die(output_speed, argnext, &mode);
  1306. break;
  1307. default:
  1308. if (recover_mode(arg, &mode) == 1) break;
  1309. if (tty_value_to_baud(xatou(arg)) != (speed_t) -1) break;
  1310. invalid_argument:
  1311. bb_error_msg_and_die("invalid argument '%s'", arg);
  1312. }
  1313. stty_state &= ~STTY_noargs;
  1314. }
  1315. /* Specifying both -a and -g is an error */
  1316. if ((stty_state & (STTY_verbose_output | STTY_recoverable_output)) ==
  1317. (STTY_verbose_output | STTY_recoverable_output)
  1318. ) {
  1319. bb_error_msg_and_die("-a and -g are mutually exclusive");
  1320. }
  1321. /* Specifying -a or -g with non-options is an error */
  1322. if ((stty_state & (STTY_verbose_output | STTY_recoverable_output))
  1323. && !(stty_state & STTY_noargs)
  1324. ) {
  1325. bb_error_msg_and_die("modes may not be set when -a or -g is used");
  1326. }
  1327. /* Now it is safe to start doing things */
  1328. if (file_name) {
  1329. G.device_name = file_name;
  1330. xmove_fd(xopen_nonblocking(G.device_name), STDIN_FILENO);
  1331. ndelay_off(STDIN_FILENO);
  1332. }
  1333. /* Initialize to all zeroes so there is no risk memcmp will report a
  1334. spurious difference in an uninitialized portion of the structure */
  1335. memset(&mode, 0, sizeof(mode));
  1336. if (tcgetattr(STDIN_FILENO, &mode))
  1337. perror_on_device_and_die("%s");
  1338. if (stty_state & (STTY_verbose_output | STTY_recoverable_output | STTY_noargs)) {
  1339. G.max_col = get_terminal_width(STDOUT_FILENO);
  1340. output_func(&mode, display_all);
  1341. return EXIT_SUCCESS;
  1342. }
  1343. /* Second pass: perform actions */
  1344. k = 0;
  1345. while (argv[++k]) {
  1346. const struct mode_info *mp;
  1347. const struct control_info *cp;
  1348. const char *arg = argv[k];
  1349. const char *argnext = argv[k+1];
  1350. int param;
  1351. if (arg[0] == '-') {
  1352. mp = find_mode(arg+1);
  1353. if (mp) {
  1354. set_mode(mp, 1 /* reversed */, &mode);
  1355. stty_state |= STTY_require_set_attr;
  1356. }
  1357. /* It is an option - already parsed. Skip it */
  1358. continue;
  1359. }
  1360. mp = find_mode(arg);
  1361. if (mp) {
  1362. set_mode(mp, 0 /* non-reversed */, &mode);
  1363. stty_state |= STTY_require_set_attr;
  1364. continue;
  1365. }
  1366. cp = find_control(arg);
  1367. if (cp) {
  1368. ++k;
  1369. set_control_char_or_die(cp, argnext, &mode);
  1370. stty_state |= STTY_require_set_attr;
  1371. continue;
  1372. }
  1373. param = find_param(arg);
  1374. if (param & param_need_arg) {
  1375. ++k;
  1376. }
  1377. switch (param) {
  1378. #ifdef __linux__
  1379. case param_line:
  1380. mode.c_line = xatoul_sfx(argnext, stty_suffixes);
  1381. stty_state |= STTY_require_set_attr;
  1382. break;
  1383. #endif
  1384. #ifdef TIOCGWINSZ
  1385. case param_cols:
  1386. case param_columns:
  1387. set_window_size(-1, xatoul_sfx(argnext, stty_suffixes));
  1388. break;
  1389. case param_size:
  1390. display_window_size(0);
  1391. break;
  1392. case param_rows:
  1393. set_window_size(xatoul_sfx(argnext, stty_suffixes), -1);
  1394. break;
  1395. #endif
  1396. case param_speed:
  1397. display_speed(&mode, 0);
  1398. break;
  1399. case param_ispeed:
  1400. set_speed_or_die(input_speed, argnext, &mode);
  1401. stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
  1402. break;
  1403. case param_ospeed:
  1404. set_speed_or_die(output_speed, argnext, &mode);
  1405. stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
  1406. break;
  1407. default:
  1408. if (recover_mode(arg, &mode) == 1)
  1409. stty_state |= STTY_require_set_attr;
  1410. else /* true: if (tty_value_to_baud(xatou(arg)) != (speed_t) -1) */{
  1411. set_speed_or_die(both_speeds, arg, &mode);
  1412. stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
  1413. } /* else - impossible (caught in the first pass):
  1414. bb_error_msg_and_die("invalid argument '%s'", arg); */
  1415. }
  1416. }
  1417. if (stty_state & STTY_require_set_attr) {
  1418. struct termios new_mode;
  1419. if (tcsetattr(STDIN_FILENO, TCSADRAIN, &mode))
  1420. perror_on_device_and_die("%s");
  1421. /* POSIX (according to Zlotnick's book) tcsetattr returns zero if
  1422. it performs *any* of the requested operations. This means it
  1423. can report 'success' when it has actually failed to perform
  1424. some proper subset of the requested operations. To detect
  1425. this partial failure, get the current terminal attributes and
  1426. compare them to the requested ones */
  1427. /* Initialize to all zeroes so there is no risk memcmp will report a
  1428. spurious difference in an uninitialized portion of the structure */
  1429. memset(&new_mode, 0, sizeof(new_mode));
  1430. if (tcgetattr(STDIN_FILENO, &new_mode))
  1431. perror_on_device_and_die("%s");
  1432. if (memcmp(&mode, &new_mode, sizeof(mode)) != 0) {
  1433. /*
  1434. * I think the below chunk is not necessary on Linux.
  1435. * If you are deleting it, also delete STTY_speed_was_set bit -
  1436. * it is only ever checked here.
  1437. */
  1438. #if 0 /* was "if CIBAUD" */
  1439. /* SunOS 4.1.3 (at least) has the problem that after this sequence,
  1440. tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2);
  1441. sometimes (m1 != m2). The only difference is in the four bits
  1442. of the c_cflag field corresponding to the baud rate. To save
  1443. Sun users a little confusion, don't report an error if this
  1444. happens. But suppress the error only if we haven't tried to
  1445. set the baud rate explicitly -- otherwise we'd never give an
  1446. error for a true failure to set the baud rate */
  1447. new_mode.c_cflag &= (~CIBAUD);
  1448. if ((stty_state & STTY_speed_was_set)
  1449. || memcmp(&mode, &new_mode, sizeof(mode)) != 0)
  1450. #endif
  1451. perror_on_device_and_die("%s: cannot perform all requested operations");
  1452. }
  1453. }
  1454. return EXIT_SUCCESS;
  1455. }