stty.c 43 KB

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