stty.c 42 KB

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