3
0

stty.c 42 KB

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