stty.c 43 KB

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