pty.c 143 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199
  1. /*++
  2. Copyright (c) 2013 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. pty.c
  5. Abstract:
  6. This module implements terminal support.
  7. Author:
  8. Evan Green 10-May-2013
  9. Environment:
  10. Kernel
  11. --*/
  12. //
  13. // ------------------------------------------------------------------- Includes
  14. //
  15. #include <minoca/kernel/kernel.h>
  16. #include <minoca/lib/termlib.h>
  17. #include "iop.h"
  18. //
  19. // ---------------------------------------------------------------- Definitions
  20. //
  21. #define TERMINAL_ALLOCATION_TAG 0x216D7254 // '!mrT'
  22. #define TERMINAL_INITIAL_PERMISSIONS \
  23. (FILE_PERMISSION_USER_READ | FILE_PERMISSION_USER_WRITE | \
  24. FILE_PERMISSION_GROUP_READ | FILE_PERMISSION_GROUP_WRITE)
  25. #define TERMINAL_DIRECTORY_NAME "Terminal"
  26. #define TERMINAL_MASTER_NAME_FORMAT "Master%X"
  27. #define TERMINAL_SLAVE_NAME_FORMAT "Slave%X"
  28. #define TERMINAL_MAX_NAME_LENGTH 23
  29. #define TERMINAL_MAX_COMMAND_HISTORY 50
  30. #define TERMINAL_MAX_CANONICAL_OUTPUT 8
  31. //
  32. // Define the number of lines to scroll in canonical mode when page up/down
  33. // is seen.
  34. //
  35. #define TERMINAL_SCROLL_LINE_COUNT 5
  36. //
  37. // Define terminal limits. The input queue length must always be at least the
  38. // max canonical length since the line gets dumped into the input queue.
  39. //
  40. #define TERMINAL_INPUT_BUFFER_SIZE 512
  41. #define TERMINAL_CANONICAL_BUFFER_SIZE (TERMINAL_INPUT_BUFFER_SIZE - 1)
  42. #define TERMINAL_OUTPUT_BUFFER_SIZE 256
  43. //
  44. // Default control characters.
  45. //
  46. #define TERMINAL_DEFAULT_END_OF_FILE 0x04
  47. #define TERMINAL_DEFAULT_END_OF_LINE 0x00
  48. #define TERMINAL_DEFAULT_ERASE 0x7F
  49. #define TERMINAL_DEFAULT_INTERRUPT 0x03
  50. #define TERMINAL_DEFAULT_KILL 0x15
  51. #define TERMINAL_DEFAULT_QUIT 0x1C
  52. #define TERMINAL_DEFAULT_SUSPEND 0x1A
  53. #define TERMINAL_DEFAULT_START 0x11
  54. #define TERMINAL_DEFAULT_STOP 0x13
  55. //
  56. // Define the default baud rate terminals come up in.
  57. //
  58. #define TERMINAL_DEFAULT_BAUD_RATE 115200
  59. //
  60. // Define the default window size that terminals get initialized to.
  61. //
  62. #define TERMINAL_DEFAULT_ROWS 25
  63. #define TERMINAL_DEFAULT_COLUMNS 80
  64. //
  65. // Define terminal flags.
  66. //
  67. #define TERMINAL_FLAG_VIRGIN_LINE 0x00000001
  68. #define TERMINAL_FLAG_UNEDITED_LINE 0x0000002
  69. #define TERMINAL_FLAG_FAIL_OPENS 0x00000004
  70. //
  71. // Define the invalid session and process group IDs.
  72. //
  73. #define TERMINAL_INVALID_SESSION -1
  74. #define TERMINAL_INVALID_PROCESS_GROUP -1
  75. #define TERMINAL_POLL_ERRORS (POLL_EVENT_ERROR | POLL_EVENT_DISCONNECTED)
  76. //
  77. // --------------------------------------------------------------------- Macros
  78. //
  79. //
  80. // The terminal master is considered open if it has more than 1 reference. An
  81. // initial reference is taken upon creation, but that does not count towards
  82. // being opened.
  83. //
  84. #define IO_IS_TERMINAL_MASTER_OPEN(_Terminal) \
  85. ((_Terminal)->MasterReferenceCount > 1)
  86. //
  87. // ------------------------------------------------------ Data Type Definitions
  88. //
  89. typedef struct _TERMINAL_SLAVE TERMINAL_SLAVE, *PTERMINAL_SLAVE;
  90. /*++
  91. Structure Description:
  92. This structure defines terminal structure.
  93. Members:
  94. Header - Stores the standard object header.
  95. ListEntry - Stores pointers to the next and previous terminals in the
  96. global list.
  97. Number - Stores the terminal number.
  98. OutputBuffer - Stores the output buffer (buffer going out of the slave into
  99. the master).
  100. OutputBufferStart - Stores the first valid index of the output buffer.
  101. OutputBufferEnd - Stores the first invalid index of the output buffer. If
  102. this is equal to the start, then the buffer is empty.
  103. OutputLock - Stores a pointer to a lock serializing access to the output
  104. buffer.
  105. InputBuffer - Stores a pointer to the input buffer.
  106. InputBufferStart - Stores the first valid index of the input buffer.
  107. InputBufferEnd - Stores the first invalid index of the input buffer. If
  108. this is equal to the start, then the buffer is empty.
  109. WorkingInputBuffer - Stores the current (unfinished) line in canonical
  110. mode.
  111. WorkingInputCursor - Stores the current position of the cursor in the
  112. working input buffer.
  113. WorkingInputLength - Stores the valid length of the working input buffer.
  114. InputLock - Stores a pointer to a lock serializing access to the
  115. working input buffer.
  116. Settings - Stores the current terminal settings.
  117. Flags - Stores a bitfield of flags. See TERMINAL_FLAG_* definitions. This
  118. field is protected by the terminal output lock.
  119. KeyData - Stores the data for the key currently being parsed. This is only
  120. used in canonical mode.
  121. SlaveHandles - Stores the count of open slave side handles, not counting
  122. those opened with no access.
  123. ProcessGroupId - Stores the owning process group ID of the terminal.
  124. SessionId - Stores the owning session ID of the terminal.
  125. ConnectionLock - Stores a spin lock that synchronizes the connection
  126. between the master and the slave, ensuring they both shut down in an
  127. orderly fashion.
  128. MasterReferenceCount - Stores the number of references on the master. This
  129. amounts to the number of open file handles plus one additional
  130. reference set on initialization.
  131. Slave - Stores a pointer to the corresponding slave object.
  132. SlaveFileObject - Stores a pointer to the slave's file object.
  133. MasterFileObject - Stores a pointer to the master's file object.
  134. WindowSize - Stores the window size of the terminal.
  135. ModemStatus - Stores the modem status bits.
  136. HardwareHandle - Stores an optional handle to the hardware device backing
  137. this terminal.
  138. SlavePathPoint - Stores the path point of the slave device, used to unlink
  139. it when the last master handle is closed.
  140. --*/
  141. typedef struct _TERMINAL {
  142. OBJECT_HEADER Header;
  143. LIST_ENTRY ListEntry;
  144. ULONG Number;
  145. PSTR OutputBuffer;
  146. ULONG OutputBufferStart;
  147. ULONG OutputBufferEnd;
  148. PQUEUED_LOCK OutputLock;
  149. PSTR InputBuffer;
  150. ULONG InputBufferStart;
  151. ULONG InputBufferEnd;
  152. PSTR WorkingInputBuffer;
  153. ULONG WorkingInputCursor;
  154. ULONG WorkingInputLength;
  155. PQUEUED_LOCK InputLock;
  156. TERMINAL_SETTINGS Settings;
  157. TERMINAL_KEY_DATA KeyData;
  158. ULONG Flags;
  159. UINTN SlaveHandles;
  160. PROCESS_GROUP_ID ProcessGroupId;
  161. SESSION_ID SessionId;
  162. ULONG MasterReferenceCount;
  163. PTERMINAL_SLAVE Slave;
  164. PFILE_OBJECT SlaveFileObject;
  165. PFILE_OBJECT MasterFileObject;
  166. TERMINAL_WINDOW_SIZE WindowSize;
  167. INT ModemStatus;
  168. PIO_HANDLE HardwareHandle;
  169. PATH_POINT SlavePathPoint;
  170. } TERMINAL, *PTERMINAL;
  171. /*++
  172. Structure Description:
  173. This structure defines the slave terminal structure.
  174. Members:
  175. Header - Stores the standard object header.
  176. Master - Stores a pointer to the master terminal.
  177. --*/
  178. struct _TERMINAL_SLAVE {
  179. OBJECT_HEADER Header;
  180. PTERMINAL Master;
  181. };
  182. /*++
  183. Structure Description:
  184. This structure defines the parameters sent during a creation request of
  185. a terminal object.
  186. Members:
  187. SlaveCreatePermissions - Store a pointer to the permissions used when
  188. creating the slave side.
  189. Master - Stores a pointer to the master terminal. When creating a master
  190. terminal, this parameter will be filled in during create. When creating
  191. a slave, this parameter must already be filled in and will be used.
  192. --*/
  193. typedef struct _TERMINAL_CREATION_PARAMETERS {
  194. FILE_PERMISSIONS SlaveCreatePermissions;
  195. PTERMINAL Master;
  196. } TERMINAL_CREATION_PARAMETERS, *PTERMINAL_CREATION_PARAMETERS;
  197. //
  198. // ----------------------------------------------- Internal Function Prototypes
  199. //
  200. KSTATUS
  201. IopCreateTerminalObject (
  202. FILE_PERMISSIONS CreatePermissions,
  203. PTERMINAL *NewTerminal
  204. );
  205. VOID
  206. IopDestroyTerminal (
  207. PVOID TerminalObject
  208. );
  209. KSTATUS
  210. IopTerminalMasterWrite (
  211. PFILE_OBJECT FileObject,
  212. PIO_CONTEXT IoContext
  213. );
  214. KSTATUS
  215. IopTerminalSlaveWrite (
  216. PFILE_OBJECT FileObject,
  217. PIO_CONTEXT IoContext
  218. );
  219. KSTATUS
  220. IopTerminalMasterRead (
  221. PFILE_OBJECT FileObject,
  222. PIO_CONTEXT IoContext
  223. );
  224. KSTATUS
  225. IopTerminalSlaveRead (
  226. PFILE_OBJECT FileObject,
  227. PIO_CONTEXT IoContext
  228. );
  229. KSTATUS
  230. IopTerminalWriteOutputBuffer (
  231. PTERMINAL Terminal,
  232. PVOID Buffer,
  233. UINTN SizeInBytes,
  234. ULONG RepeatCount,
  235. ULONG TimeoutInMilliseconds
  236. );
  237. ULONG
  238. IopTerminalGetInputBufferSpace (
  239. PTERMINAL Terminal
  240. );
  241. ULONG
  242. IopTerminalGetOutputBufferSpace (
  243. PTERMINAL Terminal
  244. );
  245. KSTATUS
  246. IopTerminalFixUpCanonicalLine (
  247. PTERMINAL Terminal,
  248. ULONG TimeoutInMilliseconds,
  249. ULONG DirtyRegionBegin,
  250. ULONG DirtyRegionEnd,
  251. ULONG CurrentScreenPosition
  252. );
  253. BOOL
  254. IopTerminalProcessEditingCharacter (
  255. PTERMINAL Terminal,
  256. CHAR Character,
  257. ULONG TimeoutInMilliseconds,
  258. PULONG DirtyRegionBegin,
  259. PULONG DirtyRegionEnd,
  260. PULONG ScreenCursorPosition,
  261. PBOOL OutputWritten
  262. );
  263. KSTATUS
  264. IopTerminalUserBufferCopy (
  265. BOOL FromKernelMode,
  266. BOOL FromBuffer,
  267. PVOID UserBuffer,
  268. PVOID LocalBuffer,
  269. UINTN Size
  270. );
  271. KSTATUS
  272. IopTerminalFlushOutputToDevice (
  273. PTERMINAL Terminal
  274. );
  275. VOID
  276. IopTerminalDisassociate (
  277. PTERMINAL Terminal
  278. );
  279. BOOL
  280. IopTerminalDisassociateIterator (
  281. PVOID Context,
  282. PKPROCESS Process
  283. );
  284. //
  285. // -------------------------------------------------------------------- Globals
  286. //
  287. //
  288. // Store a pointer to the global terminal directory.
  289. //
  290. PVOID IoTerminalDirectory;
  291. //
  292. // Store the global list of terminals.
  293. //
  294. LIST_ENTRY IoTerminalList;
  295. PQUEUED_LOCK IoTerminalListLock;
  296. //
  297. // Store a pointer to the local console terminal.
  298. //
  299. PIO_HANDLE IoLocalConsole;
  300. //
  301. // ------------------------------------------------------------------ Functions
  302. //
  303. KERNEL_API
  304. KSTATUS
  305. IoCreateTerminal (
  306. BOOL FromKernelMode,
  307. PIO_HANDLE MasterDirectory,
  308. PIO_HANDLE SlaveDirectory,
  309. PSTR MasterPath,
  310. UINTN MasterPathLength,
  311. PSTR SlavePath,
  312. UINTN SlavePathLength,
  313. ULONG MasterAccess,
  314. ULONG MasterOpenFlags,
  315. FILE_PERMISSIONS MasterCreatePermissions,
  316. FILE_PERMISSIONS SlaveCreatePermissions,
  317. PIO_HANDLE *MasterHandle
  318. )
  319. /*++
  320. Routine Description:
  321. This routine creates and opens a new terminal master.
  322. Arguments:
  323. FromKernelMode - Supplies a boolean indicating whether this request is
  324. originating from kernel mode (and should use the root path as a base)
  325. or user mode.
  326. MasterDirectory - Supplies an optional pointer to an open handle to a
  327. directory for relative paths when creating the master. Supply NULL to
  328. use the current working directory.
  329. SlaveDirectory - Supplies an optional pointer to an open handle to a
  330. directory for relative paths when creating the slave. Supply NULL to
  331. use the current working directory.
  332. MasterPath - Supplies an optional pointer to the path to create for the
  333. master.
  334. MasterPathLength - Supplies the length of the master side path buffer in
  335. bytes, including the null terminator.
  336. SlavePath - Supplies an optional pointer to the path to create for the
  337. master.
  338. SlavePathLength - Supplies the length of the slave side path buffer in
  339. bytes, including the null terminator.
  340. MasterAccess - Supplies the desired access permissions to the master side
  341. handle. See IO_ACCESS_* definitions.
  342. MasterOpenFlags - Supplies the open flags to use when opening the master.
  343. MasterCreatePermissions - Supplies the permissions to apply to the created
  344. master side.
  345. SlaveCreatePermissions - Supplies the permission to apply to the created
  346. slave side.
  347. MasterHandle - Supplies a pointer where a handle to the master side of the
  348. new terminal will be returned.
  349. Return Value:
  350. Status code.
  351. --*/
  352. {
  353. TERMINAL_CREATION_PARAMETERS CreationParameters;
  354. PIO_HANDLE SlaveHandle;
  355. KSTATUS Status;
  356. RtlZeroMemory(&CreationParameters, sizeof(TERMINAL_CREATION_PARAMETERS));
  357. CreationParameters.SlaveCreatePermissions = SlaveCreatePermissions;
  358. //
  359. // First try to open the master.
  360. //
  361. MasterOpenFlags |= OPEN_FLAG_CREATE | OPEN_FLAG_FAIL_IF_EXISTS;
  362. Status = IopOpen(FromKernelMode,
  363. MasterDirectory,
  364. MasterPath,
  365. MasterPathLength,
  366. MasterAccess,
  367. MasterOpenFlags,
  368. IoObjectTerminalMaster,
  369. &CreationParameters,
  370. MasterCreatePermissions,
  371. MasterHandle);
  372. if (!KSUCCESS(Status)) {
  373. return Status;
  374. }
  375. //
  376. // The master put itself in the creation parameters, which are now passed
  377. // down when trying to create the slave (which is mostly just a matter of
  378. // creating the path entry now).
  379. //
  380. MasterOpenFlags |= OPEN_FLAG_NO_CONTROLLING_TERMINAL;
  381. Status = IopOpen(FromKernelMode,
  382. SlaveDirectory,
  383. SlavePath,
  384. SlavePathLength,
  385. 0,
  386. MasterOpenFlags,
  387. IoObjectTerminalSlave,
  388. &CreationParameters,
  389. SlaveCreatePermissions,
  390. &SlaveHandle);
  391. if (!KSUCCESS(Status)) {
  392. IoClose(*MasterHandle);
  393. }
  394. //
  395. // Copy the path entry, then close the slave handle.
  396. //
  397. ASSERT((CreationParameters.Master != NULL) &&
  398. (CreationParameters.Master->SlavePathPoint.PathEntry == NULL));
  399. IO_COPY_PATH_POINT(&(CreationParameters.Master->SlavePathPoint),
  400. &(SlaveHandle->PathPoint));
  401. IO_PATH_POINT_ADD_REFERENCE(&(CreationParameters.Master->SlavePathPoint));
  402. IoClose(SlaveHandle);
  403. return Status;
  404. }
  405. KERNEL_API
  406. KSTATUS
  407. IoOpenLocalTerminalMaster (
  408. PIO_HANDLE *TerminalMaster
  409. )
  410. /*++
  411. Routine Description:
  412. This routine opens the master side of the local console terminal. This
  413. routine is intended to be used by the input and output devices that
  414. actually service the local console (the user input driver and video
  415. console driver).
  416. Arguments:
  417. TerminalMaster - Supplies a pointer where the I/O handle representing the
  418. master side of the local console terminal will be returned.
  419. Return Value:
  420. Status code.
  421. --*/
  422. {
  423. if (IoLocalConsole == NULL) {
  424. return STATUS_NOT_READY;
  425. }
  426. IoIoHandleAddReference(IoLocalConsole);
  427. *TerminalMaster = IoLocalConsole;
  428. return STATUS_SUCCESS;
  429. }
  430. KERNEL_API
  431. KSTATUS
  432. IoOpenControllingTerminal (
  433. PIO_HANDLE *IoHandle
  434. )
  435. /*++
  436. Routine Description:
  437. This routine attempts to open the current process' controlling terminal.
  438. Arguments:
  439. IoHandle - Supplies a pointer where the open I/O handle will be returned on
  440. success.
  441. Return Value:
  442. Status code.
  443. --*/
  444. {
  445. PIO_HANDLE Handle;
  446. ULONG PreviousValue;
  447. PKPROCESS Process;
  448. KSTATUS Status;
  449. *IoHandle = NULL;
  450. Process = PsGetCurrentProcess();
  451. KeAcquireQueuedLock(IoTerminalListLock);
  452. if (Process->ControllingTerminal == NULL) {
  453. Status = STATUS_NO_SUCH_DEVICE;
  454. } else {
  455. //
  456. // This part is a little fishy. Manually attempt to increment the
  457. // reference count on the handle. If the handle reference count was
  458. // zero, quietly back out. Because closing the slave acquires the
  459. // terminal list lock held here, the handle cannot disappear entirely.
  460. // But it can be in the process of closing. This concept was not
  461. // generalized into the I/O handle code because the idea of not
  462. // having a reference on the handle but somehow ensuring that it
  463. // couldn't disappear did not seem like a legit contract to create a
  464. // generic I/O handle function around.
  465. //
  466. Handle = Process->ControllingTerminal;
  467. PreviousValue = RtlAtomicAdd32(&(Handle->ReferenceCount), 1);
  468. if (PreviousValue == 0) {
  469. RtlAtomicAdd32(&(Handle->ReferenceCount), -1);
  470. Status = STATUS_NO_SUCH_DEVICE;
  471. } else {
  472. *IoHandle = Handle;
  473. Status = STATUS_SUCCESS;
  474. }
  475. }
  476. KeReleaseQueuedLock(IoTerminalListLock);
  477. return Status;
  478. }
  479. KERNEL_API
  480. KSTATUS
  481. IoSetTerminalSettings (
  482. PIO_HANDLE TerminalHandle,
  483. PTERMINAL_SETTINGS NewSettings,
  484. PTERMINAL_SETTINGS OriginalSettings,
  485. TERMINAL_CHANGE_BEHAVIOR When
  486. )
  487. /*++
  488. Routine Description:
  489. This routine gets or sets the current terminal settings.
  490. Arguments:
  491. TerminalHandle - Supplies a pointer to the I/O handle of the terminal to
  492. change.
  493. NewSettings - Supplies an optional pointer to the new terminal settings.
  494. If this pointer is NULL, then the current settings will be retrieved
  495. but no changes will be made.
  496. OriginalSettings - Supplies an optional pointer where the current
  497. settings will be returned.
  498. When - Supplies when the new change should occur.
  499. Return Value:
  500. Status code.
  501. --*/
  502. {
  503. PFILE_OBJECT FileObject;
  504. KSTATUS Status;
  505. PTERMINAL Terminal;
  506. PTERMINAL_SLAVE TerminalSlave;
  507. //
  508. // Get a pointer to the actual terminal structure.
  509. //
  510. FileObject = TerminalHandle->FileObject;
  511. if (FileObject->Properties.Type == IoObjectTerminalMaster) {
  512. Terminal = FileObject->SpecialIo;
  513. } else if (FileObject->Properties.Type == IoObjectTerminalSlave) {
  514. TerminalSlave = FileObject->SpecialIo;
  515. Terminal = TerminalSlave->Master;
  516. } else {
  517. return STATUS_NOT_A_TERMINAL;
  518. }
  519. ASSERT(KeGetRunLevel() == RunLevelLow);
  520. //
  521. // Lock down the terminal for this. The order of lock acquisition is
  522. // important.
  523. //
  524. KeAcquireQueuedLock(Terminal->OutputLock);
  525. KeAcquireQueuedLock(Terminal->InputLock);
  526. if (OriginalSettings != NULL) {
  527. RtlCopyMemory(OriginalSettings,
  528. &(Terminal->Settings),
  529. sizeof(TERMINAL_SETTINGS));
  530. }
  531. if (NewSettings != NULL) {
  532. //
  533. // Fail if an unsupported feature was requested. Consider adding
  534. // support for said feature.
  535. //
  536. if (((NewSettings->InputFlags &
  537. TERMINAL_UNIMPLEMENTED_INPUT_FLAGS) != 0) ||
  538. ((NewSettings->OutputFlags &
  539. TERMINAL_UNIMPLEMENTED_OUTPUT_FLAGS) != 0) ||
  540. ((NewSettings->ControlFlags &
  541. TERMINAL_UNIMPLEMENTED_CONTROL_FLAGS) != 0)) {
  542. ASSERT(FALSE);
  543. Status = STATUS_NOT_SUPPORTED;
  544. goto SetTerminalSettingsEnd;
  545. }
  546. RtlCopyMemory(&(Terminal->Settings),
  547. NewSettings,
  548. sizeof(TERMINAL_SETTINGS));
  549. }
  550. //
  551. // If the user asked, remove all input.
  552. //
  553. if (When == TerminalChangeAfterOutputFlushInput) {
  554. Terminal->InputBufferStart = 0;
  555. Terminal->InputBufferEnd = 0;
  556. }
  557. Status = STATUS_SUCCESS;
  558. SetTerminalSettingsEnd:
  559. KeReleaseQueuedLock(Terminal->OutputLock);
  560. KeReleaseQueuedLock(Terminal->InputLock);
  561. return Status;
  562. }
  563. KERNEL_API
  564. KSTATUS
  565. IoTerminalSetDevice (
  566. PIO_HANDLE TerminalMaster,
  567. PIO_HANDLE DeviceHandle
  568. )
  569. /*++
  570. Routine Description:
  571. This routine associates or disassociates a terminal object with a device.
  572. Writes to the terminal slave will be forwarded to the associated terminal,
  573. as will changes to the terminal settings. If a device is being associated
  574. with the terminal, then the new settings will be sent to the device
  575. immediately in this routine.
  576. Arguments:
  577. TerminalMaster - Supplies a handle to the terminal master.
  578. DeviceHandle - Supplies a handle to the terminal hardware device. Any
  579. previously associated handle will be closed. Supply NULL to
  580. disassociate the terminal with a device. Upon success, this routine
  581. takes ownership of this device handle, and the caller should not close
  582. it manually.
  583. Return Value:
  584. Status code.
  585. --*/
  586. {
  587. PFILE_OBJECT FileObject;
  588. KSTATUS Status;
  589. PTERMINAL Terminal;
  590. FileObject = TerminalMaster->FileObject;
  591. if (FileObject->Properties.Type != IoObjectTerminalMaster) {
  592. Status = STATUS_NOT_A_TERMINAL;
  593. goto TerminalSetDeviceEnd;
  594. }
  595. Terminal = FileObject->SpecialIo;
  596. Status = STATUS_SUCCESS;
  597. //
  598. // Remove the old handle.
  599. //
  600. KeAcquireQueuedLock(Terminal->OutputLock);
  601. KeAcquireQueuedLock(Terminal->InputLock);
  602. if (Terminal->HardwareHandle != NULL) {
  603. IoClose(Terminal->HardwareHandle);
  604. }
  605. Terminal->HardwareHandle = DeviceHandle;
  606. //
  607. // If a new device is being associated with the terminal, send the settings
  608. // down to it now.
  609. //
  610. if (DeviceHandle != NULL) {
  611. Status = IoUserControl(DeviceHandle,
  612. TerminalControlSetAttributes,
  613. TRUE,
  614. &(Terminal->Settings),
  615. sizeof(TERMINAL_SETTINGS));
  616. }
  617. KeReleaseQueuedLock(Terminal->OutputLock);
  618. KeReleaseQueuedLock(Terminal->InputLock);
  619. TerminalSetDeviceEnd:
  620. return Status;
  621. }
  622. KSTATUS
  623. IopInitializeTerminalSupport (
  624. VOID
  625. )
  626. /*++
  627. Routine Description:
  628. This routine is called during system initialization to set up support for
  629. terminals.
  630. Arguments:
  631. None.
  632. Return Value:
  633. Status code.
  634. --*/
  635. {
  636. KSTATUS Status;
  637. INITIALIZE_LIST_HEAD(&IoTerminalList);
  638. IoTerminalListLock = KeCreateQueuedLock();
  639. if (IoTerminalListLock == NULL) {
  640. Status = STATUS_INSUFFICIENT_RESOURCES;
  641. goto InitializeTerminalSupportEnd;
  642. }
  643. //
  644. // Create the Terminal object directory.
  645. //
  646. IoTerminalDirectory = ObCreateObject(ObjectDirectory,
  647. NULL,
  648. TERMINAL_DIRECTORY_NAME,
  649. sizeof(TERMINAL_DIRECTORY_NAME),
  650. sizeof(OBJECT_HEADER),
  651. NULL,
  652. OBJECT_FLAG_USE_NAME_DIRECTLY,
  653. TERMINAL_ALLOCATION_TAG);
  654. if (IoTerminalDirectory == NULL) {
  655. Status = STATUS_INSUFFICIENT_RESOURCES;
  656. goto InitializeTerminalSupportEnd;
  657. }
  658. //
  659. // Create a local console terminal.
  660. //
  661. Status = IoCreateTerminal(TRUE,
  662. NULL,
  663. NULL,
  664. NULL,
  665. 0,
  666. NULL,
  667. 0,
  668. IO_ACCESS_READ | IO_ACCESS_WRITE,
  669. 0,
  670. TERMINAL_DEFAULT_PERMISSIONS,
  671. TERMINAL_DEFAULT_PERMISSIONS,
  672. &IoLocalConsole);
  673. if (!KSUCCESS(Status)) {
  674. goto InitializeTerminalSupportEnd;
  675. }
  676. Status = STATUS_SUCCESS;
  677. InitializeTerminalSupportEnd:
  678. return Status;
  679. }
  680. KSTATUS
  681. IopTerminalOpenMaster (
  682. PIO_HANDLE IoHandle
  683. )
  684. /*++
  685. Routine Description:
  686. This routine is called when a master terminal was just opened.
  687. Arguments:
  688. IoHandle - Supplies a pointer to the I/O handle for the terminal.
  689. Return Value:
  690. Status code.
  691. --*/
  692. {
  693. PFILE_OBJECT FileObject;
  694. KSTATUS Status;
  695. PTERMINAL Terminal;
  696. FileObject = IoHandle->FileObject;
  697. ASSERT(FileObject->Properties.Type == IoObjectTerminalMaster);
  698. //
  699. // If no access is requested, then the special I/O terminal object does not
  700. // need to be present, and in fact, may not be.
  701. //
  702. if (IoHandle->Access == 0) {
  703. return STATUS_SUCCESS;
  704. }
  705. Terminal = FileObject->SpecialIo;
  706. if (Terminal == NULL) {
  707. Status = STATUS_NOT_READY;
  708. return Status;
  709. }
  710. ASSERT(Terminal->Header.Type == ObjectTerminalMaster);
  711. if (((Terminal->Flags & TERMINAL_FLAG_FAIL_OPENS) != 0) &&
  712. (!KSUCCESS(PsCheckPermission(PERMISSION_SYSTEM_ADMINISTRATOR)))) {
  713. return STATUS_RESOURCE_IN_USE;
  714. }
  715. //
  716. // Increment the number of parties that have the master terminal open. If
  717. // the initial reference taken on creation is gone, then this master
  718. // terminal is on its way out. That is, do not resurrect the master from 0
  719. // references.
  720. //
  721. Status = STATUS_SUCCESS;
  722. KeAcquireQueuedLock(IoTerminalListLock);
  723. if (Terminal->MasterReferenceCount == 0) {
  724. Status = STATUS_NO_SUCH_FILE;
  725. } else {
  726. Terminal->MasterReferenceCount += 1;
  727. }
  728. KeReleaseQueuedLock(IoTerminalListLock);
  729. return Status;
  730. }
  731. KSTATUS
  732. IopTerminalCloseMaster (
  733. PIO_HANDLE IoHandle
  734. )
  735. /*++
  736. Routine Description:
  737. This routine is called when a master terminal was just closed.
  738. Arguments:
  739. IoHandle - Supplies a pointer to the handle to close.
  740. Return Value:
  741. Status code.
  742. --*/
  743. {
  744. ULONG Events;
  745. PFILE_OBJECT FileObject;
  746. PTERMINAL Terminal;
  747. FileObject = IoHandle->FileObject;
  748. ASSERT(FileObject->Properties.Type == IoObjectTerminalMaster);
  749. //
  750. // Handles with no access never really counted and the special I/O object
  751. // may not have ever been present.
  752. //
  753. if (IoHandle->Access == 0) {
  754. return STATUS_SUCCESS;
  755. }
  756. Terminal = FileObject->SpecialIo;
  757. ASSERT(Terminal->Header.Type == ObjectTerminalMaster);
  758. //
  759. // Just decrement the reference count.
  760. //
  761. KeAcquireQueuedLock(IoTerminalListLock);
  762. ASSERT((Terminal->MasterReferenceCount > 1) &&
  763. (Terminal->MasterReferenceCount < 0x10000000));
  764. Terminal->MasterReferenceCount -= 1;
  765. //
  766. // If this was the last reference to match an open of the master, close the
  767. // connection between the master and the slave.
  768. //
  769. if (Terminal->MasterReferenceCount == 1) {
  770. //
  771. // Decrement the original reference, preventing any additional opens of
  772. // the master terminal during the destruction process. It is possible
  773. // that a path walk has already taken another reference on the master's
  774. // path entry.
  775. //
  776. Terminal->MasterReferenceCount -= 1;
  777. if (Terminal->SlaveFileObject != NULL) {
  778. Events = POLL_EVENT_IN | POLL_EVENT_OUT | POLL_EVENT_ERROR |
  779. POLL_EVENT_DISCONNECTED;
  780. IoSetIoObjectState(Terminal->SlaveFileObject->IoState,
  781. Events,
  782. TRUE);
  783. }
  784. //
  785. // Unlink the master.
  786. //
  787. IopDeleteByHandle(TRUE, IoHandle, 0);
  788. //
  789. // Unlink the slave.
  790. //
  791. if (Terminal->SlavePathPoint.PathEntry != NULL) {
  792. IopDeletePathPoint(TRUE, &(Terminal->SlavePathPoint), 0);
  793. IO_PATH_POINT_RELEASE_REFERENCE(&(Terminal->SlavePathPoint));
  794. Terminal->SlavePathPoint.PathEntry = NULL;
  795. }
  796. //
  797. // Release the initial reference on the slave file object taken when
  798. // the master was created.
  799. //
  800. if (Terminal->SlaveFileObject != NULL) {
  801. IopFileObjectReleaseReference(Terminal->SlaveFileObject);
  802. }
  803. }
  804. KeReleaseQueuedLock(IoTerminalListLock);
  805. return STATUS_SUCCESS;
  806. }
  807. KSTATUS
  808. IopTerminalOpenSlave (
  809. PIO_HANDLE IoHandle
  810. )
  811. /*++
  812. Routine Description:
  813. This routine opens the slave side of a terminal object.
  814. Arguments:
  815. IoHandle - Supplies a pointer to the I/O handle for the terminal.
  816. Return Value:
  817. Status code.
  818. --*/
  819. {
  820. PFILE_OBJECT FileObject;
  821. PIO_OBJECT_STATE MasterIoState;
  822. PKPROCESS Process;
  823. PTERMINAL_SLAVE Slave;
  824. KSTATUS Status;
  825. PTERMINAL Terminal;
  826. BOOL TerminalLocksHeld;
  827. FileObject = IoHandle->FileObject;
  828. ASSERT(FileObject->Properties.Type == IoObjectTerminalSlave);
  829. //
  830. // If the caller doesn't actually want any access, then just let it slide.
  831. // The special I/O object may not be initialized.
  832. //
  833. if (IoHandle->Access == 0) {
  834. return STATUS_SUCCESS;
  835. }
  836. Slave = FileObject->SpecialIo;
  837. if (Slave == NULL) {
  838. return STATUS_NOT_READY;
  839. }
  840. ASSERT(Slave->Header.Type == ObjectTerminalSlave);
  841. TerminalLocksHeld = FALSE;
  842. KeAcquireQueuedLock(IoTerminalListLock);
  843. //
  844. // Get the master terminal. Synchronize this to avoid situations where the
  845. // master gets cleaned up after this pointer is read. Also synchronize with
  846. // the setting of the owning process group and session. Some of the user
  847. // controls synchronize terminal lookups with session ownership changes.
  848. //
  849. Terminal = Slave->Master;
  850. if (((Terminal->Flags & TERMINAL_FLAG_FAIL_OPENS) != 0) &&
  851. (!KSUCCESS(PsCheckPermission(PERMISSION_SYSTEM_ADMINISTRATOR)))) {
  852. Status = STATUS_RESOURCE_IN_USE;
  853. goto TerminalOpenSlaveEnd;
  854. }
  855. if (IO_IS_TERMINAL_MASTER_OPEN(Terminal) != FALSE) {
  856. ObAddReference(Terminal);
  857. IopFileObjectAddReference(Terminal->MasterFileObject);
  858. } else {
  859. Terminal = NULL;
  860. }
  861. if (Terminal == NULL) {
  862. Status = STATUS_TOO_LATE;
  863. goto TerminalOpenSlaveEnd;
  864. }
  865. //
  866. // Synchronize the check and set of the owning process group and session
  867. // with other opens and requests to change the process group and session.
  868. //
  869. TerminalLocksHeld = TRUE;
  870. KeAcquireQueuedLock(Terminal->OutputLock);
  871. KeAcquireQueuedLock(Terminal->InputLock);
  872. //
  873. // If the terminal is already open in another session, refuse to open.
  874. //
  875. Process = PsGetCurrentProcess();
  876. Terminal->SlaveHandles += 1;
  877. //
  878. // Clear the error that may have been set when the last previous slave
  879. // was closed.
  880. //
  881. if (Terminal->SlaveHandles == 1) {
  882. MasterIoState = Terminal->MasterFileObject->IoState;
  883. IoSetIoObjectState(MasterIoState, POLL_EVENT_DISCONNECTED, FALSE);
  884. //
  885. // Also clear the master in event if there's nothing to actually read.
  886. //
  887. if (IopTerminalGetOutputBufferSpace(Terminal) ==
  888. TERMINAL_OUTPUT_BUFFER_SIZE - 1) {
  889. IoSetIoObjectState(MasterIoState, POLL_EVENT_IN, FALSE);
  890. }
  891. }
  892. //
  893. // Make this terminal the controlling terminal for the process if
  894. // 1) The no controlling terminal flag is not set.
  895. // 2) The terminal is not already assigned to another session.
  896. // 3) This process is a session leader.
  897. // 4) This process does not already have a controlling terminal.
  898. //
  899. if (((IoHandle->OpenFlags & OPEN_FLAG_NO_CONTROLLING_TERMINAL) == 0) &&
  900. (Terminal->SessionId == TERMINAL_INVALID_SESSION) &&
  901. (PsIsSessionLeader(Process) != FALSE) &&
  902. (Process->ControllingTerminal == NULL)) {
  903. Process->ControllingTerminal = IoHandle;
  904. Terminal->ProcessGroupId = Process->Identifiers.ProcessGroupId;
  905. Terminal->SessionId = Process->Identifiers.SessionId;
  906. }
  907. Status = STATUS_SUCCESS;
  908. TerminalOpenSlaveEnd:
  909. if (TerminalLocksHeld != FALSE) {
  910. KeReleaseQueuedLock(Terminal->InputLock);
  911. KeReleaseQueuedLock(Terminal->OutputLock);
  912. }
  913. KeReleaseQueuedLock(IoTerminalListLock);
  914. return Status;
  915. }
  916. KSTATUS
  917. IopTerminalCloseSlave (
  918. PIO_HANDLE IoHandle
  919. )
  920. /*++
  921. Routine Description:
  922. This routine is called when a master terminal was just closed.
  923. Arguments:
  924. IoHandle - Supplies a pointer to the handle to close.
  925. Return Value:
  926. Status code.
  927. --*/
  928. {
  929. PFILE_OBJECT FileObject;
  930. PKPROCESS Process;
  931. PTERMINAL_SLAVE Slave;
  932. PTERMINAL Terminal;
  933. FileObject = IoHandle->FileObject;
  934. ASSERT(FileObject->Properties.Type == IoObjectTerminalSlave);
  935. //
  936. // Handles with no access never really counted and the special I/O object
  937. // may not have been initialized.
  938. //
  939. if (IoHandle->Access == 0) {
  940. return STATUS_SUCCESS;
  941. }
  942. Slave = FileObject->SpecialIo;
  943. ASSERT(Slave->Header.Type == ObjectTerminalSlave);
  944. Process = PsGetCurrentProcess();
  945. Terminal = Slave->Master;
  946. if (PsIsSessionLeader(Process) != FALSE) {
  947. KeAcquireQueuedLock(IoTerminalListLock);
  948. }
  949. KeAcquireQueuedLock(Terminal->OutputLock);
  950. KeAcquireQueuedLock(Terminal->InputLock);
  951. ASSERT(Terminal->SlaveHandles != 0);
  952. Terminal->SlaveHandles -= 1;
  953. //
  954. // Tell the master no one's listening.
  955. //
  956. if (Terminal->SlaveHandles == 0) {
  957. IoSetIoObjectState(Terminal->MasterFileObject->IoState,
  958. POLL_EVENT_IN | POLL_EVENT_DISCONNECTED,
  959. TRUE);
  960. }
  961. //
  962. // If this is a session leader closing its controlling terminal, then
  963. // disassociate the controlling terminal for the entire session.
  964. //
  965. if ((PsIsSessionLeader(Process) != FALSE) &&
  966. (IoHandle == Process->ControllingTerminal)) {
  967. //
  968. // If the session leader is dying, send a hangup signal to the
  969. // foreground process group.
  970. //
  971. if (Process->ThreadCount == 0) {
  972. PsSignalProcessGroup(Terminal->ProcessGroupId,
  973. SIGNAL_CONTROLLING_TERMINAL_CLOSED);
  974. }
  975. IopTerminalDisassociate(Terminal);
  976. ASSERT(Process->ControllingTerminal == NULL);
  977. }
  978. KeReleaseQueuedLock(Terminal->OutputLock);
  979. KeReleaseQueuedLock(Terminal->InputLock);
  980. if (PsIsSessionLeader(Process) != FALSE) {
  981. KeReleaseQueuedLock(IoTerminalListLock);
  982. }
  983. //
  984. // Release the reference on the master taken during opening, which may
  985. // allow the master to free itself.
  986. //
  987. ObReleaseReference(Slave->Master);
  988. IopFileObjectReleaseReference(Slave->Master->MasterFileObject);
  989. return STATUS_SUCCESS;
  990. }
  991. KSTATUS
  992. IopPerformTerminalMasterIoOperation (
  993. PIO_HANDLE Handle,
  994. PIO_CONTEXT IoContext
  995. )
  996. /*++
  997. Routine Description:
  998. This routine reads from or writes to the master end of a terminal.
  999. Arguments:
  1000. Handle - Supplies a pointer to the master terminal I/O handle.
  1001. IoContext - Supplies a pointer to the I/O context.
  1002. Return Value:
  1003. Status code. A failing status code does not necessarily mean no I/O made it
  1004. in or out. Check the bytes completed value in the I/O context to find out
  1005. how much occurred.
  1006. --*/
  1007. {
  1008. PFILE_OBJECT FileObject;
  1009. KSTATUS Status;
  1010. FileObject = Handle->FileObject;
  1011. ASSERT(IoContext->IoBuffer != NULL);
  1012. ASSERT(FileObject->Properties.Type == IoObjectTerminalMaster);
  1013. if (IoContext->Write != FALSE) {
  1014. Status = IopTerminalMasterWrite(FileObject, IoContext);
  1015. } else {
  1016. Status = IopTerminalMasterRead(FileObject, IoContext);
  1017. }
  1018. return Status;
  1019. }
  1020. KSTATUS
  1021. IopPerformTerminalSlaveIoOperation (
  1022. PIO_HANDLE Handle,
  1023. PIO_CONTEXT IoContext
  1024. )
  1025. /*++
  1026. Routine Description:
  1027. This routine reads from or writes to the slave end of a terminal.
  1028. Arguments:
  1029. Handle - Supplies a pointer to the slave terminal I/O handle.
  1030. IoContext - Supplies a pointer to the I/O context.
  1031. Return Value:
  1032. Status code. A failing status code does not necessarily mean no I/O made it
  1033. in or out. Check the bytes completed value in the I/O context to find out
  1034. how much occurred.
  1035. --*/
  1036. {
  1037. PFILE_OBJECT FileObject;
  1038. KSTATUS Status;
  1039. FileObject = Handle->FileObject;
  1040. ASSERT(IoContext->IoBuffer != NULL);
  1041. ASSERT(FileObject->Properties.Type == IoObjectTerminalSlave);
  1042. if (IoContext->Write != FALSE) {
  1043. Status = IopTerminalSlaveWrite(FileObject, IoContext);
  1044. } else {
  1045. Status = IopTerminalSlaveRead(FileObject, IoContext);
  1046. }
  1047. return Status;
  1048. }
  1049. KSTATUS
  1050. IopCreateTerminal (
  1051. IO_OBJECT_TYPE Type,
  1052. PVOID OverrideParameter,
  1053. FILE_PERMISSIONS CreatePermissions,
  1054. PFILE_OBJECT *FileObject
  1055. )
  1056. /*++
  1057. Routine Description:
  1058. This routine creates a terminal master or slave.
  1059. Arguments:
  1060. Type - Supplies the type of special object to create.
  1061. OverrideParameter - Supplies an optional parameter to send along with the
  1062. override type.
  1063. CreatePermissions - Supplies the permissions to assign to the new file.
  1064. FileObject - Supplies a pointer where a pointer to the new file object
  1065. will be returned on success.
  1066. Return Value:
  1067. Status code.
  1068. --*/
  1069. {
  1070. BOOL Created;
  1071. PTERMINAL_CREATION_PARAMETERS CreationParameters;
  1072. PLIST_ENTRY CurrentEntry;
  1073. BOOL ListLockHeld;
  1074. CHAR Name[TERMINAL_MAX_NAME_LENGTH];
  1075. ULONG NameLength;
  1076. PFILE_OBJECT NewFileObject;
  1077. ULONG Number;
  1078. FILE_PROPERTIES Properties;
  1079. KSTATUS Status;
  1080. PTERMINAL Terminal;
  1081. PTERMINAL TerminalAfter;
  1082. PLIST_ENTRY TerminalAfterEntry;
  1083. CreationParameters = OverrideParameter;
  1084. ListLockHeld = FALSE;
  1085. //
  1086. // If the object came up from out of the file system, don't actually
  1087. // create anything. The common case here is querying file properties.
  1088. //
  1089. if (CreationParameters == NULL) {
  1090. ASSERT(*FileObject != NULL);
  1091. Status = STATUS_SUCCESS;
  1092. goto CreateTerminalEnd;
  1093. }
  1094. NewFileObject = NULL;
  1095. //
  1096. // Create the slave file object.
  1097. //
  1098. if (Type == IoObjectTerminalSlave) {
  1099. ASSERT(CreationParameters->Master != NULL);
  1100. Terminal = CreationParameters->Master;
  1101. ASSERT(Terminal->SlaveFileObject == NULL);
  1102. //
  1103. // Create a new file object if there isn't one already.
  1104. //
  1105. if (*FileObject == NULL) {
  1106. IopFillOutFilePropertiesForObject(&Properties,
  1107. &(Terminal->Slave->Header));
  1108. Properties.Type = IoObjectTerminalSlave;
  1109. Properties.Permissions = CreatePermissions;
  1110. Status = IopCreateOrLookupFileObject(&Properties,
  1111. ObGetRootObject(),
  1112. 0,
  1113. &NewFileObject,
  1114. &Created);
  1115. if (!KSUCCESS(Status)) {
  1116. //
  1117. // Release the reference from when the properties were filled
  1118. // out above.
  1119. //
  1120. ObReleaseReference(Terminal->Slave);
  1121. goto CreateTerminalEnd;
  1122. }
  1123. ASSERT(Created != FALSE);
  1124. *FileObject = NewFileObject;
  1125. //
  1126. // With the file object created, but not yet ready, go ahead and
  1127. // name the terminal slave object. Once it has a name it can be
  1128. // found by other threads via path lookup, but those threads will
  1129. // have to wait on the file object's ready event before proceeding.
  1130. //
  1131. ASSERT(Terminal->Number != MAX_ULONG);
  1132. //
  1133. // Create the terminal name string (on the stack, it gets copied by
  1134. // the object manager) and then set the name in the object.
  1135. //
  1136. NameLength = RtlPrintToString(Name,
  1137. TERMINAL_MAX_NAME_LENGTH,
  1138. CharacterEncodingDefault,
  1139. TERMINAL_SLAVE_NAME_FORMAT,
  1140. Terminal->Number);
  1141. Status = ObNameObject(Terminal->Slave,
  1142. Name,
  1143. NameLength,
  1144. TERMINAL_ALLOCATION_TAG,
  1145. FALSE);
  1146. if (!KSUCCESS(Status)) {
  1147. ASSERT(Status != STATUS_TOO_LATE);
  1148. goto CreateTerminalEnd;
  1149. }
  1150. }
  1151. //
  1152. // Add a reference since the master holds a reference to the slave
  1153. // file object.
  1154. //
  1155. IopFileObjectAddReference(*FileObject);
  1156. //
  1157. // By setting the slave file object to non-null, this code is
  1158. // transferring the reference originally held by the master when the
  1159. // slave was created over to the file object special I/O field.
  1160. //
  1161. Terminal->SlaveFileObject = *FileObject;
  1162. ASSERT((*FileObject)->SpecialIo == NULL);
  1163. (*FileObject)->SpecialIo = Terminal->Slave;
  1164. //
  1165. // Create a master, which creates the slave object as well.
  1166. //
  1167. } else {
  1168. ASSERT(Type == IoObjectTerminalMaster);
  1169. ASSERT(CreationParameters->Master == NULL);
  1170. Terminal = NULL;
  1171. //
  1172. // Create the terminal object. This reference will get transferred to
  1173. // the file object special I/O field on success.
  1174. //
  1175. Status = IopCreateTerminalObject(
  1176. CreationParameters->SlaveCreatePermissions,
  1177. &Terminal);
  1178. if (!KSUCCESS(Status)) {
  1179. goto CreateTerminalEnd;
  1180. }
  1181. //
  1182. // Create a file object if necessary. This adds a reference on the
  1183. // object.
  1184. //
  1185. if (*FileObject == NULL) {
  1186. IopFillOutFilePropertiesForObject(&Properties, &(Terminal->Header));
  1187. Properties.Type = IoObjectTerminalMaster;
  1188. Properties.Permissions = CreatePermissions;
  1189. Status = IopCreateOrLookupFileObject(&Properties,
  1190. ObGetRootObject(),
  1191. 0,
  1192. &NewFileObject,
  1193. &Created);
  1194. if (!KSUCCESS(Status)) {
  1195. //
  1196. // Release both the references taken by creating the object and
  1197. // filling out the file properties.
  1198. //
  1199. ObReleaseReference(Terminal);
  1200. ObReleaseReference(Terminal);
  1201. goto CreateTerminalEnd;
  1202. }
  1203. ASSERT(Created != FALSE);
  1204. *FileObject = NewFileObject;
  1205. //
  1206. // With the file object created, but not yet ready, go ahead and
  1207. // name the terminal master object. Once it has a name it can be
  1208. // found by other threads via path lookup, but those threads will
  1209. // have to wait on the file object's ready event before proceeding.
  1210. //
  1211. Number = 0;
  1212. KeAcquireQueuedLock(IoTerminalListLock);
  1213. ListLockHeld = TRUE;
  1214. LIST_REMOVE(&(Terminal->ListEntry));
  1215. CurrentEntry = IoTerminalList.Next;
  1216. TerminalAfterEntry = &IoTerminalList;
  1217. while (CurrentEntry != &IoTerminalList) {
  1218. TerminalAfter = LIST_VALUE(CurrentEntry, TERMINAL, ListEntry);
  1219. //
  1220. // Assert that the list is in order.
  1221. //
  1222. ASSERT(TerminalAfter->Number >= Number);
  1223. if (TerminalAfter->Number == Number) {
  1224. Number += 1;
  1225. } else {
  1226. TerminalAfterEntry = CurrentEntry;
  1227. break;
  1228. }
  1229. CurrentEntry = CurrentEntry->Next;
  1230. }
  1231. //
  1232. // Create the terminal name string (on the stack, it gets copied by
  1233. // the object manager) and then set the name in the object.
  1234. //
  1235. NameLength = RtlPrintToString(Name,
  1236. TERMINAL_MAX_NAME_LENGTH,
  1237. CharacterEncodingDefault,
  1238. TERMINAL_MASTER_NAME_FORMAT,
  1239. Number);
  1240. Status = ObNameObject(Terminal,
  1241. Name,
  1242. NameLength,
  1243. TERMINAL_ALLOCATION_TAG,
  1244. FALSE);
  1245. if (!KSUCCESS(Status)) {
  1246. ASSERT(Status != STATUS_TOO_LATE);
  1247. goto CreateTerminalEnd;
  1248. }
  1249. ASSERT(Terminal->Number == MAX_ULONG);
  1250. Terminal->Number = Number;
  1251. INSERT_BEFORE(&(Terminal->ListEntry), TerminalAfterEntry);
  1252. KeReleaseQueuedLock(IoTerminalListLock);
  1253. ListLockHeld = FALSE;
  1254. }
  1255. ASSERT((*FileObject)->Properties.Type == IoObjectTerminalMaster);
  1256. Terminal->MasterFileObject = *FileObject;
  1257. CreationParameters->Master = Terminal;
  1258. ASSERT((*FileObject)->SpecialIo == NULL);
  1259. (*FileObject)->SpecialIo = Terminal;
  1260. }
  1261. Status = STATUS_SUCCESS;
  1262. CreateTerminalEnd:
  1263. if (ListLockHeld != FALSE) {
  1264. KeReleaseQueuedLock(IoTerminalListLock);
  1265. }
  1266. //
  1267. // On both success and failure, the file object's ready event needs to be
  1268. // signaled. Other threads may be waiting on the event.
  1269. //
  1270. if (*FileObject != NULL) {
  1271. ASSERT((KeGetEventState((*FileObject)->ReadyEvent) == NotSignaled) ||
  1272. (KeGetEventState((*FileObject)->ReadyEvent) ==
  1273. NotSignaledWithWaiters));
  1274. KeSignalEvent((*FileObject)->ReadyEvent, SignalOptionSignalAll);
  1275. }
  1276. return Status;
  1277. }
  1278. KSTATUS
  1279. IopUnlinkTerminal (
  1280. PFILE_OBJECT FileObject,
  1281. PBOOL Unlinked
  1282. )
  1283. /*++
  1284. Routine Description:
  1285. This routine unlinks a terminal from the accessible namespace.
  1286. Arguments:
  1287. FileObject - Supplies a pointer to the terminal's file object.
  1288. Unlinked - Supplies a pointer to a boolean that receives whether or not the
  1289. terminal was successfully unlinked.
  1290. Return Value:
  1291. Status code.
  1292. --*/
  1293. {
  1294. KSTATUS Status;
  1295. POBJECT_HEADER Terminal;
  1296. ASSERT((FileObject->Properties.Type == IoObjectTerminalMaster) ||
  1297. (FileObject->Properties.Type == IoObjectTerminalSlave));
  1298. ASSERT(KeIsSharedExclusiveLockHeldExclusive(FileObject->Lock) != FALSE);
  1299. Terminal = FileObject->SpecialIo;
  1300. ASSERT(Terminal != NULL);
  1301. *Unlinked = FALSE;
  1302. Status = ObUnlinkObject(Terminal);
  1303. if (KSUCCESS(Status)) {
  1304. *Unlinked = TRUE;
  1305. }
  1306. return Status;
  1307. }
  1308. KSTATUS
  1309. IopTerminalUserControl (
  1310. PIO_HANDLE Handle,
  1311. TERMINAL_USER_CONTROL_CODE CodeNumber,
  1312. BOOL FromKernelMode,
  1313. PVOID ContextBuffer,
  1314. UINTN ContextBufferSize
  1315. )
  1316. /*++
  1317. Routine Description:
  1318. This routine handles user control requests destined for a terminal object.
  1319. Arguments:
  1320. Handle - Supplies the open file handle.
  1321. CodeNumber - Supplies the minor code of the request.
  1322. FromKernelMode - Supplies a boolean indicating whether or not this request
  1323. (and the buffer associated with it) originates from user mode (FALSE)
  1324. or kernel mode (TRUE).
  1325. ContextBuffer - Supplies a pointer to the context buffer allocated by the
  1326. caller for the request.
  1327. ContextBufferSize - Supplies the size of the supplied context buffer.
  1328. Return Value:
  1329. Status code.
  1330. --*/
  1331. {
  1332. BOOL AcceptingSignal;
  1333. INT Argument;
  1334. IO_CONTEXT Context;
  1335. PROCESS_GROUP_ID CurrentProcessGroupId;
  1336. SESSION_ID CurrentSessionId;
  1337. PFILE_OBJECT FileObject;
  1338. KSTATUS HardwareStatus;
  1339. UINTN Index;
  1340. BOOL InSession;
  1341. IO_BUFFER IoBuffer;
  1342. ULONG IoBufferFlags;
  1343. INT ModemStatus;
  1344. TERMINAL_SETTINGS_OLD OldSettings;
  1345. PKPROCESS Process;
  1346. PROCESS_GROUP_ID ProcessGroupId;
  1347. INT QueueSize;
  1348. SESSION_ID SessionId;
  1349. TERMINAL_SETTINGS Settings;
  1350. KSTATUS Status;
  1351. PTERMINAL Terminal;
  1352. PTERMINAL_SLAVE TerminalSlave;
  1353. TERMINAL_CHANGE_BEHAVIOR When;
  1354. TERMINAL_WINDOW_SIZE WindowSize;
  1355. TerminalSlave = NULL;
  1356. FileObject = Handle->FileObject;
  1357. if (FileObject->Properties.Type == IoObjectTerminalMaster) {
  1358. Terminal = FileObject->SpecialIo;
  1359. } else if (FileObject->Properties.Type == IoObjectTerminalSlave) {
  1360. TerminalSlave = FileObject->SpecialIo;
  1361. Terminal = TerminalSlave->Master;
  1362. } else {
  1363. return STATUS_NOT_A_TERMINAL;
  1364. }
  1365. switch (CodeNumber) {
  1366. case TerminalControlGetAttributes:
  1367. Status = IoSetTerminalSettings(Handle,
  1368. NULL,
  1369. &Settings,
  1370. TerminalChangeNone);
  1371. if (!KSUCCESS(Status)) {
  1372. break;
  1373. }
  1374. Status = IopTerminalUserBufferCopy(FromKernelMode,
  1375. FALSE,
  1376. ContextBuffer,
  1377. &Settings,
  1378. sizeof(TERMINAL_SETTINGS));
  1379. break;
  1380. case TerminalControlSetAttributes:
  1381. case TerminalControlSetAttributesDrain:
  1382. case TerminalControlSetAttributesFlush:
  1383. if (CodeNumber == TerminalControlSetAttributes) {
  1384. When = TerminalChangeNow;
  1385. } else if (CodeNumber == TerminalControlSetAttributesDrain) {
  1386. When = TerminalChangeAfterOutput;
  1387. } else {
  1388. ASSERT(CodeNumber == TerminalControlSetAttributesFlush);
  1389. When = TerminalChangeAfterOutputFlushInput;
  1390. }
  1391. Status = IopTerminalUserBufferCopy(FromKernelMode,
  1392. TRUE,
  1393. ContextBuffer,
  1394. &Settings,
  1395. sizeof(TERMINAL_SETTINGS));
  1396. if (!KSUCCESS(Status)) {
  1397. break;
  1398. }
  1399. Status = IoSetTerminalSettings(Handle, &Settings, NULL, When);
  1400. break;
  1401. case TerminalControlGetAttributesOld:
  1402. Status = IoSetTerminalSettings(Handle,
  1403. NULL,
  1404. &Settings,
  1405. TerminalChangeNone);
  1406. if (!KSUCCESS(Status)) {
  1407. break;
  1408. }
  1409. RtlZeroMemory(&OldSettings, sizeof(TERMINAL_SETTINGS_OLD));
  1410. OldSettings.InputFlags = Settings.InputFlags;
  1411. OldSettings.OutputFlags = Settings.OutputFlags;
  1412. OldSettings.ControlFlags = Settings.ControlFlags;
  1413. OldSettings.LocalFlags = Settings.LocalFlags;
  1414. OldSettings.LineDiscipline = 0;
  1415. for (Index = 0;
  1416. Index < TERMINAL_SETTINGS_OLD_CONTROL_COUNT;
  1417. Index += 1) {
  1418. OldSettings.ControlCharacters[Index] =
  1419. Settings.ControlCharacters[Index];
  1420. }
  1421. Status = IopTerminalUserBufferCopy(FromKernelMode,
  1422. FALSE,
  1423. ContextBuffer,
  1424. &OldSettings,
  1425. sizeof(TERMINAL_SETTINGS_OLD));
  1426. break;
  1427. case TerminalControlSetAttributesOld:
  1428. case TerminalControlSetAttributesDrainOld:
  1429. case TerminalControlSetAttributesFlushOld:
  1430. if (CodeNumber == TerminalControlSetAttributesOld) {
  1431. When = TerminalChangeNow;
  1432. } else if (CodeNumber == TerminalControlSetAttributesDrainOld) {
  1433. When = TerminalChangeAfterOutput;
  1434. } else {
  1435. ASSERT(CodeNumber == TerminalControlSetAttributesFlushOld);
  1436. When = TerminalChangeAfterOutputFlushInput;
  1437. }
  1438. Status = IopTerminalUserBufferCopy(FromKernelMode,
  1439. TRUE,
  1440. ContextBuffer,
  1441. &OldSettings,
  1442. sizeof(TERMINAL_SETTINGS_OLD));
  1443. if (!KSUCCESS(Status)) {
  1444. break;
  1445. }
  1446. //
  1447. // Get the current settings, and copy the old to the new.
  1448. //
  1449. Status = IoSetTerminalSettings(Handle,
  1450. NULL,
  1451. &Settings,
  1452. TerminalChangeNone);
  1453. if (!KSUCCESS(Status)) {
  1454. break;
  1455. }
  1456. Settings.InputFlags = OldSettings.InputFlags;
  1457. Settings.OutputFlags = OldSettings.OutputFlags;
  1458. Settings.ControlFlags = OldSettings.ControlFlags;
  1459. Settings.LocalFlags = OldSettings.LocalFlags;
  1460. for (Index = 0;
  1461. Index < TERMINAL_SETTINGS_OLD_CONTROL_COUNT;
  1462. Index += 1) {
  1463. Settings.ControlCharacters[Index] =
  1464. OldSettings.ControlCharacters[Index];
  1465. }
  1466. //
  1467. // Set the new settings.
  1468. //
  1469. Status = IoSetTerminalSettings(Handle, &Settings, NULL, When);
  1470. break;
  1471. case TerminalControlSendBreak:
  1472. //
  1473. // The integer argument is the pointer itself.
  1474. //
  1475. Argument = (UINTN)ContextBuffer;
  1476. if (Argument == 0) {
  1477. Status = STATUS_SUCCESS;
  1478. } else {
  1479. //
  1480. // A non-zero argument is undefined. Act like "drain" here, and
  1481. // wait for all output to complete.
  1482. //
  1483. Status = IopTerminalFlush(FileObject, FLUSH_FLAG_WRITE);
  1484. }
  1485. break;
  1486. case TerminalControlFlowControl:
  1487. Status = STATUS_SUCCESS;
  1488. break;
  1489. case TerminalControlFlush:
  1490. //
  1491. // The argument is an integer.
  1492. //
  1493. Argument = (UINTN)ContextBuffer;
  1494. Argument &= FLUSH_FLAG_READ | FLUSH_FLAG_WRITE;
  1495. Argument |= FLUSH_FLAG_DISCARD;
  1496. Status = IopTerminalFlush(FileObject, Argument);
  1497. break;
  1498. case TerminalControlSetExclusive:
  1499. case TerminalControlClearExclusive:
  1500. KeAcquireQueuedLock(Terminal->OutputLock);
  1501. KeAcquireQueuedLock(Terminal->InputLock);
  1502. if (CodeNumber == TerminalControlSetExclusive) {
  1503. Terminal->Flags |= TERMINAL_FLAG_FAIL_OPENS;
  1504. } else {
  1505. Terminal->Flags &= ~TERMINAL_FLAG_FAIL_OPENS;
  1506. }
  1507. KeReleaseQueuedLock(Terminal->InputLock);
  1508. KeReleaseQueuedLock(Terminal->OutputLock);
  1509. Status = STATUS_SUCCESS;
  1510. break;
  1511. case TerminalControlGetOutputQueueSize:
  1512. case TerminalControlGetInputQueueSize:
  1513. KeAcquireQueuedLock(Terminal->OutputLock);
  1514. KeAcquireQueuedLock(Terminal->InputLock);
  1515. if (CodeNumber == TerminalControlGetOutputQueueSize) {
  1516. QueueSize = IopTerminalGetOutputBufferSpace(Terminal) -
  1517. TERMINAL_OUTPUT_BUFFER_SIZE;
  1518. } else {
  1519. QueueSize = IopTerminalGetInputBufferSpace(Terminal) -
  1520. TERMINAL_INPUT_BUFFER_SIZE;
  1521. }
  1522. KeReleaseQueuedLock(Terminal->InputLock);
  1523. KeReleaseQueuedLock(Terminal->OutputLock);
  1524. Status = IopTerminalUserBufferCopy(FromKernelMode,
  1525. FALSE,
  1526. ContextBuffer,
  1527. &QueueSize,
  1528. sizeof(INT));
  1529. break;
  1530. case TerminalControlInsertInInputQueue:
  1531. IoBufferFlags = 0;
  1532. if (FromKernelMode != FALSE) {
  1533. IoBufferFlags |= IO_BUFFER_FLAG_KERNEL_MODE_DATA;
  1534. }
  1535. Status = MmInitializeIoBuffer(&IoBuffer,
  1536. ContextBuffer,
  1537. INVALID_PHYSICAL_ADDRESS,
  1538. 1,
  1539. IoBufferFlags);
  1540. if (!KSUCCESS(Status)) {
  1541. break;
  1542. }
  1543. Context.IoBuffer = &IoBuffer;
  1544. Context.SizeInBytes = 1;
  1545. Context.Flags = 0;
  1546. Context.TimeoutInMilliseconds = WAIT_TIME_INDEFINITE;
  1547. Status = IopTerminalMasterWrite(Terminal->MasterFileObject, &Context);
  1548. break;
  1549. case TerminalControlGetWindowSize:
  1550. KeAcquireQueuedLock(Terminal->OutputLock);
  1551. RtlCopyMemory(&WindowSize,
  1552. &(Terminal->WindowSize),
  1553. sizeof(TERMINAL_WINDOW_SIZE));
  1554. KeReleaseQueuedLock(Terminal->OutputLock);
  1555. Status = IopTerminalUserBufferCopy(FromKernelMode,
  1556. FALSE,
  1557. ContextBuffer,
  1558. &WindowSize,
  1559. sizeof(TERMINAL_WINDOW_SIZE));
  1560. break;
  1561. case TerminalControlSetWindowSize:
  1562. Status = IopTerminalUserBufferCopy(FromKernelMode,
  1563. TRUE,
  1564. ContextBuffer,
  1565. &WindowSize,
  1566. sizeof(TERMINAL_WINDOW_SIZE));
  1567. if (!KSUCCESS(Status)) {
  1568. break;
  1569. }
  1570. KeAcquireQueuedLock(Terminal->OutputLock);
  1571. RtlCopyMemory(&(Terminal->WindowSize),
  1572. &WindowSize,
  1573. sizeof(TERMINAL_WINDOW_SIZE));
  1574. KeReleaseQueuedLock(Terminal->OutputLock);
  1575. break;
  1576. case TerminalControlGetModemStatus:
  1577. case TerminalControlOrModemStatus:
  1578. case TerminalControlClearModemStatus:
  1579. case TerminalControlSetModemStatus:
  1580. Status = IopTerminalUserBufferCopy(FromKernelMode,
  1581. TRUE,
  1582. ContextBuffer,
  1583. &ModemStatus,
  1584. sizeof(INT));
  1585. if (!KSUCCESS(Status)) {
  1586. break;
  1587. }
  1588. KeAcquireQueuedLock(Terminal->OutputLock);
  1589. if (CodeNumber == TerminalControlOrModemStatus) {
  1590. Terminal->ModemStatus |= ModemStatus;
  1591. } else if (CodeNumber == TerminalControlClearModemStatus) {
  1592. Terminal->ModemStatus &= ~ModemStatus;
  1593. } else if (CodeNumber == TerminalControlSetModemStatus) {
  1594. Terminal->ModemStatus = ModemStatus;
  1595. }
  1596. ModemStatus = Terminal->ModemStatus;
  1597. KeReleaseQueuedLock(Terminal->OutputLock);
  1598. Status = IopTerminalUserBufferCopy(FromKernelMode,
  1599. FALSE,
  1600. ContextBuffer,
  1601. &ModemStatus,
  1602. sizeof(INT));
  1603. break;
  1604. case TerminalControlGetSoftCarrier:
  1605. case TerminalControlSetSoftCarrier:
  1606. Status = IopTerminalUserBufferCopy(FromKernelMode,
  1607. TRUE,
  1608. ContextBuffer,
  1609. &Argument,
  1610. sizeof(INT));
  1611. if (!KSUCCESS(Status)) {
  1612. break;
  1613. }
  1614. KeAcquireQueuedLock(Terminal->OutputLock);
  1615. KeAcquireQueuedLock(Terminal->InputLock);
  1616. if (CodeNumber == TerminalControlSetSoftCarrier) {
  1617. Terminal->ModemStatus |= ModemStatus;
  1618. if (Argument != 0) {
  1619. Terminal->Settings.ControlFlags |= TERMINAL_CONTROL_NO_HANGUP;
  1620. } else {
  1621. Terminal->Settings.ControlFlags &= ~TERMINAL_CONTROL_NO_HANGUP;
  1622. }
  1623. }
  1624. Argument = FALSE;
  1625. if ((Terminal->Settings.ControlFlags & TERMINAL_CONTROL_NO_HANGUP) !=
  1626. 0) {
  1627. Argument = TRUE;
  1628. }
  1629. KeReleaseQueuedLock(Terminal->InputLock);
  1630. KeReleaseQueuedLock(Terminal->OutputLock);
  1631. Status = IopTerminalUserBufferCopy(FromKernelMode,
  1632. FALSE,
  1633. ContextBuffer,
  1634. &Argument,
  1635. sizeof(INT));
  1636. break;
  1637. case TerminalControlGetProcessGroup:
  1638. //
  1639. // The given terminal must be the controlling terminal of the calling
  1640. // process.
  1641. //
  1642. PsGetProcessGroup(NULL, &CurrentProcessGroupId, &CurrentSessionId);
  1643. Status = STATUS_SUCCESS;
  1644. KeAcquireQueuedLock(Terminal->OutputLock);
  1645. KeAcquireQueuedLock(Terminal->InputLock);
  1646. if (Terminal->SessionId != CurrentSessionId) {
  1647. Status = STATUS_NOT_A_TERMINAL;
  1648. } else {
  1649. ProcessGroupId = Terminal->ProcessGroupId;
  1650. }
  1651. KeReleaseQueuedLock(Terminal->InputLock);
  1652. KeReleaseQueuedLock(Terminal->OutputLock);
  1653. if (!KSUCCESS(Status)) {
  1654. break;
  1655. }
  1656. Status = IopTerminalUserBufferCopy(FromKernelMode,
  1657. FALSE,
  1658. ContextBuffer,
  1659. &ProcessGroupId,
  1660. sizeof(PROCESS_GROUP_ID));
  1661. break;
  1662. case TerminalControlSetProcessGroup:
  1663. Status = IopTerminalUserBufferCopy(FromKernelMode,
  1664. TRUE,
  1665. ContextBuffer,
  1666. &ProcessGroupId,
  1667. sizeof(PROCESS_GROUP_ID));
  1668. if (!KSUCCESS(Status)) {
  1669. break;
  1670. }
  1671. //
  1672. // If the terminal does not have the slave side attached or does not
  1673. // belong to the calling session, then the process does not have
  1674. // permission to update its process group.
  1675. //
  1676. PsGetProcessGroup(NULL, &CurrentProcessGroupId, &CurrentSessionId);
  1677. //
  1678. // The given terminal must be in the current session.
  1679. //
  1680. InSession = PsIsProcessGroupInSession(ProcessGroupId, CurrentSessionId);
  1681. if (InSession == FALSE) {
  1682. Status = STATUS_PERMISSION_DENIED;
  1683. break;
  1684. }
  1685. AcceptingSignal = FALSE;
  1686. KeAcquireQueuedLock(Terminal->OutputLock);
  1687. KeAcquireQueuedLock(Terminal->InputLock);
  1688. if (Terminal->SessionId != CurrentSessionId) {
  1689. Status = STATUS_NOT_A_TERMINAL;
  1690. //
  1691. // If the calling process is not in the owning (foreground) process
  1692. // group, then it is sent a signal unless it is blocking or ignoring
  1693. // the background terminal output signal.
  1694. //
  1695. } else {
  1696. if (CurrentProcessGroupId != Terminal->ProcessGroupId) {
  1697. AcceptingSignal = PsIsThreadAcceptingSignal(
  1698. NULL,
  1699. SIGNAL_BACKGROUND_TERMINAL_OUTPUT);
  1700. }
  1701. //
  1702. // If the process is not accepting signals or the signal did not
  1703. // need to be checked, then the process group is free to change.
  1704. //
  1705. if (AcceptingSignal == FALSE) {
  1706. Terminal->ProcessGroupId = ProcessGroupId;
  1707. Status = STATUS_SUCCESS;
  1708. }
  1709. }
  1710. KeReleaseQueuedLock(Terminal->InputLock);
  1711. KeReleaseQueuedLock(Terminal->OutputLock);
  1712. //
  1713. // If the process is accepting the signal checked above, send it and
  1714. // tell the caller to try again later. If it's not accepting it, just
  1715. // let it go through.
  1716. //
  1717. if (AcceptingSignal != FALSE) {
  1718. PsSignalProcessGroup(CurrentProcessGroupId,
  1719. SIGNAL_BACKGROUND_TERMINAL_OUTPUT);
  1720. Status = STATUS_TRY_AGAIN;
  1721. }
  1722. break;
  1723. case TerminalControlSetControllingTerminal:
  1724. Argument = (UINTN)ContextBuffer;
  1725. Process = PsGetCurrentProcess();
  1726. //
  1727. // If this process is not a session leader or it has a controlling
  1728. // terminal already, fail.
  1729. //
  1730. if ((PsIsSessionLeader(Process) == FALSE) ||
  1731. (Process->ControllingTerminal != NULL)) {
  1732. Status = STATUS_PERMISSION_DENIED;
  1733. }
  1734. //
  1735. // If this handle is only open for write and the caller isn't an
  1736. // administrator, fail.
  1737. //
  1738. if ((Handle->Access & IO_ACCESS_READ) == 0) {
  1739. Status = PsCheckPermission(PERMISSION_SYSTEM_ADMINISTRATOR);
  1740. if (!KSUCCESS(Status)) {
  1741. break;
  1742. }
  1743. }
  1744. //
  1745. // If the terminal already belongs to a different session, then it
  1746. // cannot bet set as the controlling terminal of this session unless
  1747. // the caller is root and the argument is 1.
  1748. //
  1749. SessionId = Terminal->SessionId;
  1750. CurrentSessionId = Process->Identifiers.SessionId;
  1751. if (SessionId != TERMINAL_INVALID_SESSION) {
  1752. if (SessionId == CurrentSessionId) {
  1753. Status = STATUS_SUCCESS;
  1754. break;
  1755. }
  1756. //
  1757. // Allow root to steal terminals from different session if the
  1758. // argument is non-zero.
  1759. //
  1760. Status = PsCheckPermission(PERMISSION_SYSTEM_ADMINISTRATOR);
  1761. if ((!KSUCCESS(Status)) || (Argument == 0)) {
  1762. Status = STATUS_PERMISSION_DENIED;
  1763. break;
  1764. }
  1765. }
  1766. KeAcquireQueuedLock(IoTerminalListLock);
  1767. KeAcquireQueuedLock(Terminal->OutputLock);
  1768. KeAcquireQueuedLock(Terminal->InputLock);
  1769. //
  1770. // Double check the controlling terminal now that the terminal list
  1771. // lock protecting it is held.
  1772. //
  1773. if (Process->ControllingTerminal != NULL) {
  1774. Status = STATUS_PERMISSION_DENIED;
  1775. //
  1776. // If the session changed between the unlocked check and now, fail.
  1777. //
  1778. } else if (Terminal->SessionId != SessionId) {
  1779. Status = STATUS_TRY_AGAIN;
  1780. //
  1781. // Everyone that had the terminal as their controlling terminal no
  1782. // longer does.
  1783. //
  1784. } else {
  1785. IopTerminalDisassociate(Terminal);
  1786. Process->ControllingTerminal = Handle;
  1787. Terminal->SessionId = CurrentSessionId;
  1788. Terminal->ProcessGroupId = Process->Identifiers.ProcessGroupId;
  1789. }
  1790. KeReleaseQueuedLock(Terminal->InputLock);
  1791. KeReleaseQueuedLock(Terminal->OutputLock);
  1792. KeReleaseQueuedLock(IoTerminalListLock);
  1793. break;
  1794. case TerminalControlGetCurrentSessionId:
  1795. if (FileObject->Properties.Type != IoObjectTerminalMaster) {
  1796. Status = STATUS_NOT_A_TERMINAL;
  1797. break;
  1798. }
  1799. //
  1800. // The given terminal must be the controlling terminal of the calling
  1801. // process.
  1802. //
  1803. Process = PsGetCurrentProcess();
  1804. KeAcquireQueuedLock(Terminal->OutputLock);
  1805. KeAcquireQueuedLock(Terminal->InputLock);
  1806. if (Terminal->SessionId != CurrentSessionId) {
  1807. Status = STATUS_NOT_A_TERMINAL;
  1808. } else {
  1809. SessionId = Terminal->SessionId;
  1810. Status = STATUS_SUCCESS;
  1811. }
  1812. KeReleaseQueuedLock(Terminal->InputLock);
  1813. KeReleaseQueuedLock(Terminal->OutputLock);
  1814. if (!KSUCCESS(Status)) {
  1815. break;
  1816. }
  1817. Status = IopTerminalUserBufferCopy(FromKernelMode,
  1818. FALSE,
  1819. ContextBuffer,
  1820. &SessionId,
  1821. sizeof(SESSION_ID));
  1822. break;
  1823. case TerminalControlGiveUpControllingTerminal:
  1824. Process = PsGetCurrentProcess();
  1825. //
  1826. // The controlling terminal is protected by the terminal list lock.
  1827. //
  1828. KeAcquireQueuedLock(IoTerminalListLock);
  1829. KeAcquireQueuedLock(Terminal->OutputLock);
  1830. KeAcquireQueuedLock(Terminal->InputLock);
  1831. if (Process->ControllingTerminal != Handle) {
  1832. Status = STATUS_NOT_A_TERMINAL;
  1833. } else {
  1834. Status = STATUS_SUCCESS;
  1835. if (PsIsSessionLeader(Process) != FALSE) {
  1836. PsSignalProcessGroup(Terminal->ProcessGroupId,
  1837. SIGNAL_CONTROLLING_TERMINAL_CLOSED);
  1838. PsSignalProcessGroup(Terminal->ProcessGroupId,
  1839. SIGNAL_CONTINUE);
  1840. IopTerminalDisassociate(Terminal);
  1841. }
  1842. }
  1843. KeReleaseQueuedLock(Terminal->InputLock);
  1844. KeReleaseQueuedLock(Terminal->OutputLock);
  1845. KeReleaseQueuedLock(IoTerminalListLock);
  1846. break;
  1847. case TerminalControlRedirectLocalConsole:
  1848. case TerminalControlSetPacketMode:
  1849. ASSERT(FALSE);
  1850. Status = STATUS_NOT_IMPLEMENTED;
  1851. break;
  1852. case TerminalControlSendBreakPosix:
  1853. case TerminalControlStartBreak:
  1854. case TerminalControlStopBreak:
  1855. Status = STATUS_SUCCESS;
  1856. break;
  1857. default:
  1858. Status = STATUS_NOT_SUPPORTED;
  1859. break;
  1860. }
  1861. //
  1862. // Also forward the request on to the physical device if there is one.
  1863. //
  1864. if ((KSUCCESS(Status)) && (Terminal->HardwareHandle != NULL)) {
  1865. HardwareStatus = IoUserControl(Terminal->HardwareHandle,
  1866. CodeNumber,
  1867. FromKernelMode,
  1868. ContextBuffer,
  1869. ContextBufferSize);
  1870. if (HardwareStatus != STATUS_NOT_HANDLED) {
  1871. Status = HardwareStatus;
  1872. }
  1873. }
  1874. return Status;
  1875. }
  1876. KSTATUS
  1877. IopTerminalFlush (
  1878. PFILE_OBJECT FileObject,
  1879. ULONG Flags
  1880. )
  1881. /*++
  1882. Routine Description:
  1883. This routine flushes a terminal object, discarding unwritten and unread
  1884. data.
  1885. Arguments:
  1886. FileObject - Supplies a pointer to the terminal to flush.
  1887. Flags - Supplies the flags governing the flush operation. See FLUSH_FLAG_*
  1888. definitions.
  1889. Return Value:
  1890. Status code.
  1891. --*/
  1892. {
  1893. BOOL AcceptingSignal;
  1894. PIO_OBJECT_STATE MasterIoState;
  1895. PROCESS_GROUP_ID ProcessGroup;
  1896. SESSION_ID Session;
  1897. PTERMINAL_SLAVE Slave;
  1898. PIO_OBJECT_STATE SlaveIoState;
  1899. KSTATUS Status;
  1900. PTERMINAL Terminal;
  1901. if (FileObject->Properties.Type == IoObjectTerminalSlave) {
  1902. Slave = FileObject->SpecialIo;
  1903. Terminal = NULL;
  1904. ASSERT(Slave->Header.Type == ObjectTerminalSlave);
  1905. Terminal = Slave->Master;
  1906. if (IO_IS_TERMINAL_MASTER_OPEN(Terminal) == FALSE) {
  1907. Status = STATUS_END_OF_FILE;
  1908. goto TerminalFlushEnd;
  1909. }
  1910. } else {
  1911. Terminal = FileObject->SpecialIo;
  1912. }
  1913. if (Terminal->SlaveFileObject == NULL) {
  1914. Status = STATUS_NOT_FOUND;
  1915. goto TerminalFlushEnd;
  1916. }
  1917. SlaveIoState = Terminal->SlaveFileObject->IoState;
  1918. MasterIoState = Terminal->MasterFileObject->IoState;
  1919. PsGetProcessGroup(NULL, &ProcessGroup, &Session);
  1920. if (Terminal->SlaveHandles == 0) {
  1921. Status = STATUS_NOT_READY;
  1922. goto TerminalFlushEnd;
  1923. }
  1924. //
  1925. // If the flushing process is not in the same process group, send the
  1926. // process group a signal unless the flushing process is ignoring or
  1927. // blocking that signal.
  1928. //
  1929. if ((ProcessGroup != Terminal->ProcessGroupId) &&
  1930. ((Terminal->Settings.LocalFlags &
  1931. TERMINAL_LOCAL_STOP_BACKGROUND_WRITES) != 0)) {
  1932. AcceptingSignal = PsIsThreadAcceptingSignal(
  1933. NULL,
  1934. SIGNAL_BACKGROUND_TERMINAL_OUTPUT);
  1935. //
  1936. // If the process is accepting that signal, send it to it and tell it
  1937. // to try again later. The exception is an orphaned process group, in
  1938. // which case an error is returned. If the process is not accepting the
  1939. // signal, just let the flush go through.
  1940. //
  1941. if (AcceptingSignal != FALSE) {
  1942. if (PsIsProcessGroupOrphaned(ProcessGroup) != FALSE) {
  1943. Status = STATUS_DEVICE_IO_ERROR;
  1944. } else {
  1945. PsSignalProcessGroup(ProcessGroup,
  1946. SIGNAL_BACKGROUND_TERMINAL_OUTPUT);
  1947. Status = STATUS_TRY_AGAIN;
  1948. }
  1949. goto TerminalFlushEnd;
  1950. }
  1951. }
  1952. //
  1953. // If discarding, reset the buffers.
  1954. //
  1955. if ((Flags & FLUSH_FLAG_DISCARD) != 0) {
  1956. if ((Flags & FLUSH_FLAG_READ) != 0) {
  1957. KeAcquireQueuedLock(Terminal->InputLock);
  1958. Terminal->InputBufferStart = 0;
  1959. Terminal->InputBufferEnd = 0;
  1960. IoSetIoObjectState(MasterIoState, POLL_EVENT_OUT, TRUE);
  1961. IoSetIoObjectState(SlaveIoState, POLL_EVENT_IN, FALSE);
  1962. Terminal->WorkingInputCursor = 0;
  1963. Terminal->WorkingInputLength = 0;
  1964. KeReleaseQueuedLock(Terminal->InputLock);
  1965. }
  1966. if ((Flags & FLUSH_FLAG_WRITE) != 0) {
  1967. KeAcquireQueuedLock(Terminal->OutputLock);
  1968. Terminal->OutputBufferStart = 0;
  1969. Terminal->OutputBufferEnd = 0;
  1970. IoSetIoObjectState(MasterIoState, POLL_EVENT_IN, FALSE);
  1971. IoSetIoObjectState(SlaveIoState, POLL_EVENT_OUT, TRUE);
  1972. KeReleaseQueuedLock(Terminal->OutputLock);
  1973. }
  1974. //
  1975. // If draining, wait for the output to go through.
  1976. //
  1977. } else {
  1978. //
  1979. // It doesn't make sense for the caller to try to flush a read, as
  1980. // they're the ones that need to flush.
  1981. //
  1982. if ((Flags & FLUSH_FLAG_READ) != 0) {
  1983. Status = STATUS_INVALID_PARAMETER;
  1984. goto TerminalFlushEnd;
  1985. }
  1986. //
  1987. // Wait for the write buffer to become empty.
  1988. //
  1989. if ((Flags & FLUSH_FLAG_WRITE) != 0) {
  1990. Status = STATUS_SUCCESS;
  1991. while (KSUCCESS(Status)) {
  1992. KeAcquireQueuedLock(Terminal->OutputLock);
  1993. //
  1994. // If the output is empty, then hooray, it's done.
  1995. //
  1996. if (Terminal->OutputBufferStart == Terminal->OutputBufferEnd) {
  1997. KeReleaseQueuedLock(Terminal->OutputLock);
  1998. break;
  1999. }
  2000. //
  2001. // Hijack the out event and unsignal it. When the master reads
  2002. // the data, it will signal it again.
  2003. //
  2004. IoSetIoObjectState(SlaveIoState, POLL_EVENT_OUT, FALSE);
  2005. KeReleaseQueuedLock(Terminal->OutputLock);
  2006. Status = KeWaitForEvent(SlaveIoState->WriteEvent,
  2007. TRUE,
  2008. WAIT_TIME_INDEFINITE);
  2009. }
  2010. if (!KSUCCESS(Status)) {
  2011. goto TerminalFlushEnd;
  2012. }
  2013. }
  2014. }
  2015. Status = STATUS_SUCCESS;
  2016. TerminalFlushEnd:
  2017. return Status;
  2018. }
  2019. //
  2020. // --------------------------------------------------------- Internal Functions
  2021. //
  2022. KSTATUS
  2023. IopCreateTerminalObject (
  2024. FILE_PERMISSIONS CreatePermissions,
  2025. PTERMINAL *NewTerminal
  2026. )
  2027. /*++
  2028. Routine Description:
  2029. This routine creates a new terminal object.
  2030. Arguments:
  2031. CreatePermissions - Supplies the initial permissions to set on the slave
  2032. file object.
  2033. NewTerminal - Supplies a pointer where a pointer to a new terminal will be
  2034. returned on success.
  2035. Return Value:
  2036. Status code.
  2037. --*/
  2038. {
  2039. PCHAR ControlCharacters;
  2040. PTERMINAL_SLAVE Slave;
  2041. KSTATUS Status;
  2042. PTERMINAL Terminal;
  2043. //
  2044. // Create the terminal object. This references goes to the special I/O
  2045. // member of the file object on success.
  2046. //
  2047. Terminal = ObCreateObject(ObjectTerminalMaster,
  2048. IoTerminalDirectory,
  2049. NULL,
  2050. 0,
  2051. sizeof(TERMINAL),
  2052. IopDestroyTerminal,
  2053. 0,
  2054. TERMINAL_ALLOCATION_TAG);
  2055. if (Terminal == NULL) {
  2056. Status = STATUS_INSUFFICIENT_RESOURCES;
  2057. goto CreateTerminalObjectEnd;
  2058. }
  2059. //
  2060. // Initialize the terminal with an invalid number. The number is only used
  2061. // by terminals that are named in the terminal directory. Naming a terminal
  2062. // happens later with the appropriate synchronization.
  2063. //
  2064. Terminal->Number = MAX_ULONG;
  2065. //
  2066. // Set the master reference count to 1. This helps determine when the
  2067. // master is last closed by preventing new opens from succeeding if the
  2068. // master's reference goes to 0.
  2069. //
  2070. Terminal->MasterReferenceCount = 1;
  2071. //
  2072. // Allocate the input buffers.
  2073. //
  2074. Terminal->InputBuffer = MmAllocatePagedPool(TERMINAL_INPUT_BUFFER_SIZE,
  2075. TERMINAL_ALLOCATION_TAG);
  2076. if (Terminal->InputBuffer == NULL) {
  2077. Status = STATUS_INSUFFICIENT_RESOURCES;
  2078. goto CreateTerminalObjectEnd;
  2079. }
  2080. RtlZeroMemory(Terminal->InputBuffer, TERMINAL_INPUT_BUFFER_SIZE);
  2081. Terminal->WorkingInputBuffer = MmAllocatePagedPool(
  2082. TERMINAL_CANONICAL_BUFFER_SIZE,
  2083. TERMINAL_ALLOCATION_TAG);
  2084. if (Terminal->WorkingInputBuffer == NULL) {
  2085. Status = STATUS_INSUFFICIENT_RESOURCES;
  2086. goto CreateTerminalObjectEnd;
  2087. }
  2088. Terminal->InputLock = KeCreateQueuedLock();
  2089. if (Terminal->InputLock == NULL) {
  2090. Status = STATUS_INSUFFICIENT_RESOURCES;
  2091. goto CreateTerminalObjectEnd;
  2092. }
  2093. //
  2094. // Allocate the output buffers.
  2095. //
  2096. Terminal->OutputBuffer = MmAllocatePagedPool(TERMINAL_OUTPUT_BUFFER_SIZE,
  2097. TERMINAL_ALLOCATION_TAG);
  2098. if (Terminal->OutputBuffer == NULL) {
  2099. Status = STATUS_INSUFFICIENT_RESOURCES;
  2100. goto CreateTerminalObjectEnd;
  2101. }
  2102. Terminal->OutputLock = KeCreateQueuedLock();
  2103. if (Terminal->OutputLock == NULL) {
  2104. Status = STATUS_INSUFFICIENT_RESOURCES;
  2105. goto CreateTerminalObjectEnd;
  2106. }
  2107. //
  2108. // Set some default flags.
  2109. //
  2110. Terminal->Settings.LocalFlags = TERMINAL_LOCAL_ECHO |
  2111. TERMINAL_LOCAL_ECHO_ERASE |
  2112. TERMINAL_LOCAL_ECHO_KILL_NEWLINE |
  2113. TERMINAL_LOCAL_ECHO_KILL_EXTENDED |
  2114. TERMINAL_LOCAL_ECHO_NEWLINE |
  2115. TERMINAL_LOCAL_ECHO_CONTROL |
  2116. TERMINAL_LOCAL_CANONICAL |
  2117. TERMINAL_LOCAL_SIGNALS;
  2118. Terminal->Settings.InputFlags = TERMINAL_INPUT_CR_TO_NEWLINE;
  2119. Terminal->Settings.OutputFlags = TERMINAL_OUTPUT_POST_PROCESS |
  2120. TERMINAL_OUTPUT_NEWLINE_TO_CRLF;
  2121. Terminal->Settings.ControlFlags = TERMINAL_CONTROL_8_BITS_PER_CHARACTER;
  2122. ControlCharacters = Terminal->Settings.ControlCharacters;
  2123. ControlCharacters[TerminalCharacterEndOfFile] =
  2124. TERMINAL_DEFAULT_END_OF_FILE;
  2125. ControlCharacters[TerminalCharacterEndOfLine] =
  2126. TERMINAL_DEFAULT_END_OF_LINE;
  2127. ControlCharacters[TerminalCharacterErase] = TERMINAL_DEFAULT_ERASE;
  2128. ControlCharacters[TerminalCharacterInterrupt] = TERMINAL_DEFAULT_INTERRUPT;
  2129. ControlCharacters[TerminalCharacterKill] = TERMINAL_DEFAULT_KILL;
  2130. ControlCharacters[TerminalCharacterQuit] = TERMINAL_DEFAULT_QUIT;
  2131. ControlCharacters[TerminalCharacterSuspend] = TERMINAL_DEFAULT_SUSPEND;
  2132. ControlCharacters[TerminalCharacterStart] = TERMINAL_DEFAULT_START;
  2133. ControlCharacters[TerminalCharacterStop] = TERMINAL_DEFAULT_STOP;
  2134. ControlCharacters[TerminalCharacterFlushCount] = 1;
  2135. ControlCharacters[TerminalCharacterFlushTime] = 0;
  2136. Terminal->Settings.InputSpeed = TERMINAL_DEFAULT_BAUD_RATE;
  2137. Terminal->Settings.OutputSpeed = TERMINAL_DEFAULT_BAUD_RATE;
  2138. Terminal->WindowSize.Rows = TERMINAL_DEFAULT_ROWS;
  2139. Terminal->WindowSize.Columns = TERMINAL_DEFAULT_COLUMNS;
  2140. //
  2141. // Initialize the owning session and process group.
  2142. //
  2143. Terminal->SessionId = TERMINAL_INVALID_SESSION;
  2144. Terminal->ProcessGroupId = TERMINAL_INVALID_PROCESS_GROUP;
  2145. //
  2146. // Create the corresponding slave object.
  2147. //
  2148. Status = STATUS_SUCCESS;
  2149. Slave = ObCreateObject(ObjectTerminalSlave,
  2150. IoTerminalDirectory,
  2151. NULL,
  2152. 0,
  2153. sizeof(TERMINAL_SLAVE),
  2154. NULL,
  2155. 0,
  2156. TERMINAL_ALLOCATION_TAG);
  2157. if (Slave == NULL) {
  2158. Status = STATUS_INSUFFICIENT_RESOURCES;
  2159. goto CreateTerminalObjectEnd;
  2160. }
  2161. //
  2162. // Wire the master and slave together.
  2163. //
  2164. Terminal->Slave = Slave;
  2165. Slave->Master = Terminal;
  2166. //
  2167. // Add the terminal to the end of the list.
  2168. //
  2169. KeAcquireQueuedLock(IoTerminalListLock);
  2170. INSERT_BEFORE(&(Terminal->ListEntry), &IoTerminalList);
  2171. KeReleaseQueuedLock(IoTerminalListLock);
  2172. Status = STATUS_SUCCESS;
  2173. CreateTerminalObjectEnd:
  2174. if (!KSUCCESS(Status)) {
  2175. if (Terminal != NULL) {
  2176. ObReleaseReference(Terminal);
  2177. Terminal = NULL;
  2178. }
  2179. }
  2180. *NewTerminal = Terminal;
  2181. return Status;
  2182. }
  2183. VOID
  2184. IopDestroyTerminal (
  2185. PVOID TerminalObject
  2186. )
  2187. /*++
  2188. Routine Description:
  2189. This routine is called when an terminal master's reference count drops to
  2190. zero. It destroys all resources associated with the terminal. This occurs
  2191. well after all the slave has been freed.
  2192. Arguments:
  2193. TerminalObject - Supplies a pointer to the terminal object being destroyed.
  2194. Return Value:
  2195. None.
  2196. --*/
  2197. {
  2198. PTERMINAL Terminal;
  2199. Terminal = (PTERMINAL)TerminalObject;
  2200. ASSERT(Terminal->SlavePathPoint.PathEntry == NULL);
  2201. //
  2202. // If the slave never got a file object, then the master still has a
  2203. // reference on the slave it needs to release.
  2204. //
  2205. if (Terminal->SlaveFileObject == NULL) {
  2206. ObReleaseReference(Terminal->Slave);
  2207. }
  2208. if (Terminal->ListEntry.Next != NULL) {
  2209. KeAcquireQueuedLock(IoTerminalListLock);
  2210. LIST_REMOVE(&(Terminal->ListEntry));
  2211. KeReleaseQueuedLock(IoTerminalListLock);
  2212. }
  2213. if (Terminal->HardwareHandle != NULL) {
  2214. IoClose(Terminal->HardwareHandle);
  2215. Terminal->HardwareHandle = NULL;
  2216. }
  2217. if (Terminal->InputBuffer != NULL) {
  2218. MmFreePagedPool(Terminal->InputBuffer);
  2219. }
  2220. if (Terminal->WorkingInputBuffer != NULL) {
  2221. MmFreePagedPool(Terminal->WorkingInputBuffer);
  2222. }
  2223. if (Terminal->InputLock != NULL) {
  2224. KeDestroyQueuedLock(Terminal->InputLock);
  2225. }
  2226. if (Terminal->OutputBuffer != NULL) {
  2227. MmFreePagedPool(Terminal->OutputBuffer);
  2228. }
  2229. if (Terminal->OutputLock != NULL) {
  2230. KeDestroyQueuedLock(Terminal->OutputLock);
  2231. }
  2232. return;
  2233. }
  2234. KSTATUS
  2235. IopTerminalMasterWrite (
  2236. PFILE_OBJECT FileObject,
  2237. PIO_CONTEXT IoContext
  2238. )
  2239. /*++
  2240. Routine Description:
  2241. This routine writes data to the terminal slave (data that will come out
  2242. the slave's standard input).
  2243. Arguments:
  2244. FileObject - Supplies a pointer to the terminal master file object.
  2245. IoContext - Supplies a pointer to the I/O context.
  2246. Return Value:
  2247. Status code. A failing status code does not necessarily mean no I/O made it
  2248. in or out. Check the bytes completed value in the I/O context to find out
  2249. how much occurred.
  2250. --*/
  2251. {
  2252. BOOL AddCharacter;
  2253. UCHAR Byte;
  2254. UINTN ByteIndex;
  2255. UCHAR Bytes[2];
  2256. UINTN BytesSize;
  2257. BOOL CharacterHandled;
  2258. PCHAR ControlCharacters;
  2259. ULONG DirtyRegionBegin;
  2260. ULONG DirtyRegionEnd;
  2261. ULONG EchoFlags;
  2262. ULONG EchoMask;
  2263. BOOL EchoThisCharacter;
  2264. BOOL InputAdded;
  2265. ULONG InputFlags;
  2266. BOOL InputLockHeld;
  2267. BOOL IsEndOfLine;
  2268. UINTN LocalByteIndex;
  2269. CHAR LocalBytes[64];
  2270. UINTN LocalByteSize;
  2271. ULONG LocalFlags;
  2272. PIO_OBJECT_STATE MasterIoState;
  2273. ULONG MoveIndex;
  2274. BOOL OutputLockHeld;
  2275. BOOL OutputWritten;
  2276. ULONG ReturnedEvents;
  2277. ULONG ScreenCursorPosition;
  2278. PIO_OBJECT_STATE SlaveIoState;
  2279. ULONG Space;
  2280. KSTATUS Status;
  2281. PTERMINAL Terminal;
  2282. ULONG TimeoutInMilliseconds;
  2283. BOOL TransferWorkingBuffer;
  2284. Terminal = FileObject->SpecialIo;
  2285. ASSERT(Terminal->Header.Type == ObjectTerminalMaster);
  2286. ASSERT(FileObject == Terminal->MasterFileObject);
  2287. MasterIoState = FileObject->IoState;
  2288. if (Terminal->SlaveFileObject == NULL) {
  2289. IoContext->BytesCompleted = 0;
  2290. return STATUS_NOT_READY;
  2291. }
  2292. SlaveIoState = Terminal->SlaveFileObject->IoState;
  2293. InputFlags = Terminal->Settings.InputFlags;
  2294. LocalFlags = Terminal->Settings.LocalFlags;
  2295. EchoMask = TERMINAL_LOCAL_ECHO | TERMINAL_LOCAL_ECHO_ERASE |
  2296. TERMINAL_LOCAL_ECHO_KILL_NEWLINE |
  2297. TERMINAL_LOCAL_ECHO_KILL_EXTENDED |
  2298. TERMINAL_LOCAL_ECHO_NEWLINE |
  2299. TERMINAL_LOCAL_ECHO_CONTROL;
  2300. EchoFlags = LocalFlags & EchoMask;
  2301. ControlCharacters = Terminal->Settings.ControlCharacters;
  2302. InputAdded = FALSE;
  2303. DirtyRegionBegin = Terminal->WorkingInputCursor;
  2304. DirtyRegionEnd = Terminal->WorkingInputCursor;
  2305. OutputLockHeld = FALSE;
  2306. OutputWritten = FALSE;
  2307. ScreenCursorPosition = Terminal->WorkingInputCursor;
  2308. TimeoutInMilliseconds = IoContext->TimeoutInMilliseconds;
  2309. if (EchoFlags != 0) {
  2310. KeAcquireQueuedLock(Terminal->OutputLock);
  2311. OutputLockHeld = TRUE;
  2312. }
  2313. KeAcquireQueuedLock(Terminal->InputLock);
  2314. InputLockHeld = TRUE;
  2315. //
  2316. // Loop through every byte.
  2317. //
  2318. LocalByteIndex = 0;
  2319. LocalByteSize = 0;
  2320. for (ByteIndex = 0; ByteIndex < IoContext->SizeInBytes; ByteIndex += 1) {
  2321. TransferWorkingBuffer = FALSE;
  2322. AddCharacter = TRUE;
  2323. //
  2324. // Get the particular byte in question. Keep a local bounce buffer to
  2325. // avoid calling the copy I/O buffer data function for every single
  2326. // byte.
  2327. //
  2328. if (LocalByteIndex < LocalByteSize) {
  2329. Byte = LocalBytes[LocalByteIndex];
  2330. LocalByteIndex += 1;
  2331. } else {
  2332. LocalByteSize = IoContext->SizeInBytes - ByteIndex;
  2333. if (LocalByteSize > sizeof(LocalBytes)) {
  2334. LocalByteSize = sizeof(LocalBytes);
  2335. }
  2336. Status = MmCopyIoBufferData(IoContext->IoBuffer,
  2337. LocalBytes,
  2338. ByteIndex,
  2339. LocalByteSize,
  2340. FALSE);
  2341. if (!KSUCCESS(Status)) {
  2342. goto TerminalMasterWriteEnd;
  2343. }
  2344. Byte = LocalBytes[0];
  2345. LocalByteIndex = 1;
  2346. }
  2347. //
  2348. // Grab the output lock if it's not already held.
  2349. //
  2350. if ((OutputLockHeld == FALSE) && (EchoFlags != 0)) {
  2351. KeAcquireQueuedLock(Terminal->OutputLock);
  2352. OutputLockHeld = TRUE;
  2353. }
  2354. //
  2355. // Process signal generating characters.
  2356. //
  2357. if (Byte == ControlCharacters[TerminalCharacterInterrupt]) {
  2358. if ((LocalFlags & TERMINAL_LOCAL_SIGNALS) != 0) {
  2359. AddCharacter = FALSE;
  2360. if ((Terminal->SlaveHandles != 0) &&
  2361. (Terminal->ProcessGroupId !=
  2362. TERMINAL_INVALID_PROCESS_GROUP)) {
  2363. PsSignalProcessGroup(Terminal->ProcessGroupId,
  2364. SIGNAL_KEYBOARD_INTERRUPT);
  2365. }
  2366. }
  2367. }
  2368. if (Byte == ControlCharacters[TerminalCharacterQuit]) {
  2369. if ((LocalFlags & TERMINAL_LOCAL_SIGNALS) != 0) {
  2370. AddCharacter = FALSE;
  2371. if ((Terminal->SlaveHandles != 0) &&
  2372. (Terminal->ProcessGroupId !=
  2373. TERMINAL_INVALID_PROCESS_GROUP)) {
  2374. PsSignalProcessGroup(Terminal->ProcessGroupId,
  2375. SIGNAL_REQUEST_CORE_DUMP);
  2376. }
  2377. }
  2378. }
  2379. //
  2380. // Run through the input flags.
  2381. //
  2382. if ((InputFlags & TERMINAL_INPUT_STRIP) != 0) {
  2383. Byte &= 0x7F;
  2384. }
  2385. if (Byte == '\r') {
  2386. if ((InputFlags & TERMINAL_INPUT_CR_TO_NEWLINE) != 0) {
  2387. Byte = '\n';
  2388. } else if ((InputFlags & TERMINAL_INPUT_IGNORE_CR) != 0) {
  2389. AddCharacter = FALSE;
  2390. }
  2391. } else if (Byte == '\n') {
  2392. if ((InputFlags & TERMINAL_INPUT_NEWLINE_TO_CR) != 0) {
  2393. Byte = '\r';
  2394. }
  2395. }
  2396. //
  2397. // Process the byte in cooked mode.
  2398. //
  2399. if ((LocalFlags & TERMINAL_LOCAL_CANONICAL) != 0) {
  2400. IsEndOfLine = FALSE;
  2401. //
  2402. // First let an editing function take a look at it.
  2403. //
  2404. CharacterHandled = IopTerminalProcessEditingCharacter(
  2405. Terminal,
  2406. Byte,
  2407. TimeoutInMilliseconds,
  2408. &DirtyRegionBegin,
  2409. &DirtyRegionEnd,
  2410. &ScreenCursorPosition,
  2411. &OutputWritten);
  2412. if (CharacterHandled != FALSE) {
  2413. AddCharacter = FALSE;
  2414. //
  2415. // Pushing return transfers the working buffer to the slave's input.
  2416. //
  2417. } else if ((Byte ==
  2418. ControlCharacters[TerminalCharacterEndOfLine]) ||
  2419. (Byte == '\n')) {
  2420. TransferWorkingBuffer = TRUE;
  2421. Terminal->WorkingInputCursor = Terminal->WorkingInputLength;
  2422. IsEndOfLine = TRUE;
  2423. //
  2424. // End of file also causes output to be flushed.
  2425. //
  2426. } else if (Byte == ControlCharacters[TerminalCharacterEndOfFile]) {
  2427. TransferWorkingBuffer = TRUE;
  2428. }
  2429. //
  2430. // Add the character to the working buffer if needed.
  2431. //
  2432. if (AddCharacter != FALSE) {
  2433. if (Terminal->WorkingInputLength !=
  2434. TERMINAL_CANONICAL_BUFFER_SIZE) {
  2435. if (Terminal->WorkingInputCursor < DirtyRegionBegin) {
  2436. DirtyRegionBegin = Terminal->WorkingInputCursor;
  2437. }
  2438. //
  2439. // Make a hole.
  2440. //
  2441. for (MoveIndex = Terminal->WorkingInputLength;
  2442. MoveIndex > Terminal->WorkingInputCursor;
  2443. MoveIndex -= 1) {
  2444. Terminal->WorkingInputBuffer[MoveIndex] =
  2445. Terminal->WorkingInputBuffer[MoveIndex - 1];
  2446. }
  2447. Terminal->WorkingInputBuffer[Terminal->WorkingInputCursor] =
  2448. Byte;
  2449. Terminal->WorkingInputCursor += 1;
  2450. Terminal->WorkingInputLength += 1;
  2451. if ((IsEndOfLine == FALSE) &&
  2452. (Terminal->WorkingInputLength > DirtyRegionEnd)) {
  2453. DirtyRegionEnd = Terminal->WorkingInputLength;
  2454. Terminal->Flags &= ~(TERMINAL_FLAG_VIRGIN_LINE |
  2455. TERMINAL_FLAG_UNEDITED_LINE);
  2456. }
  2457. }
  2458. }
  2459. //
  2460. // Flush the buffer if desired.
  2461. //
  2462. if (TransferWorkingBuffer != FALSE) {
  2463. //
  2464. // Fix up the line before abandoning it.
  2465. //
  2466. if ((DirtyRegionBegin != DirtyRegionEnd) &&
  2467. ((EchoFlags & TERMINAL_LOCAL_ECHO) != 0)) {
  2468. if (OutputLockHeld == FALSE) {
  2469. KeAcquireQueuedLock(Terminal->OutputLock);
  2470. OutputLockHeld = TRUE;
  2471. }
  2472. IopTerminalFixUpCanonicalLine(Terminal,
  2473. TimeoutInMilliseconds,
  2474. DirtyRegionBegin,
  2475. DirtyRegionEnd,
  2476. ScreenCursorPosition);
  2477. ScreenCursorPosition = Terminal->WorkingInputCursor;
  2478. OutputWritten = TRUE;
  2479. }
  2480. //
  2481. // Wait for there to be enough space.
  2482. //
  2483. while (TRUE) {
  2484. if (InputLockHeld == FALSE) {
  2485. KeAcquireQueuedLock(Terminal->InputLock);
  2486. InputLockHeld = TRUE;
  2487. }
  2488. InputFlags = Terminal->Settings.InputFlags;
  2489. LocalFlags = Terminal->Settings.LocalFlags;
  2490. EchoFlags = LocalFlags & EchoMask;
  2491. Space = IopTerminalGetInputBufferSpace(Terminal);
  2492. if (Space >= Terminal->WorkingInputLength) {
  2493. break;
  2494. }
  2495. IoSetIoObjectState(MasterIoState, POLL_EVENT_OUT, FALSE);
  2496. IoSetIoObjectState(SlaveIoState, POLL_EVENT_IN, TRUE);
  2497. InputAdded = FALSE;
  2498. KeReleaseQueuedLock(Terminal->InputLock);
  2499. InputLockHeld = FALSE;
  2500. Status = IoWaitForIoObjectState(MasterIoState,
  2501. POLL_EVENT_OUT,
  2502. TRUE,
  2503. TimeoutInMilliseconds,
  2504. &ReturnedEvents);
  2505. if (!KSUCCESS(Status)) {
  2506. goto TerminalMasterWriteEnd;
  2507. }
  2508. if ((ReturnedEvents & TERMINAL_POLL_ERRORS) != 0) {
  2509. Status = STATUS_DEVICE_IO_ERROR;
  2510. goto TerminalMasterWriteEnd;
  2511. }
  2512. }
  2513. //
  2514. // Move the bytes to the input buffer.
  2515. //
  2516. for (MoveIndex = 0;
  2517. MoveIndex < Terminal->WorkingInputLength;
  2518. MoveIndex += 1) {
  2519. Terminal->InputBuffer[Terminal->InputBufferEnd] =
  2520. Terminal->WorkingInputBuffer[MoveIndex];
  2521. Terminal->InputBufferEnd += 1;
  2522. if (Terminal->InputBufferEnd ==
  2523. TERMINAL_INPUT_BUFFER_SIZE) {
  2524. Terminal->InputBufferEnd = 0;
  2525. }
  2526. ASSERT(Terminal->InputBufferEnd !=
  2527. Terminal->InputBufferStart);
  2528. }
  2529. KeReleaseQueuedLock(Terminal->InputLock);
  2530. InputLockHeld = FALSE;
  2531. InputAdded = TRUE;
  2532. Terminal->WorkingInputCursor = 0;
  2533. Terminal->WorkingInputLength = 0;
  2534. DirtyRegionBegin = 0;
  2535. DirtyRegionEnd = 0;
  2536. ScreenCursorPosition = 0;
  2537. Terminal->Flags |= TERMINAL_FLAG_VIRGIN_LINE |
  2538. TERMINAL_FLAG_UNEDITED_LINE;
  2539. }
  2540. //
  2541. // Input is not canonical, it just goes directly in the input buffer.
  2542. //
  2543. } else {
  2544. if (AddCharacter == FALSE) {
  2545. continue;
  2546. }
  2547. //
  2548. // Wait if there's not enough space available.
  2549. //
  2550. while (IopTerminalGetInputBufferSpace(Terminal) == 0) {
  2551. IoSetIoObjectState(MasterIoState, POLL_EVENT_OUT, FALSE);
  2552. IoSetIoObjectState(SlaveIoState, POLL_EVENT_IN, TRUE);
  2553. KeReleaseQueuedLock(Terminal->InputLock);
  2554. InputLockHeld = FALSE;
  2555. InputAdded = FALSE;
  2556. Status = IoWaitForIoObjectState(MasterIoState,
  2557. POLL_EVENT_OUT,
  2558. TRUE,
  2559. TimeoutInMilliseconds,
  2560. &ReturnedEvents);
  2561. if (!KSUCCESS(Status)) {
  2562. goto TerminalMasterWriteEnd;
  2563. }
  2564. if ((ReturnedEvents & TERMINAL_POLL_ERRORS) != 0) {
  2565. Status = STATUS_DEVICE_IO_ERROR;
  2566. goto TerminalMasterWriteEnd;
  2567. }
  2568. KeAcquireQueuedLock(Terminal->InputLock);
  2569. InputLockHeld = TRUE;
  2570. }
  2571. //
  2572. // Add the character to the input buffer.
  2573. //
  2574. Terminal->InputBuffer[Terminal->InputBufferEnd] = Byte;
  2575. Terminal->InputBufferEnd += 1;
  2576. if (Terminal->InputBufferEnd == TERMINAL_INPUT_BUFFER_SIZE) {
  2577. Terminal->InputBufferEnd = 0;
  2578. }
  2579. ASSERT(Terminal->InputBufferEnd != Terminal->InputBufferStart);
  2580. InputAdded = TRUE;
  2581. }
  2582. //
  2583. // Potentially echo the byte. Failure to echo is not necessarily
  2584. // considered a failure.
  2585. //
  2586. if (EchoFlags != 0) {
  2587. //
  2588. // In raw mode, echo everything unless disallowed.
  2589. //
  2590. if ((LocalFlags & TERMINAL_LOCAL_CANONICAL) == 0) {
  2591. EchoThisCharacter = FALSE;
  2592. if ((EchoFlags & TERMINAL_LOCAL_ECHO) != 0) {
  2593. EchoThisCharacter = TRUE;
  2594. } else if ((Byte == '\n') &&
  2595. ((EchoFlags & TERMINAL_LOCAL_ECHO_NEWLINE) != 0)) {
  2596. EchoThisCharacter = TRUE;
  2597. }
  2598. //
  2599. // In canonical mode, only consider echoing newlines. Everything
  2600. // else is handled automatically.
  2601. //
  2602. } else {
  2603. EchoThisCharacter = FALSE;
  2604. if (Byte == '\n') {
  2605. if ((EchoFlags &
  2606. (TERMINAL_LOCAL_ECHO_NEWLINE |
  2607. TERMINAL_LOCAL_ECHO)) != 0) {
  2608. EchoThisCharacter = TRUE;
  2609. }
  2610. }
  2611. }
  2612. if (EchoThisCharacter != FALSE) {
  2613. Bytes[0] = Byte;
  2614. BytesSize = 1;
  2615. if ((Byte < ' ') &&
  2616. ((EchoFlags & TERMINAL_LOCAL_ECHO_CONTROL) != 0) &&
  2617. (!RtlIsCharacterSpace(Byte)) && (Byte != '\0')) {
  2618. Bytes[1] = Byte + '@';
  2619. Bytes[0] = '^';
  2620. BytesSize = 2;
  2621. }
  2622. IopTerminalWriteOutputBuffer(Terminal,
  2623. Bytes,
  2624. BytesSize,
  2625. 1,
  2626. TimeoutInMilliseconds);
  2627. OutputWritten = TRUE;
  2628. }
  2629. }
  2630. }
  2631. //
  2632. // In canonical mode, the line may need to be fixed up.
  2633. //
  2634. if ((DirtyRegionBegin != DirtyRegionEnd) &&
  2635. ((EchoFlags & TERMINAL_LOCAL_ECHO) != 0)) {
  2636. if (OutputLockHeld == FALSE) {
  2637. KeAcquireQueuedLock(Terminal->OutputLock);
  2638. OutputLockHeld = TRUE;
  2639. }
  2640. IopTerminalFixUpCanonicalLine(Terminal,
  2641. TimeoutInMilliseconds,
  2642. DirtyRegionBegin,
  2643. DirtyRegionEnd,
  2644. ScreenCursorPosition);
  2645. OutputWritten = TRUE;
  2646. }
  2647. Status = STATUS_SUCCESS;
  2648. TerminalMasterWriteEnd:
  2649. //
  2650. // Signal the input and/or output that there's stuff to do.
  2651. //
  2652. if (OutputWritten != FALSE) {
  2653. if (OutputLockHeld == FALSE) {
  2654. KeAcquireQueuedLock(Terminal->OutputLock);
  2655. OutputLockHeld = TRUE;
  2656. }
  2657. IoSetIoObjectState(MasterIoState, POLL_EVENT_IN, TRUE);
  2658. }
  2659. if (InputAdded != FALSE) {
  2660. if (InputLockHeld == FALSE) {
  2661. KeAcquireQueuedLock(Terminal->InputLock);
  2662. InputLockHeld = TRUE;
  2663. }
  2664. IoSetIoObjectState(SlaveIoState, POLL_EVENT_IN, TRUE);
  2665. }
  2666. //
  2667. // Release the various locks that are held.
  2668. //
  2669. if (InputLockHeld != FALSE) {
  2670. KeReleaseQueuedLock(Terminal->InputLock);
  2671. }
  2672. if (OutputLockHeld != FALSE) {
  2673. KeReleaseQueuedLock(Terminal->OutputLock);
  2674. }
  2675. IoContext->BytesCompleted = ByteIndex;
  2676. return Status;
  2677. }
  2678. KSTATUS
  2679. IopTerminalSlaveWrite (
  2680. PFILE_OBJECT FileObject,
  2681. PIO_CONTEXT IoContext
  2682. )
  2683. /*++
  2684. Routine Description:
  2685. This routine writes data to the terminal master (ie writes to the slaves
  2686. standard out).
  2687. Arguments:
  2688. FileObject - Supplies a pointer to the slave terminal file object.
  2689. IoContext - Supplies a pointer to the I/O context.
  2690. Return Value:
  2691. Status code. A failing status code does not necessarily mean no I/O made it
  2692. in or out. Check the bytes completed value in the I/O context to find out
  2693. how much occurred.
  2694. --*/
  2695. {
  2696. BOOL AcceptingSignal;
  2697. BOOL AnythingWritten;
  2698. UINTN BytesThisRound;
  2699. UINTN BytesWritten;
  2700. UCHAR LocalBytes[64];
  2701. BOOL LockHeld;
  2702. PIO_OBJECT_STATE MasterIoState;
  2703. PROCESS_GROUP_ID ProcessGroup;
  2704. ULONG ReturnedEvents;
  2705. SESSION_ID Session;
  2706. BOOL SignalProcessGroup;
  2707. PTERMINAL_SLAVE Slave;
  2708. PIO_OBJECT_STATE SlaveIoState;
  2709. ULONG Space;
  2710. KSTATUS Status;
  2711. PTERMINAL Terminal;
  2712. ULONG TimeoutInMilliseconds;
  2713. AnythingWritten = FALSE;
  2714. BytesWritten = 0;
  2715. LockHeld = FALSE;
  2716. MasterIoState = NULL;
  2717. SignalProcessGroup = FALSE;
  2718. Slave = FileObject->SpecialIo;
  2719. Terminal = Slave->Master;
  2720. TimeoutInMilliseconds = IoContext->TimeoutInMilliseconds;
  2721. ASSERT(Slave->Header.Type == ObjectTerminalSlave);
  2722. if (IO_IS_TERMINAL_MASTER_OPEN(Terminal) == FALSE) {
  2723. Status = STATUS_BROKEN_PIPE;
  2724. goto TerminalSlaveWriteEnd;
  2725. }
  2726. SlaveIoState = Terminal->SlaveFileObject->IoState;
  2727. MasterIoState = Terminal->MasterFileObject->IoState;
  2728. PsGetProcessGroup(NULL, &ProcessGroup, &Session);
  2729. //
  2730. // Synchronize the checks on the terminal attachment and the owning session
  2731. // and process group with the IOCTLs that may modify them.
  2732. //
  2733. KeAcquireQueuedLock(Terminal->OutputLock);
  2734. LockHeld = TRUE;
  2735. //
  2736. // If the writing process is not in the same process group, send the
  2737. // process group a signal unless the writing process is ignoring or
  2738. // blocking that signal.
  2739. //
  2740. if ((ProcessGroup != Terminal->ProcessGroupId) &&
  2741. ((Terminal->Settings.LocalFlags &
  2742. TERMINAL_LOCAL_STOP_BACKGROUND_WRITES) != 0)) {
  2743. AcceptingSignal = PsIsThreadAcceptingSignal(
  2744. NULL,
  2745. SIGNAL_BACKGROUND_TERMINAL_OUTPUT);
  2746. //
  2747. // If the process is accepting that signal, send it to it and tell it
  2748. // to try again later. The exception is an orphaned process group, in
  2749. // which case an error is returned. If the process is not accepting the
  2750. // signal, just let the write go through.
  2751. //
  2752. if (AcceptingSignal != FALSE) {
  2753. if (PsIsProcessGroupOrphaned(ProcessGroup) != FALSE) {
  2754. Status = STATUS_DEVICE_IO_ERROR;
  2755. } else {
  2756. SignalProcessGroup = TRUE;
  2757. Status = STATUS_TRY_AGAIN;
  2758. }
  2759. goto TerminalSlaveWriteEnd;
  2760. }
  2761. }
  2762. //
  2763. // Loop writing bytes until it's done.
  2764. //
  2765. Status = STATUS_SUCCESS;
  2766. Space = IopTerminalGetOutputBufferSpace(Terminal);
  2767. while (BytesWritten != IoContext->SizeInBytes) {
  2768. //
  2769. // If there's no space, release the lock and wait for space to open up.
  2770. //
  2771. if (Space == 0) {
  2772. IoSetIoObjectState(MasterIoState, POLL_EVENT_IN, TRUE);
  2773. IoSetIoObjectState(SlaveIoState, POLL_EVENT_OUT, FALSE);
  2774. KeReleaseQueuedLock(Terminal->OutputLock);
  2775. LockHeld = FALSE;
  2776. Status = IoWaitForIoObjectState(SlaveIoState,
  2777. POLL_EVENT_OUT,
  2778. TRUE,
  2779. TimeoutInMilliseconds,
  2780. &ReturnedEvents);
  2781. if (!KSUCCESS(Status)) {
  2782. goto TerminalSlaveWriteEnd;
  2783. }
  2784. if ((ReturnedEvents & TERMINAL_POLL_ERRORS) != 0) {
  2785. Status = STATUS_DEVICE_IO_ERROR;
  2786. goto TerminalSlaveWriteEnd;
  2787. }
  2788. KeAcquireQueuedLock(Terminal->OutputLock);
  2789. LockHeld = TRUE;
  2790. Space = IopTerminalGetOutputBufferSpace(Terminal);
  2791. continue;
  2792. }
  2793. BytesThisRound = Space;
  2794. if (IoContext->SizeInBytes - BytesWritten < Space) {
  2795. BytesThisRound = IoContext->SizeInBytes - BytesWritten;
  2796. }
  2797. //
  2798. // Copy the data from the I/O buffer to a local bounce buffer, then
  2799. // into the output buffer.
  2800. //
  2801. if (BytesThisRound > sizeof(LocalBytes)) {
  2802. BytesThisRound = sizeof(LocalBytes);
  2803. }
  2804. Status = MmCopyIoBufferData(IoContext->IoBuffer,
  2805. LocalBytes,
  2806. BytesWritten,
  2807. BytesThisRound,
  2808. FALSE);
  2809. if (!KSUCCESS(Status)) {
  2810. break;
  2811. }
  2812. Status = IopTerminalWriteOutputBuffer(Terminal,
  2813. LocalBytes,
  2814. BytesThisRound,
  2815. 1,
  2816. TimeoutInMilliseconds);
  2817. if (!KSUCCESS(Status)) {
  2818. goto TerminalSlaveWriteEnd;
  2819. }
  2820. Space = IopTerminalGetOutputBufferSpace(Terminal);
  2821. AnythingWritten = TRUE;
  2822. BytesWritten += BytesThisRound;
  2823. }
  2824. //
  2825. // Unsignal the write event if this routine just wrote the last of the
  2826. // space.
  2827. //
  2828. ASSERT(LockHeld != FALSE);
  2829. if ((AnythingWritten != FALSE) && (Space == 0)) {
  2830. IoSetIoObjectState(SlaveIoState, POLL_EVENT_OUT, FALSE);
  2831. }
  2832. TerminalSlaveWriteEnd:
  2833. if (AnythingWritten != FALSE) {
  2834. if (LockHeld == FALSE) {
  2835. KeAcquireQueuedLock(Terminal->OutputLock);
  2836. LockHeld = TRUE;
  2837. }
  2838. IoSetIoObjectState(MasterIoState, POLL_EVENT_IN, TRUE);
  2839. }
  2840. if (LockHeld != FALSE) {
  2841. KeReleaseQueuedLock(Terminal->OutputLock);
  2842. }
  2843. if (SignalProcessGroup != FALSE) {
  2844. PsSignalProcessGroup(ProcessGroup, SIGNAL_BACKGROUND_TERMINAL_OUTPUT);
  2845. }
  2846. IoContext->BytesCompleted = BytesWritten;
  2847. return Status;
  2848. }
  2849. KSTATUS
  2850. IopTerminalMasterRead (
  2851. PFILE_OBJECT FileObject,
  2852. PIO_CONTEXT IoContext
  2853. )
  2854. /*++
  2855. Routine Description:
  2856. This routine reads data from the master side (the slave's standard out).
  2857. Arguments:
  2858. FileObject - Supplies a pointer to the master terminal file object.
  2859. IoContext - Supplies a pointer to the I/O context.
  2860. Return Value:
  2861. Status code. A failing status code does not necessarily mean no I/O made it
  2862. in or out. Check the bytes completed value in the I/O context to find out
  2863. how much occurred.
  2864. --*/
  2865. {
  2866. BOOL AnythingRead;
  2867. UINTN BytesRead;
  2868. UINTN CopySize;
  2869. BOOL LockHeld;
  2870. PIO_OBJECT_STATE MasterIoState;
  2871. ULONG ReturnedEvents;
  2872. PIO_OBJECT_STATE SlaveIoState;
  2873. ULONG Space;
  2874. KSTATUS Status;
  2875. PTERMINAL Terminal;
  2876. ULONG TimeoutInMilliseconds;
  2877. Terminal = FileObject->SpecialIo;
  2878. ASSERT(Terminal->Header.Type == ObjectTerminalMaster);
  2879. ASSERT(Terminal->MasterFileObject == FileObject);
  2880. if (Terminal->SlaveFileObject == NULL) {
  2881. IoContext->BytesCompleted = 0;
  2882. return STATUS_NOT_READY;
  2883. }
  2884. SlaveIoState = Terminal->SlaveFileObject->IoState;
  2885. MasterIoState = FileObject->IoState;
  2886. TimeoutInMilliseconds = IoContext->TimeoutInMilliseconds;
  2887. AnythingRead = FALSE;
  2888. BytesRead = 0;
  2889. KeAcquireQueuedLock(Terminal->OutputLock);
  2890. LockHeld = TRUE;
  2891. Space = IopTerminalGetOutputBufferSpace(Terminal);
  2892. while (BytesRead < IoContext->SizeInBytes) {
  2893. //
  2894. // Wait for data to be ready.
  2895. //
  2896. while (Space == TERMINAL_OUTPUT_BUFFER_SIZE - 1) {
  2897. //
  2898. // If the caller got something already, just return immediately
  2899. // instead of waiting for the full buffer amount.
  2900. //
  2901. if (AnythingRead != FALSE) {
  2902. Status = STATUS_SUCCESS;
  2903. goto TerminalMasterReadEnd;
  2904. }
  2905. IoSetIoObjectState(MasterIoState, POLL_EVENT_IN, FALSE);
  2906. IoSetIoObjectState(SlaveIoState, POLL_EVENT_OUT, TRUE);
  2907. KeReleaseQueuedLock(Terminal->OutputLock);
  2908. LockHeld = FALSE;
  2909. Status = IoWaitForIoObjectState(MasterIoState,
  2910. POLL_EVENT_IN,
  2911. TRUE,
  2912. TimeoutInMilliseconds,
  2913. &ReturnedEvents);
  2914. if (!KSUCCESS(Status)) {
  2915. goto TerminalMasterReadEnd;
  2916. }
  2917. if ((ReturnedEvents & TERMINAL_POLL_ERRORS) != 0) {
  2918. Status = STATUS_DEVICE_IO_ERROR;
  2919. goto TerminalMasterReadEnd;
  2920. }
  2921. KeAcquireQueuedLock(Terminal->OutputLock);
  2922. LockHeld = TRUE;
  2923. Space = IopTerminalGetOutputBufferSpace(Terminal);
  2924. }
  2925. //
  2926. // Copy the bytes out. Don't wrap across the terminal's circular buffer.
  2927. //
  2928. CopySize = (TERMINAL_OUTPUT_BUFFER_SIZE - 1) - Space;
  2929. if (CopySize > IoContext->SizeInBytes - BytesRead) {
  2930. CopySize = IoContext->SizeInBytes - BytesRead;
  2931. }
  2932. if (CopySize >
  2933. TERMINAL_OUTPUT_BUFFER_SIZE - Terminal->OutputBufferStart) {
  2934. CopySize = TERMINAL_OUTPUT_BUFFER_SIZE -
  2935. Terminal->OutputBufferStart;
  2936. }
  2937. Status = MmCopyIoBufferData(
  2938. IoContext->IoBuffer,
  2939. Terminal->OutputBuffer + Terminal->OutputBufferStart,
  2940. BytesRead,
  2941. CopySize,
  2942. TRUE);
  2943. if (!KSUCCESS(Status)) {
  2944. goto TerminalMasterReadEnd;
  2945. }
  2946. Terminal->OutputBufferStart += CopySize;
  2947. ASSERT(Terminal->OutputBufferStart <= TERMINAL_OUTPUT_BUFFER_SIZE);
  2948. if (Terminal->OutputBufferStart == TERMINAL_OUTPUT_BUFFER_SIZE) {
  2949. Terminal->OutputBufferStart = 0;
  2950. }
  2951. Space += CopySize;
  2952. AnythingRead = TRUE;
  2953. BytesRead += CopySize;
  2954. }
  2955. Status = STATUS_SUCCESS;
  2956. TerminalMasterReadEnd:
  2957. if (AnythingRead != FALSE) {
  2958. if (LockHeld == FALSE) {
  2959. KeAcquireQueuedLock(Terminal->OutputLock);
  2960. LockHeld = TRUE;
  2961. }
  2962. IoSetIoObjectState(SlaveIoState, POLL_EVENT_OUT, TRUE);
  2963. Space = IopTerminalGetOutputBufferSpace(Terminal);
  2964. if (Space == TERMINAL_OUTPUT_BUFFER_SIZE - 1) {
  2965. IoSetIoObjectState(MasterIoState, POLL_EVENT_IN, FALSE);
  2966. }
  2967. }
  2968. if (LockHeld != FALSE) {
  2969. KeReleaseQueuedLock(Terminal->OutputLock);
  2970. }
  2971. IoContext->BytesCompleted = BytesRead;
  2972. return Status;
  2973. }
  2974. KSTATUS
  2975. IopTerminalSlaveRead (
  2976. PFILE_OBJECT FileObject,
  2977. PIO_CONTEXT IoContext
  2978. )
  2979. /*++
  2980. Routine Description:
  2981. This routine reads data from the slave side (the slave's standard in).
  2982. Arguments:
  2983. FileObject - Supplies a pointer to the slave terminal file object.
  2984. IoContext - Supplies a pointer to the I/O context.
  2985. Return Value:
  2986. Status code. A failing status code does not necessarily mean no I/O made it
  2987. in or out. Check the bytes completed value in the I/O context to find out
  2988. how much occurred.
  2989. --*/
  2990. {
  2991. BOOL AcceptingSignal;
  2992. UINTN AdvanceSize;
  2993. BOOL AnythingRead;
  2994. BOOL BreakForNewline;
  2995. UINTN BytesRead;
  2996. CHAR Character;
  2997. PCHAR ControlCharacters;
  2998. UINTN CopyIndex;
  2999. UINTN CopySize;
  3000. UCHAR FlushCount;
  3001. UCHAR FlushTime;
  3002. UINTN InputIndex;
  3003. ULONG LocalFlags;
  3004. BOOL LockHeld;
  3005. PIO_OBJECT_STATE MasterIoState;
  3006. PROCESS_GROUP_ID ProcessGroup;
  3007. ULONG ReturnedEvents;
  3008. SESSION_ID Session;
  3009. BOOL SignalProcessGroup;
  3010. PTERMINAL_SLAVE Slave;
  3011. PIO_OBJECT_STATE SlaveIoState;
  3012. ULONG Space;
  3013. KSTATUS Status;
  3014. PTERMINAL Terminal;
  3015. ULONG TimeoutInMilliseconds;
  3016. SignalProcessGroup = FALSE;
  3017. Slave = FileObject->SpecialIo;
  3018. ASSERT(Slave->Header.Type == ObjectTerminalSlave);
  3019. Terminal = Slave->Master;
  3020. ASSERT(FileObject == Terminal->SlaveFileObject);
  3021. SlaveIoState = Terminal->SlaveFileObject->IoState;
  3022. MasterIoState = Terminal->MasterFileObject->IoState;
  3023. ControlCharacters = Terminal->Settings.ControlCharacters;
  3024. TimeoutInMilliseconds = IoContext->TimeoutInMilliseconds;
  3025. AnythingRead = FALSE;
  3026. BytesRead = 0;
  3027. LockHeld = FALSE;
  3028. PsGetProcessGroup(NULL, &ProcessGroup, &Session);
  3029. //
  3030. // Synchronize the checks on the terminal attachment and the owning session
  3031. // and process group with the IOCTLs that may modify them.
  3032. //
  3033. KeAcquireQueuedLock(Terminal->InputLock);
  3034. LockHeld = TRUE;
  3035. LocalFlags = Terminal->Settings.LocalFlags;
  3036. //
  3037. // If the reading process is not in the same process group, send the
  3038. // process group a signal unless the reading process is ignoring or
  3039. // blocking that signal.
  3040. //
  3041. if (ProcessGroup != Terminal->ProcessGroupId) {
  3042. //
  3043. // If it's an orphaned process, fail the I/O.
  3044. //
  3045. if (PsIsProcessGroupOrphaned(ProcessGroup) != FALSE) {
  3046. Status = STATUS_DEVICE_IO_ERROR;
  3047. goto TerminalSlaveReadEnd;
  3048. }
  3049. AcceptingSignal = PsIsThreadAcceptingSignal(
  3050. NULL,
  3051. SIGNAL_BACKGROUND_TERMINAL_INPUT);
  3052. //
  3053. // If the process is accepting that signal, send it to it and tell it
  3054. // to try again later. If it's not accepting it, just let it go through.
  3055. //
  3056. if (AcceptingSignal != FALSE) {
  3057. SignalProcessGroup = TRUE;
  3058. Status = STATUS_TRY_AGAIN;
  3059. goto TerminalSlaveReadEnd;
  3060. }
  3061. }
  3062. //
  3063. // Wait the designated amount of time, or block indefinitely.
  3064. //
  3065. if (TimeoutInMilliseconds == WAIT_TIME_INDEFINITE) {
  3066. FlushTime = ControlCharacters[TerminalCharacterFlushTime];
  3067. if (FlushTime != 0) {
  3068. TimeoutInMilliseconds = FlushTime * 100;
  3069. }
  3070. }
  3071. BreakForNewline = FALSE;
  3072. Status = STATUS_SUCCESS;
  3073. Space = IopTerminalGetInputBufferSpace(Terminal);
  3074. while (BytesRead < IoContext->SizeInBytes) {
  3075. //
  3076. // Wait for data to be ready.
  3077. //
  3078. if (Space == TERMINAL_INPUT_BUFFER_SIZE - 1) {
  3079. //
  3080. // In non-canonical mode, observe the minimum and timeout counts.
  3081. //
  3082. if ((LocalFlags & TERMINAL_LOCAL_CANONICAL) == 0) {
  3083. FlushCount = ControlCharacters[TerminalCharacterFlushCount];
  3084. if (FlushCount != 0) {
  3085. //
  3086. // If there's a minimum and it's been met, stop now.
  3087. //
  3088. if (BytesRead >= FlushCount) {
  3089. break;
  3090. }
  3091. //
  3092. // The minimum is zero. If time is also zero, then do not block.
  3093. //
  3094. } else {
  3095. if (ControlCharacters[TerminalCharacterFlushTime] == 0) {
  3096. TimeoutInMilliseconds = 0;
  3097. }
  3098. }
  3099. }
  3100. //
  3101. // If all open handles to the master were closed, there's never
  3102. // going to be any more data.
  3103. //
  3104. if (IO_IS_TERMINAL_MASTER_OPEN(Terminal) == FALSE) {
  3105. Status = STATUS_END_OF_FILE;
  3106. break;
  3107. }
  3108. IoSetIoObjectState(SlaveIoState, POLL_EVENT_IN, FALSE);
  3109. IoSetIoObjectState(MasterIoState, POLL_EVENT_OUT, TRUE);
  3110. KeReleaseQueuedLock(Terminal->InputLock);
  3111. LockHeld = FALSE;
  3112. Status = IoWaitForIoObjectState(SlaveIoState,
  3113. POLL_EVENT_IN,
  3114. TRUE,
  3115. TimeoutInMilliseconds,
  3116. &ReturnedEvents);
  3117. if (!KSUCCESS(Status)) {
  3118. goto TerminalSlaveReadEnd;
  3119. }
  3120. if ((ReturnedEvents & TERMINAL_POLL_ERRORS) != 0) {
  3121. Status = STATUS_DEVICE_IO_ERROR;
  3122. goto TerminalSlaveReadEnd;
  3123. }
  3124. KeAcquireQueuedLock(Terminal->InputLock);
  3125. LockHeld = TRUE;
  3126. LocalFlags = Terminal->Settings.LocalFlags;
  3127. Space = IopTerminalGetInputBufferSpace(Terminal);
  3128. if (Space == TERMINAL_INPUT_BUFFER_SIZE - 1) {
  3129. break;
  3130. }
  3131. }
  3132. //
  3133. // Determine how much to copy out of the terminal's input buffer.
  3134. //
  3135. CopySize = (TERMINAL_INPUT_BUFFER_SIZE - 1) - Space;
  3136. if (CopySize > IoContext->SizeInBytes - BytesRead) {
  3137. CopySize = IoContext->SizeInBytes - BytesRead;
  3138. }
  3139. if (CopySize >
  3140. TERMINAL_INPUT_BUFFER_SIZE - Terminal->InputBufferStart) {
  3141. CopySize = TERMINAL_INPUT_BUFFER_SIZE - Terminal->InputBufferStart;
  3142. }
  3143. //
  3144. // If it's canonical, look for a newline and break on that.
  3145. //
  3146. AdvanceSize = CopySize;
  3147. if ((LocalFlags & TERMINAL_LOCAL_CANONICAL) != 0) {
  3148. for (CopyIndex = 0; CopyIndex < CopySize; CopyIndex += 1) {
  3149. InputIndex = Terminal->InputBufferStart + CopyIndex;
  3150. Character = Terminal->InputBuffer[InputIndex];
  3151. if ((Character ==
  3152. ControlCharacters[TerminalCharacterEndOfLine]) ||
  3153. (Character == '\n')) {
  3154. CopySize = CopyIndex + 1;
  3155. AdvanceSize = CopySize;
  3156. BreakForNewline = TRUE;
  3157. break;
  3158. //
  3159. // An EOF character is treated like a "return now" character,
  3160. // but is not reported to the user.
  3161. //
  3162. } else if (Character ==
  3163. ControlCharacters[TerminalCharacterEndOfFile]) {
  3164. CopySize = CopyIndex;
  3165. AdvanceSize = CopySize + 1;
  3166. BreakForNewline = TRUE;
  3167. break;
  3168. }
  3169. }
  3170. }
  3171. Status = MmCopyIoBufferData(
  3172. IoContext->IoBuffer,
  3173. Terminal->InputBuffer + Terminal->InputBufferStart,
  3174. BytesRead,
  3175. CopySize,
  3176. TRUE);
  3177. if (!KSUCCESS(Status)) {
  3178. break;
  3179. }
  3180. Terminal->InputBufferStart += AdvanceSize;
  3181. ASSERT(Terminal->InputBufferStart <= TERMINAL_INPUT_BUFFER_SIZE);
  3182. if (Terminal->InputBufferStart == TERMINAL_INPUT_BUFFER_SIZE) {
  3183. Terminal->InputBufferStart = 0;
  3184. }
  3185. BytesRead += CopySize;
  3186. Space += CopySize;
  3187. AnythingRead = TRUE;
  3188. //
  3189. // If this was a newline and it's canonical mode, then let the user
  3190. // chew on that.
  3191. //
  3192. if (BreakForNewline != FALSE) {
  3193. break;
  3194. }
  3195. }
  3196. ASSERT(LockHeld != FALSE);
  3197. TerminalSlaveReadEnd:
  3198. if (AnythingRead != FALSE) {
  3199. if (LockHeld == FALSE) {
  3200. KeAcquireQueuedLock(Terminal->InputLock);
  3201. LockHeld = TRUE;
  3202. }
  3203. IoSetIoObjectState(MasterIoState, POLL_EVENT_OUT, TRUE);
  3204. Space = IopTerminalGetInputBufferSpace(Terminal);
  3205. if (Space == TERMINAL_INPUT_BUFFER_SIZE - 1) {
  3206. IoSetIoObjectState(SlaveIoState, POLL_EVENT_IN, FALSE);
  3207. }
  3208. }
  3209. if (LockHeld != FALSE) {
  3210. KeReleaseQueuedLock(Terminal->InputLock);
  3211. }
  3212. if (SignalProcessGroup != FALSE) {
  3213. PsSignalProcessGroup(ProcessGroup, SIGNAL_BACKGROUND_TERMINAL_INPUT);
  3214. }
  3215. IoContext->BytesCompleted = BytesRead;
  3216. return Status;
  3217. }
  3218. KSTATUS
  3219. IopTerminalWriteOutputBuffer (
  3220. PTERMINAL Terminal,
  3221. PVOID Buffer,
  3222. UINTN SizeInBytes,
  3223. ULONG RepeatCount,
  3224. ULONG TimeoutInMilliseconds
  3225. )
  3226. /*++
  3227. Routine Description:
  3228. This routine writes data to the terminal output buffer. It assumes the
  3229. output lock is already held and it does not set any events. It may
  3230. release and reacquire the output lock during the course of the routine, but
  3231. the routine will always return with the output lock held (just like it
  3232. started with).
  3233. Arguments:
  3234. Terminal - Supplies a pointer to the terminal.
  3235. Buffer - Supplies a pointer to the buffer that contains the data to write.
  3236. SizeInBytes - Supplies the number of bytes to write.
  3237. RepeatCount - Supplies the number of times to write the buffer to the
  3238. output.
  3239. TimeoutInMilliseconds - Supplies the number of milliseconds that the I/O
  3240. operation should be waited on before timing out. Use
  3241. WAIT_TIME_INDEFINITE to wait forever on the I/O.
  3242. Return Value:
  3243. Status code.
  3244. --*/
  3245. {
  3246. UCHAR Byte;
  3247. PUCHAR ByteBuffer;
  3248. UINTN ByteIndex;
  3249. BOOL DidLeadingCharacter;
  3250. BOOL LockHeld;
  3251. ULONG Mask;
  3252. PIO_OBJECT_STATE MasterIoState;
  3253. ULONG OutputFlags;
  3254. ULONG RepeatIndex;
  3255. ULONG ReturnedEvents;
  3256. PIO_OBJECT_STATE SlaveIoState;
  3257. ULONG Space;
  3258. KSTATUS Status;
  3259. ByteBuffer = (PUCHAR)Buffer;
  3260. DidLeadingCharacter = FALSE;
  3261. LockHeld = TRUE;
  3262. OutputFlags = Terminal->Settings.OutputFlags;
  3263. MasterIoState = Terminal->MasterFileObject->IoState;
  3264. SlaveIoState = Terminal->SlaveFileObject->IoState;
  3265. Space = IopTerminalGetOutputBufferSpace(Terminal);
  3266. for (RepeatIndex = 0; RepeatIndex < RepeatCount; RepeatIndex += 1) {
  3267. for (ByteIndex = 0; ByteIndex < SizeInBytes; ByteIndex += 1) {
  3268. //
  3269. // Wait for space to become available.
  3270. //
  3271. if ((Space == 0) && (Terminal->HardwareHandle != NULL)) {
  3272. Status = IopTerminalFlushOutputToDevice(Terminal);
  3273. if (!KSUCCESS(Status)) {
  3274. goto TerminalWriteOutputBufferEnd;
  3275. }
  3276. Space = IopTerminalGetOutputBufferSpace(Terminal);
  3277. ASSERT(Space != 0);
  3278. }
  3279. while (Space == 0) {
  3280. IoSetIoObjectState(MasterIoState, POLL_EVENT_IN, TRUE);
  3281. IoSetIoObjectState(SlaveIoState, POLL_EVENT_OUT, FALSE);
  3282. KeReleaseQueuedLock(Terminal->OutputLock);
  3283. LockHeld = FALSE;
  3284. Status = IoWaitForIoObjectState(SlaveIoState,
  3285. POLL_EVENT_OUT,
  3286. TRUE,
  3287. TimeoutInMilliseconds,
  3288. &ReturnedEvents);
  3289. if (!KSUCCESS(Status)) {
  3290. goto TerminalWriteOutputBufferEnd;
  3291. }
  3292. if ((ReturnedEvents & TERMINAL_POLL_ERRORS) != 0) {
  3293. Status = STATUS_DEVICE_IO_ERROR;
  3294. goto TerminalWriteOutputBufferEnd;
  3295. }
  3296. KeAcquireQueuedLock(Terminal->OutputLock);
  3297. LockHeld = TRUE;
  3298. Space = IopTerminalGetOutputBufferSpace(Terminal);
  3299. }
  3300. //
  3301. // Process any output flags.
  3302. //
  3303. Byte = ByteBuffer[ByteIndex];
  3304. if (Byte == '\r') {
  3305. if ((OutputFlags & TERMINAL_OUTPUT_CR_TO_NEWLINE) != 0) {
  3306. Byte = '\n';
  3307. }
  3308. } else if (Byte == '\n') {
  3309. //
  3310. // If \n should be translated to \r\n, then change the byte to
  3311. // \r, and decrement the loop counter to go around again on the
  3312. // same byte. The second time around, just output the \n.
  3313. //
  3314. Mask = TERMINAL_OUTPUT_POST_PROCESS |
  3315. TERMINAL_OUTPUT_NEWLINE_TO_CRLF;
  3316. if ((OutputFlags & Mask) == Mask) {
  3317. if (DidLeadingCharacter == FALSE) {
  3318. Byte = '\r';
  3319. ByteIndex -= 1;
  3320. DidLeadingCharacter = TRUE;
  3321. } else {
  3322. DidLeadingCharacter = FALSE;
  3323. }
  3324. }
  3325. }
  3326. //
  3327. // Write the byte in.
  3328. //
  3329. Terminal->OutputBuffer[Terminal->OutputBufferEnd] = Byte;
  3330. Terminal->OutputBufferEnd += 1;
  3331. if (Terminal->OutputBufferEnd == TERMINAL_OUTPUT_BUFFER_SIZE) {
  3332. Terminal->OutputBufferEnd = 0;
  3333. }
  3334. Space -= 1;
  3335. }
  3336. }
  3337. if (Terminal->HardwareHandle != NULL) {
  3338. ASSERT(LockHeld != FALSE);
  3339. Status = IopTerminalFlushOutputToDevice(Terminal);
  3340. if (!KSUCCESS(Status)) {
  3341. goto TerminalWriteOutputBufferEnd;
  3342. }
  3343. }
  3344. Status = STATUS_SUCCESS;
  3345. TerminalWriteOutputBufferEnd:
  3346. if (LockHeld == FALSE) {
  3347. KeAcquireQueuedLock(Terminal->OutputLock);
  3348. }
  3349. return Status;
  3350. }
  3351. ULONG
  3352. IopTerminalGetInputBufferSpace (
  3353. PTERMINAL Terminal
  3354. )
  3355. /*++
  3356. Routine Description:
  3357. This routine returns the amount of space available in bytes in the input
  3358. buffer of a terminal.
  3359. Arguments:
  3360. Terminal - Supplies a pointer to the terminal.
  3361. Return Value:
  3362. returns the number of bytes available in the input buffer.
  3363. --*/
  3364. {
  3365. ULONG Space;
  3366. if (Terminal->InputBufferEnd >= Terminal->InputBufferStart) {
  3367. Space = TERMINAL_INPUT_BUFFER_SIZE - 1 -
  3368. (Terminal->InputBufferEnd - Terminal->InputBufferStart);
  3369. //
  3370. // The buffer has wrapped around.
  3371. //
  3372. } else {
  3373. Space = Terminal->InputBufferStart - Terminal->InputBufferEnd - 1;
  3374. }
  3375. return Space;
  3376. }
  3377. ULONG
  3378. IopTerminalGetOutputBufferSpace (
  3379. PTERMINAL Terminal
  3380. )
  3381. /*++
  3382. Routine Description:
  3383. This routine returns the amount of space available in bytes in the output
  3384. buffer of a terminal.
  3385. Arguments:
  3386. Terminal - Supplies a pointer to the terminal.
  3387. Return Value:
  3388. returns the number of bytes available in the output buffer.
  3389. --*/
  3390. {
  3391. ULONG Space;
  3392. if (Terminal->OutputBufferEnd >= Terminal->OutputBufferStart) {
  3393. Space = TERMINAL_OUTPUT_BUFFER_SIZE - 1 -
  3394. (Terminal->OutputBufferEnd - Terminal->OutputBufferStart);
  3395. //
  3396. // The buffer has wrapped around.
  3397. //
  3398. } else {
  3399. Space = Terminal->OutputBufferStart - Terminal->OutputBufferEnd - 1;
  3400. }
  3401. return Space;
  3402. }
  3403. KSTATUS
  3404. IopTerminalFixUpCanonicalLine (
  3405. PTERMINAL Terminal,
  3406. ULONG TimeoutInMilliseconds,
  3407. ULONG DirtyRegionBegin,
  3408. ULONG DirtyRegionEnd,
  3409. ULONG CurrentScreenPosition
  3410. )
  3411. /*++
  3412. Routine Description:
  3413. This routine fixes up the terminal output for canonical mode processing
  3414. either when a block of input or a valid line is finished. It does not
  3415. acquire any locks or set any events, it assumes that is handled by the
  3416. caller. Specifically, the working input lock and output lock must both
  3417. be held.
  3418. Arguments:
  3419. Terminal - Supplies a pointer to the terminal.
  3420. TimeoutInMilliseconds - Supplies the amount of time to wait for output
  3421. operations before giving up.
  3422. DirtyRegionBegin - Supplies the first character in the dirty region, as an
  3423. offset in characters from the beginning of the line. The beginning of
  3424. the line may not be column zero.
  3425. DirtyRegionEnd - Supplies the first character not in the dirty region, as
  3426. an offset in characters from the beginning of the line.
  3427. CurrentScreenPosition - Supplies the position of the screen's cursor as an
  3428. offset in characters from the beginning of the line.
  3429. Return Value:
  3430. Status code.
  3431. --*/
  3432. {
  3433. CHAR Character;
  3434. PCHAR ControlCharacters;
  3435. KSTATUS Status;
  3436. ULONG ValidLineEnd;
  3437. ULONG WorkingInputLength;
  3438. ControlCharacters = Terminal->Settings.ControlCharacters;
  3439. //
  3440. // If the last character is a newline, pretend it's not there.
  3441. //
  3442. WorkingInputLength = Terminal->WorkingInputLength;
  3443. if ((WorkingInputLength != 0) &&
  3444. ((Terminal->WorkingInputBuffer[WorkingInputLength - 1] ==
  3445. ControlCharacters[TerminalCharacterEndOfLine]) ||
  3446. (Terminal->WorkingInputBuffer[WorkingInputLength - 1] == '\n'))) {
  3447. WorkingInputLength -= 1;
  3448. }
  3449. //
  3450. // Back up to the start of the dirty region.
  3451. //
  3452. ASSERT(DirtyRegionBegin <= CurrentScreenPosition);
  3453. if (DirtyRegionBegin < CurrentScreenPosition) {
  3454. Character = '\b';
  3455. Status = IopTerminalWriteOutputBuffer(
  3456. Terminal,
  3457. &Character,
  3458. 1,
  3459. CurrentScreenPosition - DirtyRegionBegin,
  3460. TimeoutInMilliseconds);
  3461. if (!KSUCCESS(Status)) {
  3462. goto TerminalFixUpCanonicalLineEnd;
  3463. }
  3464. CurrentScreenPosition = DirtyRegionBegin;
  3465. }
  3466. //
  3467. // Write out the portion of the dirty region that's still a valid line.
  3468. //
  3469. ValidLineEnd = DirtyRegionEnd;
  3470. if (WorkingInputLength < ValidLineEnd) {
  3471. ValidLineEnd = WorkingInputLength;
  3472. }
  3473. if (ValidLineEnd > DirtyRegionBegin) {
  3474. Status = IopTerminalWriteOutputBuffer(
  3475. Terminal,
  3476. Terminal->WorkingInputBuffer + DirtyRegionBegin,
  3477. ValidLineEnd - DirtyRegionBegin,
  3478. 1,
  3479. TimeoutInMilliseconds);
  3480. if (!KSUCCESS(Status)) {
  3481. goto TerminalFixUpCanonicalLineEnd;
  3482. }
  3483. CurrentScreenPosition += ValidLineEnd - DirtyRegionBegin;
  3484. }
  3485. //
  3486. // Write spaces to erase any additional portion that goes beyond the valid
  3487. // line end.
  3488. //
  3489. if (CurrentScreenPosition < DirtyRegionEnd) {
  3490. Character = ' ';
  3491. Status = IopTerminalWriteOutputBuffer(
  3492. Terminal,
  3493. &Character,
  3494. 1,
  3495. DirtyRegionEnd - CurrentScreenPosition,
  3496. TimeoutInMilliseconds);
  3497. if (!KSUCCESS(Status)) {
  3498. goto TerminalFixUpCanonicalLineEnd;
  3499. }
  3500. CurrentScreenPosition = DirtyRegionEnd;
  3501. }
  3502. //
  3503. // Finally, back up to the cursor position.
  3504. //
  3505. if (CurrentScreenPosition > Terminal->WorkingInputCursor) {
  3506. Character = '\b';
  3507. Status = IopTerminalWriteOutputBuffer(
  3508. Terminal,
  3509. &Character,
  3510. 1,
  3511. CurrentScreenPosition - Terminal->WorkingInputCursor,
  3512. TimeoutInMilliseconds);
  3513. if (!KSUCCESS(Status)) {
  3514. goto TerminalFixUpCanonicalLineEnd;
  3515. }
  3516. }
  3517. Status = STATUS_SUCCESS;
  3518. TerminalFixUpCanonicalLineEnd:
  3519. return Status;
  3520. }
  3521. BOOL
  3522. IopTerminalProcessEditingCharacter (
  3523. PTERMINAL Terminal,
  3524. CHAR Character,
  3525. ULONG TimeoutInMilliseconds,
  3526. PULONG DirtyRegionBegin,
  3527. PULONG DirtyRegionEnd,
  3528. PULONG ScreenCursorPosition,
  3529. PBOOL OutputWritten
  3530. )
  3531. /*++
  3532. Routine Description:
  3533. This routine processes any characters that change the working buffer in a
  3534. non-straightforward way. This routine operates in canonical mode only.
  3535. Arguments:
  3536. Terminal - Supplies a pointer to the terminal.
  3537. Character - Supplies the character to process.
  3538. TimeoutInMilliseconds - Supplies the number of milliseconds to wait if the
  3539. output buffer is written to.
  3540. DirtyRegionBegin - Supplies a pointer that contains the region of the line
  3541. that needs to be redrawn. This may get expanded on output.
  3542. DirtyRegionEnd - Supplies a pointer that contains the end of the region of
  3543. the line that needs to be redrawn. This also may get expanded on
  3544. output.
  3545. ScreenCursorPosition - Supplies a pointer that contains the screen's
  3546. current cursor position on input, and may get altered on output.
  3547. OutputWritten - Supplies a pointer where TRUE will be returned if the
  3548. output buffer was written to. Otherwise, this value will be left
  3549. untouched.
  3550. Return Value:
  3551. TRUE if the byte was handled by this routine and should not be added to the
  3552. working buffer.
  3553. FALSE if the character was not handled by this routine.
  3554. --*/
  3555. {
  3556. TERMINAL_COMMAND_DATA CommandData;
  3557. PCHAR ControlCharacters;
  3558. UINTN LastIndex;
  3559. ULONG LocalFlags;
  3560. UINTN MoveIndex;
  3561. CHAR OutputString[TERMINAL_MAX_CANONICAL_OUTPUT];
  3562. UINTN OutputStringLength;
  3563. TERMINAL_PARSE_RESULT ParseResult;
  3564. BOOL Result;
  3565. ControlCharacters = Terminal->Settings.ControlCharacters;
  3566. LocalFlags = Terminal->Settings.LocalFlags;
  3567. ParseResult = TermProcessInput(&(Terminal->KeyData), Character);
  3568. switch (ParseResult) {
  3569. case TerminalParseResultNormalCharacter:
  3570. //
  3571. // Erase backs up one.
  3572. //
  3573. Result = FALSE;
  3574. if (Character == ControlCharacters[TerminalCharacterErase]) {
  3575. if (Terminal->WorkingInputCursor != 0) {
  3576. Terminal->WorkingInputCursor -= 1;
  3577. ASSERT(Terminal->WorkingInputLength != 0);
  3578. //
  3579. // Potentially expand the portion of the screen that will
  3580. // need cleaning up.
  3581. //
  3582. if ((LocalFlags & TERMINAL_LOCAL_ECHO_ERASE) != 0) {
  3583. if (Terminal->WorkingInputCursor < *DirtyRegionBegin) {
  3584. *DirtyRegionBegin = Terminal->WorkingInputCursor;
  3585. }
  3586. if (Terminal->WorkingInputLength + 1 > *DirtyRegionEnd) {
  3587. *DirtyRegionEnd = Terminal->WorkingInputLength + 1;
  3588. }
  3589. //
  3590. // If not echoing erase, print the character that was just
  3591. // erased to indicate what happened. This is useful for
  3592. // line printers.
  3593. //
  3594. } else {
  3595. LastIndex = Terminal->WorkingInputCursor + 1;
  3596. OutputString[0] = Terminal->WorkingInputBuffer[LastIndex];
  3597. IopTerminalWriteOutputBuffer(Terminal,
  3598. OutputString,
  3599. 1,
  3600. 1,
  3601. TimeoutInMilliseconds);
  3602. }
  3603. //
  3604. // Move the characters after the cursor back one.
  3605. //
  3606. for (MoveIndex = Terminal->WorkingInputCursor;
  3607. MoveIndex < Terminal->WorkingInputLength - 1;
  3608. MoveIndex += 1) {
  3609. Terminal->WorkingInputBuffer[MoveIndex] =
  3610. Terminal->WorkingInputBuffer[MoveIndex + 1];
  3611. }
  3612. Terminal->WorkingInputLength -= 1;
  3613. }
  3614. Result = TRUE;
  3615. //
  3616. // Kill erases the whole line.
  3617. //
  3618. } else if (Character == ControlCharacters[TerminalCharacterKill]) {
  3619. //
  3620. // If the extended bit is set, visually erase the whole line.
  3621. //
  3622. if ((LocalFlags & TERMINAL_LOCAL_ECHO_KILL_EXTENDED) != 0) {
  3623. Result = TRUE;
  3624. *DirtyRegionBegin = 0;
  3625. if (Terminal->WorkingInputLength > *DirtyRegionEnd) {
  3626. *DirtyRegionEnd = Terminal->WorkingInputLength;
  3627. }
  3628. //
  3629. // Otherwise if the old echo kill is set, add a newline.
  3630. //
  3631. } else if ((LocalFlags & TERMINAL_LOCAL_ECHO_KILL_NEWLINE) != 0) {
  3632. Result = TRUE;
  3633. OutputString[0] = Character;
  3634. OutputString[1] = '\n';
  3635. IopTerminalWriteOutputBuffer(Terminal,
  3636. OutputString,
  3637. 2,
  3638. 1,
  3639. TimeoutInMilliseconds);
  3640. //
  3641. // Just echo the kill character.
  3642. //
  3643. } else {
  3644. Result = FALSE;
  3645. }
  3646. Terminal->WorkingInputCursor = 0;
  3647. Terminal->WorkingInputLength = 0;
  3648. Terminal->Flags &= ~(TERMINAL_FLAG_VIRGIN_LINE |
  3649. TERMINAL_FLAG_UNEDITED_LINE);
  3650. //
  3651. // These other characters are simply not printed.
  3652. //
  3653. } else {
  3654. if ((Character == ControlCharacters[TerminalCharacterStart]) ||
  3655. (Character == ControlCharacters[TerminalCharacterStop])) {
  3656. Result = TRUE;
  3657. }
  3658. }
  3659. return Result;
  3660. case TerminalParseResultPartialCommand:
  3661. return TRUE;
  3662. case TerminalParseResultCompleteCommand:
  3663. break;
  3664. default:
  3665. ASSERT(FALSE);
  3666. return FALSE;
  3667. }
  3668. //
  3669. // Handle the complete key that just came in.
  3670. //
  3671. RtlZeroMemory(&CommandData, sizeof(TERMINAL_COMMAND_DATA));
  3672. switch (Terminal->KeyData.Key) {
  3673. case TerminalKeyPageUp:
  3674. case TerminalKeyPageDown:
  3675. if (Terminal->KeyData.Key == TerminalKeyPageUp) {
  3676. CommandData.Command = TerminalCommandScrollUp;
  3677. } else {
  3678. CommandData.Command = TerminalCommandScrollDown;
  3679. }
  3680. CommandData.ParameterCount = 1;
  3681. CommandData.Parameter[0] = TERMINAL_SCROLL_LINE_COUNT;
  3682. Result = TermCreateOutputSequence(&CommandData,
  3683. OutputString,
  3684. sizeof(OutputString));
  3685. if (Result != FALSE) {
  3686. OutputString[sizeof(OutputString) - 1] = '\0';
  3687. OutputStringLength = RtlStringLength(OutputString);
  3688. IopTerminalWriteOutputBuffer(Terminal,
  3689. OutputString,
  3690. OutputStringLength,
  3691. 1,
  3692. TimeoutInMilliseconds);
  3693. *OutputWritten = TRUE;
  3694. }
  3695. break;
  3696. case TerminalKeyRight:
  3697. if (Terminal->WorkingInputCursor != Terminal->WorkingInputLength) {
  3698. Terminal->WorkingInputCursor += 1;
  3699. if (Terminal->WorkingInputCursor > *DirtyRegionEnd) {
  3700. *DirtyRegionEnd = Terminal->WorkingInputCursor;
  3701. }
  3702. }
  3703. break;
  3704. case TerminalKeyLeft:
  3705. if (Terminal->WorkingInputCursor != 0) {
  3706. Terminal->WorkingInputCursor -= 1;
  3707. if (Terminal->WorkingInputCursor < *DirtyRegionBegin) {
  3708. *DirtyRegionBegin = Terminal->WorkingInputCursor;
  3709. }
  3710. }
  3711. break;
  3712. default:
  3713. break;
  3714. }
  3715. return TRUE;
  3716. }
  3717. KSTATUS
  3718. IopTerminalUserBufferCopy (
  3719. BOOL FromKernelMode,
  3720. BOOL FromBuffer,
  3721. PVOID UserBuffer,
  3722. PVOID LocalBuffer,
  3723. UINTN Size
  3724. )
  3725. /*++
  3726. Routine Description:
  3727. This routine copies to or from a user mode or kernel mode buffer.
  3728. Arguments:
  3729. FromKernelMode - Supplies a boolean indicating whether or not this request
  3730. (and the buffer associated with it) originates from user mode (FALSE)
  3731. or kernel mode (TRUE).
  3732. FromBuffer - Supplies a boolean indicating whether to copy to the user
  3733. buffer (FALSE) or from the user buffer (TRUE).
  3734. UserBuffer - Supplies the user buffer pointer.
  3735. LocalBuffer - Supplies the local kernel mode buffer.
  3736. Size - Supplies the number of bytes to copy.
  3737. Return Value:
  3738. Status code.
  3739. --*/
  3740. {
  3741. KSTATUS Status;
  3742. //
  3743. // If the caller says it's from kernel mode, it better be a kernel mode
  3744. // address.
  3745. //
  3746. ASSERT((UserBuffer >= KERNEL_VA_START) || (FromKernelMode == FALSE));
  3747. Status = STATUS_SUCCESS;
  3748. if (FromBuffer != FALSE) {
  3749. if (FromKernelMode != FALSE) {
  3750. RtlCopyMemory(LocalBuffer, UserBuffer, Size);
  3751. } else {
  3752. Status = MmCopyFromUserMode(LocalBuffer, UserBuffer, Size);
  3753. }
  3754. } else {
  3755. if (FromKernelMode != FALSE) {
  3756. RtlCopyMemory(UserBuffer, LocalBuffer, Size);
  3757. } else {
  3758. Status = MmCopyToUserMode(UserBuffer, LocalBuffer, Size);
  3759. }
  3760. }
  3761. return Status;
  3762. }
  3763. KSTATUS
  3764. IopTerminalFlushOutputToDevice (
  3765. PTERMINAL Terminal
  3766. )
  3767. /*++
  3768. Routine Description:
  3769. This routine writes the currently buffered output data to the hardware
  3770. device. This routine assumes the output lock is already held.
  3771. Arguments:
  3772. Terminal - Supplies a pointer to the terminal whose output data should be
  3773. flushed.
  3774. Return Value:
  3775. Status code.
  3776. --*/
  3777. {
  3778. UINTN BytesWritten;
  3779. IO_BUFFER IoBuffer;
  3780. UINTN Size;
  3781. KSTATUS Status;
  3782. ASSERT(Terminal->HardwareHandle != NULL);
  3783. Status = STATUS_SUCCESS;
  3784. //
  3785. // Loop writing portions of the output buffer.
  3786. //
  3787. while (TRUE) {
  3788. //
  3789. // If the start is greater than the end, then the buffer has wrapped
  3790. // around and needs to be written in two steps.
  3791. //
  3792. if (Terminal->OutputBufferEnd < Terminal->OutputBufferStart) {
  3793. Size = TERMINAL_OUTPUT_BUFFER_SIZE - Terminal->OutputBufferStart;
  3794. Status = MmInitializeIoBuffer(
  3795. &IoBuffer,
  3796. Terminal->OutputBuffer + Terminal->OutputBufferStart,
  3797. INVALID_PHYSICAL_ADDRESS,
  3798. Size,
  3799. IO_BUFFER_FLAG_KERNEL_MODE_DATA);
  3800. if (!KSUCCESS(Status)) {
  3801. return Status;
  3802. }
  3803. Status = IoWrite(Terminal->HardwareHandle,
  3804. &IoBuffer,
  3805. Size,
  3806. 0,
  3807. WAIT_TIME_INDEFINITE,
  3808. &BytesWritten);
  3809. if (!KSUCCESS(Status)) {
  3810. return Status;
  3811. }
  3812. Terminal->OutputBufferStart += BytesWritten;
  3813. if (Terminal->OutputBufferStart == TERMINAL_OUTPUT_BUFFER_SIZE) {
  3814. Terminal->OutputBufferStart = 0;
  3815. }
  3816. continue;
  3817. }
  3818. //
  3819. // If the buffer is empty, stop.
  3820. //
  3821. if (Terminal->OutputBufferStart == Terminal->OutputBufferEnd) {
  3822. break;
  3823. }
  3824. Size = Terminal->OutputBufferEnd - Terminal->OutputBufferStart;
  3825. Status = MmInitializeIoBuffer(
  3826. &IoBuffer,
  3827. Terminal->OutputBuffer + Terminal->OutputBufferStart,
  3828. INVALID_PHYSICAL_ADDRESS,
  3829. Size,
  3830. IO_BUFFER_FLAG_KERNEL_MODE_DATA);
  3831. if (!KSUCCESS(Status)) {
  3832. return Status;
  3833. }
  3834. Status = IoWrite(Terminal->HardwareHandle,
  3835. &IoBuffer,
  3836. Size,
  3837. 0,
  3838. WAIT_TIME_INDEFINITE,
  3839. &BytesWritten);
  3840. if (!KSUCCESS(Status)) {
  3841. return Status;
  3842. }
  3843. Terminal->OutputBufferStart += BytesWritten;
  3844. ASSERT(Terminal->OutputBufferStart != TERMINAL_OUTPUT_BUFFER_SIZE);
  3845. }
  3846. return Status;
  3847. }
  3848. VOID
  3849. IopTerminalDisassociate (
  3850. PTERMINAL Terminal
  3851. )
  3852. /*++
  3853. Routine Description:
  3854. This routine clears the controlling terminal from every process in the
  3855. terminal's session. This routine assumes the terminal list lock and
  3856. terminal locks are already held.
  3857. Arguments:
  3858. Terminal - Supplies a pointer to the controlling terminal.
  3859. Return Value:
  3860. None.
  3861. --*/
  3862. {
  3863. SESSION_ID SessionId;
  3864. SessionId = Terminal->SessionId;
  3865. if (SessionId != TERMINAL_INVALID_SESSION) {
  3866. PsIterateProcess(ProcessIdSession,
  3867. SessionId,
  3868. IopTerminalDisassociateIterator,
  3869. NULL);
  3870. }
  3871. Terminal->SessionId = TERMINAL_INVALID_SESSION;
  3872. Terminal->ProcessGroupId = TERMINAL_INVALID_PROCESS_GROUP;
  3873. return;
  3874. }
  3875. BOOL
  3876. IopTerminalDisassociateIterator (
  3877. PVOID Context,
  3878. PKPROCESS Process
  3879. )
  3880. /*++
  3881. Routine Description:
  3882. This routine describes the prototype for the process list iterator. This
  3883. routine is called with the process list lock held.
  3884. Arguments:
  3885. Context - Supplies a pointer's worth of context passed into the iterate
  3886. routine.
  3887. Process - Supplies the process to examine.
  3888. Return Value:
  3889. FALSE always to indicate continuing to iterate.
  3890. --*/
  3891. {
  3892. Process->ControllingTerminal = NULL;
  3893. return FALSE;
  3894. }