command.c 103 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221
  1. /*
  2. Command interpreter routine for virtual terminal [aka TeletYpe]
  3. Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
  4. Copyright (C) 2013 by Open Source Routing.
  5. Copyright (C) 2013 by Internet Systems Consortium, Inc. ("ISC")
  6. This file is part of GNU Zebra.
  7. GNU Zebra is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published
  9. by the Free Software Foundation; either version 2, or (at your
  10. option) any later version.
  11. GNU Zebra is distributed in the hope that it will be useful, but
  12. WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. General Public License for more details.
  15. You should have received a copy of the GNU General Public License
  16. along with GNU Zebra; see the file COPYING. If not, write to the
  17. Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  18. Boston, MA 02111-1307, USA. */
  19. #include <zebra.h>
  20. #include "memory.h"
  21. #include "log.h"
  22. #include <lib/version.h>
  23. #include "thread.h"
  24. #include "vector.h"
  25. #include "vty.h"
  26. #include "command.h"
  27. #include "workqueue.h"
  28. /* Command vector which includes some level of command lists. Normally
  29. each daemon maintains each own cmdvec. */
  30. vector cmdvec = NULL;
  31. struct cmd_token token_cr;
  32. char *command_cr = NULL;
  33. enum filter_type
  34. {
  35. FILTER_RELAXED,
  36. FILTER_STRICT
  37. };
  38. enum matcher_rv
  39. {
  40. MATCHER_OK,
  41. MATCHER_COMPLETE,
  42. MATCHER_INCOMPLETE,
  43. MATCHER_NO_MATCH,
  44. MATCHER_AMBIGUOUS,
  45. MATCHER_EXCEED_ARGC_MAX
  46. };
  47. #define MATCHER_ERROR(matcher_rv) \
  48. ( (matcher_rv) == MATCHER_INCOMPLETE \
  49. || (matcher_rv) == MATCHER_NO_MATCH \
  50. || (matcher_rv) == MATCHER_AMBIGUOUS \
  51. || (matcher_rv) == MATCHER_EXCEED_ARGC_MAX \
  52. )
  53. /* Host information structure. */
  54. struct host host;
  55. /* Standard command node structures. */
  56. static struct cmd_node auth_node =
  57. {
  58. AUTH_NODE,
  59. "Password: ",
  60. };
  61. static struct cmd_node view_node =
  62. {
  63. VIEW_NODE,
  64. "%s> ",
  65. };
  66. static struct cmd_node restricted_node =
  67. {
  68. RESTRICTED_NODE,
  69. "%s$ ",
  70. };
  71. static struct cmd_node auth_enable_node =
  72. {
  73. AUTH_ENABLE_NODE,
  74. "Password: ",
  75. };
  76. static struct cmd_node enable_node =
  77. {
  78. ENABLE_NODE,
  79. "%s# ",
  80. };
  81. static struct cmd_node config_node =
  82. {
  83. CONFIG_NODE,
  84. "%s(config)# ",
  85. 1
  86. };
  87. /* Default motd string. */
  88. static const char *default_motd =
  89. "\r\n\
  90. Hello, this is " QUAGGA_PROGNAME " (version " QUAGGA_VERSION ").\r\n\
  91. " QUAGGA_COPYRIGHT "\r\n\
  92. " GIT_INFO "\r\n";
  93. static const struct facility_map {
  94. int facility;
  95. const char *name;
  96. size_t match;
  97. } syslog_facilities[] =
  98. {
  99. { LOG_KERN, "kern", 1 },
  100. { LOG_USER, "user", 2 },
  101. { LOG_MAIL, "mail", 1 },
  102. { LOG_DAEMON, "daemon", 1 },
  103. { LOG_AUTH, "auth", 1 },
  104. { LOG_SYSLOG, "syslog", 1 },
  105. { LOG_LPR, "lpr", 2 },
  106. { LOG_NEWS, "news", 1 },
  107. { LOG_UUCP, "uucp", 2 },
  108. { LOG_CRON, "cron", 1 },
  109. #ifdef LOG_FTP
  110. { LOG_FTP, "ftp", 1 },
  111. #endif
  112. { LOG_LOCAL0, "local0", 6 },
  113. { LOG_LOCAL1, "local1", 6 },
  114. { LOG_LOCAL2, "local2", 6 },
  115. { LOG_LOCAL3, "local3", 6 },
  116. { LOG_LOCAL4, "local4", 6 },
  117. { LOG_LOCAL5, "local5", 6 },
  118. { LOG_LOCAL6, "local6", 6 },
  119. { LOG_LOCAL7, "local7", 6 },
  120. { 0, NULL, 0 },
  121. };
  122. static const char *
  123. facility_name(int facility)
  124. {
  125. const struct facility_map *fm;
  126. for (fm = syslog_facilities; fm->name; fm++)
  127. if (fm->facility == facility)
  128. return fm->name;
  129. return "";
  130. }
  131. static int
  132. facility_match(const char *str)
  133. {
  134. const struct facility_map *fm;
  135. for (fm = syslog_facilities; fm->name; fm++)
  136. if (!strncmp(str,fm->name,fm->match))
  137. return fm->facility;
  138. return -1;
  139. }
  140. static int
  141. level_match(const char *s)
  142. {
  143. int level ;
  144. for ( level = 0 ; zlog_priority [level] != NULL ; level ++ )
  145. if (!strncmp (s, zlog_priority[level], 2))
  146. return level;
  147. return ZLOG_DISABLED;
  148. }
  149. /* This is called from main when a daemon is invoked with -v or --version. */
  150. void
  151. print_version (const char *progname)
  152. {
  153. printf ("%s version %s\n", progname, QUAGGA_VERSION);
  154. printf ("%s\n", QUAGGA_COPYRIGHT);
  155. }
  156. /* Utility function to concatenate argv argument into a single string
  157. with inserting ' ' character between each argument. */
  158. char *
  159. argv_concat (const char **argv, int argc, int shift)
  160. {
  161. int i;
  162. size_t len;
  163. char *str;
  164. char *p;
  165. len = 0;
  166. for (i = shift; i < argc; i++)
  167. len += strlen(argv[i])+1;
  168. if (!len)
  169. return NULL;
  170. p = str = XMALLOC(MTYPE_TMP, len);
  171. for (i = shift; i < argc; i++)
  172. {
  173. size_t arglen;
  174. memcpy(p, argv[i], (arglen = strlen(argv[i])));
  175. p += arglen;
  176. *p++ = ' ';
  177. }
  178. *(p-1) = '\0';
  179. return str;
  180. }
  181. /* Install top node of command vector. */
  182. void
  183. install_node (struct cmd_node *node,
  184. int (*func) (struct vty *))
  185. {
  186. vector_set_index (cmdvec, node->node, node);
  187. node->func = func;
  188. node->cmd_vector = vector_init (VECTOR_MIN_SIZE);
  189. }
  190. /* Breaking up string into each command piece. I assume given
  191. character is separated by a space character. Return value is a
  192. vector which includes char ** data element. */
  193. vector
  194. cmd_make_strvec (const char *string)
  195. {
  196. const char *cp, *start;
  197. char *token;
  198. int strlen;
  199. vector strvec;
  200. if (string == NULL)
  201. return NULL;
  202. cp = string;
  203. /* Skip white spaces. */
  204. while (isspace ((int) *cp) && *cp != '\0')
  205. cp++;
  206. /* Return if there is only white spaces */
  207. if (*cp == '\0')
  208. return NULL;
  209. if (*cp == '!' || *cp == '#')
  210. return NULL;
  211. /* Prepare return vector. */
  212. strvec = vector_init (VECTOR_MIN_SIZE);
  213. /* Copy each command piece and set into vector. */
  214. while (1)
  215. {
  216. start = cp;
  217. while (!(isspace ((int) *cp) || *cp == '\r' || *cp == '\n') &&
  218. *cp != '\0')
  219. cp++;
  220. strlen = cp - start;
  221. token = XMALLOC (MTYPE_STRVEC, strlen + 1);
  222. memcpy (token, start, strlen);
  223. *(token + strlen) = '\0';
  224. vector_set (strvec, token);
  225. while ((isspace ((int) *cp) || *cp == '\n' || *cp == '\r') &&
  226. *cp != '\0')
  227. cp++;
  228. if (*cp == '\0')
  229. return strvec;
  230. }
  231. }
  232. /* Free allocated string vector. */
  233. void
  234. cmd_free_strvec (vector v)
  235. {
  236. unsigned int i;
  237. char *cp;
  238. if (!v)
  239. return;
  240. for (i = 0; i < vector_active (v); i++)
  241. if ((cp = vector_slot (v, i)) != NULL)
  242. XFREE (MTYPE_STRVEC, cp);
  243. vector_free (v);
  244. }
  245. struct format_parser_state
  246. {
  247. vector topvect; /* Top level vector */
  248. vector intvect; /* Intermediate level vector, used when there's
  249. * a multiple in a keyword. */
  250. vector curvect; /* current vector where read tokens should be
  251. appended. */
  252. const char *string; /* pointer to command string, not modified */
  253. const char *cp; /* pointer in command string, moved along while
  254. parsing */
  255. const char *dp; /* pointer in description string, moved along while
  256. parsing */
  257. int in_keyword; /* flag to remember if we are in a keyword group */
  258. int in_multiple; /* flag to remember if we are in a multiple group */
  259. int just_read_word; /* flag to remember if the last thing we red was a
  260. * real word and not some abstract token */
  261. };
  262. static void
  263. format_parser_error(struct format_parser_state *state, const char *message)
  264. {
  265. int offset = state->cp - state->string + 1;
  266. fprintf(stderr, "\nError parsing command: \"%s\"\n", state->string);
  267. fprintf(stderr, " %*c\n", offset, '^');
  268. fprintf(stderr, "%s at offset %d.\n", message, offset);
  269. fprintf(stderr, "This is a programming error. Check your DEFUNs etc.\n");
  270. exit(1);
  271. }
  272. static char *
  273. format_parser_desc_str(struct format_parser_state *state)
  274. {
  275. const char *cp, *start;
  276. char *token;
  277. int strlen;
  278. cp = state->dp;
  279. if (cp == NULL)
  280. return NULL;
  281. /* Skip white spaces. */
  282. while (isspace ((int) *cp) && *cp != '\0')
  283. cp++;
  284. /* Return if there is only white spaces */
  285. if (*cp == '\0')
  286. return NULL;
  287. start = cp;
  288. while (!(*cp == '\r' || *cp == '\n') && *cp != '\0')
  289. cp++;
  290. strlen = cp - start;
  291. token = XMALLOC (MTYPE_CMD_TOKENS, strlen + 1);
  292. memcpy (token, start, strlen);
  293. *(token + strlen) = '\0';
  294. state->dp = cp;
  295. return token;
  296. }
  297. static void
  298. format_parser_begin_keyword(struct format_parser_state *state)
  299. {
  300. struct cmd_token *token;
  301. vector keyword_vect;
  302. if (state->in_keyword
  303. || state->in_multiple)
  304. format_parser_error(state, "Unexpected '{'");
  305. state->cp++;
  306. state->in_keyword = 1;
  307. token = XCALLOC(MTYPE_CMD_TOKENS, sizeof(*token));
  308. token->type = TOKEN_KEYWORD;
  309. token->keyword = vector_init(VECTOR_MIN_SIZE);
  310. keyword_vect = vector_init(VECTOR_MIN_SIZE);
  311. vector_set(token->keyword, keyword_vect);
  312. vector_set(state->curvect, token);
  313. state->curvect = keyword_vect;
  314. }
  315. static void
  316. format_parser_begin_multiple(struct format_parser_state *state)
  317. {
  318. struct cmd_token *token;
  319. if (state->in_keyword == 1)
  320. format_parser_error(state, "Keyword starting with '('");
  321. if (state->in_multiple)
  322. format_parser_error(state, "Nested group");
  323. state->cp++;
  324. state->in_multiple = 1;
  325. state->just_read_word = 0;
  326. token = XCALLOC(MTYPE_CMD_TOKENS, sizeof(*token));
  327. token->type = TOKEN_MULTIPLE;
  328. token->multiple = vector_init(VECTOR_MIN_SIZE);
  329. vector_set(state->curvect, token);
  330. if (state->curvect != state->topvect)
  331. state->intvect = state->curvect;
  332. state->curvect = token->multiple;
  333. }
  334. static void
  335. format_parser_end_keyword(struct format_parser_state *state)
  336. {
  337. if (state->in_multiple
  338. || !state->in_keyword)
  339. format_parser_error(state, "Unexpected '}'");
  340. if (state->in_keyword == 1)
  341. format_parser_error(state, "Empty keyword group");
  342. state->cp++;
  343. state->in_keyword = 0;
  344. state->curvect = state->topvect;
  345. }
  346. static void
  347. format_parser_end_multiple(struct format_parser_state *state)
  348. {
  349. char *dummy;
  350. if (!state->in_multiple)
  351. format_parser_error(state, "Unepexted ')'");
  352. if (vector_active(state->curvect) == 0)
  353. format_parser_error(state, "Empty multiple section");
  354. if (!state->just_read_word)
  355. {
  356. /* There are constructions like
  357. * 'show ip ospf database ... (self-originate|)'
  358. * in use.
  359. * The old parser reads a description string for the
  360. * word '' between |) which will never match.
  361. * Simulate this behvaior by dropping the next desc
  362. * string in such a case. */
  363. dummy = format_parser_desc_str(state);
  364. XFREE(MTYPE_CMD_TOKENS, dummy);
  365. }
  366. state->cp++;
  367. state->in_multiple = 0;
  368. if (state->intvect)
  369. state->curvect = state->intvect;
  370. else
  371. state->curvect = state->topvect;
  372. }
  373. static void
  374. format_parser_handle_pipe(struct format_parser_state *state)
  375. {
  376. struct cmd_token *keyword_token;
  377. vector keyword_vect;
  378. if (state->in_multiple)
  379. {
  380. state->just_read_word = 0;
  381. state->cp++;
  382. }
  383. else if (state->in_keyword)
  384. {
  385. state->in_keyword = 1;
  386. state->cp++;
  387. keyword_token = vector_slot(state->topvect,
  388. vector_active(state->topvect) - 1);
  389. keyword_vect = vector_init(VECTOR_MIN_SIZE);
  390. vector_set(keyword_token->keyword, keyword_vect);
  391. state->curvect = keyword_vect;
  392. }
  393. else
  394. {
  395. format_parser_error(state, "Unexpected '|'");
  396. }
  397. }
  398. static void
  399. format_parser_read_word(struct format_parser_state *state)
  400. {
  401. const char *start;
  402. int len;
  403. char *cmd;
  404. struct cmd_token *token;
  405. start = state->cp;
  406. while (state->cp[0] != '\0'
  407. && !strchr("\r\n(){}|", state->cp[0])
  408. && !isspace((int)state->cp[0]))
  409. state->cp++;
  410. len = state->cp - start;
  411. cmd = XMALLOC(MTYPE_CMD_TOKENS, len + 1);
  412. memcpy(cmd, start, len);
  413. cmd[len] = '\0';
  414. token = XCALLOC(MTYPE_CMD_TOKENS, sizeof(*token));
  415. token->type = TOKEN_TERMINAL;
  416. token->cmd = cmd;
  417. token->desc = format_parser_desc_str(state);
  418. vector_set(state->curvect, token);
  419. if (state->in_keyword == 1)
  420. state->in_keyword = 2;
  421. state->just_read_word = 1;
  422. }
  423. /**
  424. * Parse a given command format string and build a tree of tokens from
  425. * it that is suitable to be used by the command subsystem.
  426. *
  427. * @param string Command format string.
  428. * @param descstr Description string.
  429. * @return A vector of struct cmd_token representing the given command,
  430. * or NULL on error.
  431. */
  432. static vector
  433. cmd_parse_format(const char *string, const char *descstr)
  434. {
  435. struct format_parser_state state;
  436. if (string == NULL)
  437. return NULL;
  438. memset(&state, 0, sizeof(state));
  439. state.topvect = state.curvect = vector_init(VECTOR_MIN_SIZE);
  440. state.cp = state.string = string;
  441. state.dp = descstr;
  442. while (1)
  443. {
  444. while (isspace((int)state.cp[0]) && state.cp[0] != '\0')
  445. state.cp++;
  446. switch (state.cp[0])
  447. {
  448. case '\0':
  449. if (state.in_keyword
  450. || state.in_multiple)
  451. format_parser_error(&state, "Unclosed group/keyword");
  452. return state.topvect;
  453. case '{':
  454. format_parser_begin_keyword(&state);
  455. break;
  456. case '(':
  457. format_parser_begin_multiple(&state);
  458. break;
  459. case '}':
  460. format_parser_end_keyword(&state);
  461. break;
  462. case ')':
  463. format_parser_end_multiple(&state);
  464. break;
  465. case '|':
  466. format_parser_handle_pipe(&state);
  467. break;
  468. default:
  469. format_parser_read_word(&state);
  470. }
  471. }
  472. }
  473. /* Return prompt character of specified node. */
  474. const char *
  475. cmd_prompt (enum node_type node)
  476. {
  477. struct cmd_node *cnode;
  478. cnode = vector_slot (cmdvec, node);
  479. return cnode->prompt;
  480. }
  481. /* Install a command into a node. */
  482. void
  483. install_element (enum node_type ntype, struct cmd_element *cmd)
  484. {
  485. struct cmd_node *cnode;
  486. /* cmd_init hasn't been called */
  487. if (!cmdvec)
  488. return;
  489. cnode = vector_slot (cmdvec, ntype);
  490. if (cnode == NULL)
  491. {
  492. fprintf (stderr, "Command node %d doesn't exist, please check it\n",
  493. ntype);
  494. exit (1);
  495. }
  496. vector_set (cnode->cmd_vector, cmd);
  497. if (cmd->tokens == NULL)
  498. cmd->tokens = cmd_parse_format(cmd->string, cmd->doc);
  499. }
  500. static const unsigned char itoa64[] =
  501. "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
  502. static void
  503. to64(char *s, long v, int n)
  504. {
  505. while (--n >= 0)
  506. {
  507. *s++ = itoa64[v&0x3f];
  508. v >>= 6;
  509. }
  510. }
  511. static char *
  512. zencrypt (const char *passwd)
  513. {
  514. char salt[6];
  515. struct timeval tv;
  516. char *crypt (const char *, const char *);
  517. gettimeofday(&tv,0);
  518. to64(&salt[0], random(), 3);
  519. to64(&salt[3], tv.tv_usec, 3);
  520. salt[5] = '\0';
  521. return crypt (passwd, salt);
  522. }
  523. /* This function write configuration of this host. */
  524. static int
  525. config_write_host (struct vty *vty)
  526. {
  527. if (host.name)
  528. vty_out (vty, "hostname %s%s", host.name, VTY_NEWLINE);
  529. if (host.encrypt)
  530. {
  531. if (host.password_encrypt)
  532. vty_out (vty, "password 8 %s%s", host.password_encrypt, VTY_NEWLINE);
  533. if (host.enable_encrypt)
  534. vty_out (vty, "enable password 8 %s%s", host.enable_encrypt, VTY_NEWLINE);
  535. }
  536. else
  537. {
  538. if (host.password)
  539. vty_out (vty, "password %s%s", host.password, VTY_NEWLINE);
  540. if (host.enable)
  541. vty_out (vty, "enable password %s%s", host.enable, VTY_NEWLINE);
  542. }
  543. if (zlog_default->default_lvl != LOG_DEBUG)
  544. {
  545. vty_out (vty, "! N.B. The 'log trap' command is deprecated.%s",
  546. VTY_NEWLINE);
  547. vty_out (vty, "log trap %s%s",
  548. zlog_priority[zlog_default->default_lvl], VTY_NEWLINE);
  549. }
  550. if (host.logfile && (zlog_default->maxlvl[ZLOG_DEST_FILE] != ZLOG_DISABLED))
  551. {
  552. vty_out (vty, "log file %s", host.logfile);
  553. if (zlog_default->maxlvl[ZLOG_DEST_FILE] != zlog_default->default_lvl)
  554. vty_out (vty, " %s",
  555. zlog_priority[zlog_default->maxlvl[ZLOG_DEST_FILE]]);
  556. vty_out (vty, "%s", VTY_NEWLINE);
  557. }
  558. if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] != ZLOG_DISABLED)
  559. {
  560. vty_out (vty, "log stdout");
  561. if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] != zlog_default->default_lvl)
  562. vty_out (vty, " %s",
  563. zlog_priority[zlog_default->maxlvl[ZLOG_DEST_STDOUT]]);
  564. vty_out (vty, "%s", VTY_NEWLINE);
  565. }
  566. if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
  567. vty_out(vty,"no log monitor%s",VTY_NEWLINE);
  568. else if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] != zlog_default->default_lvl)
  569. vty_out(vty,"log monitor %s%s",
  570. zlog_priority[zlog_default->maxlvl[ZLOG_DEST_MONITOR]],VTY_NEWLINE);
  571. if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != ZLOG_DISABLED)
  572. {
  573. vty_out (vty, "log syslog");
  574. if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != zlog_default->default_lvl)
  575. vty_out (vty, " %s",
  576. zlog_priority[zlog_default->maxlvl[ZLOG_DEST_SYSLOG]]);
  577. vty_out (vty, "%s", VTY_NEWLINE);
  578. }
  579. if (zlog_default->facility != LOG_DAEMON)
  580. vty_out (vty, "log facility %s%s",
  581. facility_name(zlog_default->facility), VTY_NEWLINE);
  582. if (zlog_default->record_priority == 1)
  583. vty_out (vty, "log record-priority%s", VTY_NEWLINE);
  584. if (zlog_default->timestamp_precision > 0)
  585. vty_out (vty, "log timestamp precision %d%s",
  586. zlog_default->timestamp_precision, VTY_NEWLINE);
  587. if (host.advanced)
  588. vty_out (vty, "service advanced-vty%s", VTY_NEWLINE);
  589. if (host.encrypt)
  590. vty_out (vty, "service password-encryption%s", VTY_NEWLINE);
  591. if (host.lines >= 0)
  592. vty_out (vty, "service terminal-length %d%s", host.lines,
  593. VTY_NEWLINE);
  594. if (host.motdfile)
  595. vty_out (vty, "banner motd file %s%s", host.motdfile, VTY_NEWLINE);
  596. else if (! host.motd)
  597. vty_out (vty, "no banner motd%s", VTY_NEWLINE);
  598. return 1;
  599. }
  600. /* Utility function for getting command vector. */
  601. static vector
  602. cmd_node_vector (vector v, enum node_type ntype)
  603. {
  604. struct cmd_node *cnode = vector_slot (v, ntype);
  605. return cnode->cmd_vector;
  606. }
  607. #if 0
  608. /* Filter command vector by symbol. This function is not actually used;
  609. * should it be deleted? */
  610. static int
  611. cmd_filter_by_symbol (char *command, char *symbol)
  612. {
  613. int i, lim;
  614. if (strcmp (symbol, "IPV4_ADDRESS") == 0)
  615. {
  616. i = 0;
  617. lim = strlen (command);
  618. while (i < lim)
  619. {
  620. if (! (isdigit ((int) command[i]) || command[i] == '.' || command[i] == '/'))
  621. return 1;
  622. i++;
  623. }
  624. return 0;
  625. }
  626. if (strcmp (symbol, "STRING") == 0)
  627. {
  628. i = 0;
  629. lim = strlen (command);
  630. while (i < lim)
  631. {
  632. if (! (isalpha ((int) command[i]) || command[i] == '_' || command[i] == '-'))
  633. return 1;
  634. i++;
  635. }
  636. return 0;
  637. }
  638. if (strcmp (symbol, "IFNAME") == 0)
  639. {
  640. i = 0;
  641. lim = strlen (command);
  642. while (i < lim)
  643. {
  644. if (! isalnum ((int) command[i]))
  645. return 1;
  646. i++;
  647. }
  648. return 0;
  649. }
  650. return 0;
  651. }
  652. #endif
  653. /* Completion match types. */
  654. enum match_type
  655. {
  656. no_match,
  657. extend_match,
  658. ipv4_prefix_match,
  659. ipv4_match,
  660. ipv6_prefix_match,
  661. ipv6_match,
  662. range_match,
  663. vararg_match,
  664. partly_match,
  665. exact_match
  666. };
  667. static enum match_type
  668. cmd_ipv4_match (const char *str)
  669. {
  670. const char *sp;
  671. int dots = 0, nums = 0;
  672. char buf[4];
  673. if (str == NULL)
  674. return partly_match;
  675. for (;;)
  676. {
  677. memset (buf, 0, sizeof (buf));
  678. sp = str;
  679. while (*str != '\0')
  680. {
  681. if (*str == '.')
  682. {
  683. if (dots >= 3)
  684. return no_match;
  685. if (*(str + 1) == '.')
  686. return no_match;
  687. if (*(str + 1) == '\0')
  688. return partly_match;
  689. dots++;
  690. break;
  691. }
  692. if (!isdigit ((int) *str))
  693. return no_match;
  694. str++;
  695. }
  696. if (str - sp > 3)
  697. return no_match;
  698. strncpy (buf, sp, str - sp);
  699. if (atoi (buf) > 255)
  700. return no_match;
  701. nums++;
  702. if (*str == '\0')
  703. break;
  704. str++;
  705. }
  706. if (nums < 4)
  707. return partly_match;
  708. return exact_match;
  709. }
  710. static enum match_type
  711. cmd_ipv4_prefix_match (const char *str)
  712. {
  713. const char *sp;
  714. int dots = 0;
  715. char buf[4];
  716. if (str == NULL)
  717. return partly_match;
  718. for (;;)
  719. {
  720. memset (buf, 0, sizeof (buf));
  721. sp = str;
  722. while (*str != '\0' && *str != '/')
  723. {
  724. if (*str == '.')
  725. {
  726. if (dots == 3)
  727. return no_match;
  728. if (*(str + 1) == '.' || *(str + 1) == '/')
  729. return no_match;
  730. if (*(str + 1) == '\0')
  731. return partly_match;
  732. dots++;
  733. break;
  734. }
  735. if (!isdigit ((int) *str))
  736. return no_match;
  737. str++;
  738. }
  739. if (str - sp > 3)
  740. return no_match;
  741. strncpy (buf, sp, str - sp);
  742. if (atoi (buf) > 255)
  743. return no_match;
  744. if (dots == 3)
  745. {
  746. if (*str == '/')
  747. {
  748. if (*(str + 1) == '\0')
  749. return partly_match;
  750. str++;
  751. break;
  752. }
  753. else if (*str == '\0')
  754. return partly_match;
  755. }
  756. if (*str == '\0')
  757. return partly_match;
  758. str++;
  759. }
  760. sp = str;
  761. while (*str != '\0')
  762. {
  763. if (!isdigit ((int) *str))
  764. return no_match;
  765. str++;
  766. }
  767. if (atoi (sp) > 32)
  768. return no_match;
  769. return exact_match;
  770. }
  771. #define IPV6_ADDR_STR "0123456789abcdefABCDEF:.%"
  772. #define IPV6_PREFIX_STR "0123456789abcdefABCDEF:.%/"
  773. #define STATE_START 1
  774. #define STATE_COLON 2
  775. #define STATE_DOUBLE 3
  776. #define STATE_ADDR 4
  777. #define STATE_DOT 5
  778. #define STATE_SLASH 6
  779. #define STATE_MASK 7
  780. #ifdef HAVE_IPV6
  781. static enum match_type
  782. cmd_ipv6_match (const char *str)
  783. {
  784. struct sockaddr_in6 sin6_dummy;
  785. int ret;
  786. if (str == NULL)
  787. return partly_match;
  788. if (strspn (str, IPV6_ADDR_STR) != strlen (str))
  789. return no_match;
  790. /* use inet_pton that has a better support,
  791. * for example inet_pton can support the automatic addresses:
  792. * ::1.2.3.4
  793. */
  794. ret = inet_pton(AF_INET6, str, &sin6_dummy.sin6_addr);
  795. if (ret == 1)
  796. return exact_match;
  797. return no_match;
  798. }
  799. static enum match_type
  800. cmd_ipv6_prefix_match (const char *str)
  801. {
  802. int state = STATE_START;
  803. int colons = 0, nums = 0, double_colon = 0;
  804. int mask;
  805. const char *sp = NULL;
  806. char *endptr = NULL;
  807. if (str == NULL)
  808. return partly_match;
  809. if (strspn (str, IPV6_PREFIX_STR) != strlen (str))
  810. return no_match;
  811. while (*str != '\0' && state != STATE_MASK)
  812. {
  813. switch (state)
  814. {
  815. case STATE_START:
  816. if (*str == ':')
  817. {
  818. if (*(str + 1) != ':' && *(str + 1) != '\0')
  819. return no_match;
  820. colons--;
  821. state = STATE_COLON;
  822. }
  823. else
  824. {
  825. sp = str;
  826. state = STATE_ADDR;
  827. }
  828. continue;
  829. case STATE_COLON:
  830. colons++;
  831. if (*(str + 1) == '/')
  832. return no_match;
  833. else if (*(str + 1) == ':')
  834. state = STATE_DOUBLE;
  835. else
  836. {
  837. sp = str + 1;
  838. state = STATE_ADDR;
  839. }
  840. break;
  841. case STATE_DOUBLE:
  842. if (double_colon)
  843. return no_match;
  844. if (*(str + 1) == ':')
  845. return no_match;
  846. else
  847. {
  848. if (*(str + 1) != '\0' && *(str + 1) != '/')
  849. colons++;
  850. sp = str + 1;
  851. if (*(str + 1) == '/')
  852. state = STATE_SLASH;
  853. else
  854. state = STATE_ADDR;
  855. }
  856. double_colon++;
  857. nums += 1;
  858. break;
  859. case STATE_ADDR:
  860. if (*(str + 1) == ':' || *(str + 1) == '.'
  861. || *(str + 1) == '\0' || *(str + 1) == '/')
  862. {
  863. if (str - sp > 3)
  864. return no_match;
  865. for (; sp <= str; sp++)
  866. if (*sp == '/')
  867. return no_match;
  868. nums++;
  869. if (*(str + 1) == ':')
  870. state = STATE_COLON;
  871. else if (*(str + 1) == '.')
  872. {
  873. if (colons || double_colon)
  874. state = STATE_DOT;
  875. else
  876. return no_match;
  877. }
  878. else if (*(str + 1) == '/')
  879. state = STATE_SLASH;
  880. }
  881. break;
  882. case STATE_DOT:
  883. state = STATE_ADDR;
  884. break;
  885. case STATE_SLASH:
  886. if (*(str + 1) == '\0')
  887. return partly_match;
  888. state = STATE_MASK;
  889. break;
  890. default:
  891. break;
  892. }
  893. if (nums > 11)
  894. return no_match;
  895. if (colons > 7)
  896. return no_match;
  897. str++;
  898. }
  899. if (state < STATE_MASK)
  900. return partly_match;
  901. mask = strtol (str, &endptr, 10);
  902. if (*endptr != '\0')
  903. return no_match;
  904. if (mask < 0 || mask > 128)
  905. return no_match;
  906. /* I don't know why mask < 13 makes command match partly.
  907. Forgive me to make this comments. I Want to set static default route
  908. because of lack of function to originate default in ospf6d; sorry
  909. yasu
  910. if (mask < 13)
  911. return partly_match;
  912. */
  913. return exact_match;
  914. }
  915. #endif /* HAVE_IPV6 */
  916. #define DECIMAL_STRLEN_MAX 10
  917. static int
  918. cmd_range_match (const char *range, const char *str)
  919. {
  920. char *p;
  921. char buf[DECIMAL_STRLEN_MAX + 1];
  922. char *endptr = NULL;
  923. unsigned long min, max, val;
  924. if (str == NULL)
  925. return 1;
  926. val = strtoul (str, &endptr, 10);
  927. if (*endptr != '\0')
  928. return 0;
  929. range++;
  930. p = strchr (range, '-');
  931. if (p == NULL)
  932. return 0;
  933. if (p - range > DECIMAL_STRLEN_MAX)
  934. return 0;
  935. strncpy (buf, range, p - range);
  936. buf[p - range] = '\0';
  937. min = strtoul (buf, &endptr, 10);
  938. if (*endptr != '\0')
  939. return 0;
  940. range = p + 1;
  941. p = strchr (range, '>');
  942. if (p == NULL)
  943. return 0;
  944. if (p - range > DECIMAL_STRLEN_MAX)
  945. return 0;
  946. strncpy (buf, range, p - range);
  947. buf[p - range] = '\0';
  948. max = strtoul (buf, &endptr, 10);
  949. if (*endptr != '\0')
  950. return 0;
  951. if (val < min || val > max)
  952. return 0;
  953. return 1;
  954. }
  955. static enum match_type
  956. cmd_word_match(struct cmd_token *token,
  957. enum filter_type filter,
  958. const char *word)
  959. {
  960. const char *str;
  961. enum match_type match_type;
  962. str = token->cmd;
  963. if (filter == FILTER_RELAXED)
  964. if (!word || !strlen(word))
  965. return partly_match;
  966. if (!word)
  967. return no_match;
  968. if (CMD_VARARG(str))
  969. {
  970. return vararg_match;
  971. }
  972. else if (CMD_RANGE(str))
  973. {
  974. if (cmd_range_match(str, word))
  975. return range_match;
  976. }
  977. #ifdef HAVE_IPV6
  978. else if (CMD_IPV6(str))
  979. {
  980. match_type = cmd_ipv6_match(word);
  981. if ((filter == FILTER_RELAXED && match_type != no_match)
  982. || (filter == FILTER_STRICT && match_type == exact_match))
  983. return ipv6_match;
  984. }
  985. else if (CMD_IPV6_PREFIX(str))
  986. {
  987. match_type = cmd_ipv6_prefix_match(word);
  988. if ((filter == FILTER_RELAXED && match_type != no_match)
  989. || (filter == FILTER_STRICT && match_type == exact_match))
  990. return ipv6_prefix_match;
  991. }
  992. #endif /* HAVE_IPV6 */
  993. else if (CMD_IPV4(str))
  994. {
  995. match_type = cmd_ipv4_match(word);
  996. if ((filter == FILTER_RELAXED && match_type != no_match)
  997. || (filter == FILTER_STRICT && match_type == exact_match))
  998. return ipv4_match;
  999. }
  1000. else if (CMD_IPV4_PREFIX(str))
  1001. {
  1002. match_type = cmd_ipv4_prefix_match(word);
  1003. if ((filter == FILTER_RELAXED && match_type != no_match)
  1004. || (filter == FILTER_STRICT && match_type == exact_match))
  1005. return ipv4_prefix_match;
  1006. }
  1007. else if (CMD_OPTION(str) || CMD_VARIABLE(str))
  1008. {
  1009. return extend_match;
  1010. }
  1011. else
  1012. {
  1013. if (filter == FILTER_RELAXED && !strncmp(str, word, strlen(word)))
  1014. {
  1015. if (!strcmp(str, word))
  1016. return exact_match;
  1017. return partly_match;
  1018. }
  1019. if (filter == FILTER_STRICT && !strcmp(str, word))
  1020. return exact_match;
  1021. }
  1022. return no_match;
  1023. }
  1024. struct cmd_matcher
  1025. {
  1026. struct cmd_element *cmd; /* The command element the matcher is using */
  1027. enum filter_type filter; /* Whether to use strict or relaxed matching */
  1028. vector vline; /* The tokenized commandline which is to be matched */
  1029. unsigned int index; /* The index up to which matching should be done */
  1030. /* If set, construct a list of matches at the position given by index */
  1031. enum match_type *match_type;
  1032. vector *match;
  1033. unsigned int word_index; /* iterating over vline */
  1034. };
  1035. static int
  1036. push_argument(int *argc, const char **argv, const char *arg)
  1037. {
  1038. if (!arg || !strlen(arg))
  1039. arg = NULL;
  1040. if (!argc || !argv)
  1041. return 0;
  1042. if (*argc >= CMD_ARGC_MAX)
  1043. return -1;
  1044. argv[(*argc)++] = arg;
  1045. return 0;
  1046. }
  1047. static void
  1048. cmd_matcher_record_match(struct cmd_matcher *matcher,
  1049. enum match_type match_type,
  1050. struct cmd_token *token)
  1051. {
  1052. if (matcher->word_index != matcher->index)
  1053. return;
  1054. if (matcher->match)
  1055. {
  1056. if (!*matcher->match)
  1057. *matcher->match = vector_init(VECTOR_MIN_SIZE);
  1058. vector_set(*matcher->match, token);
  1059. }
  1060. if (matcher->match_type)
  1061. {
  1062. if (match_type > *matcher->match_type)
  1063. *matcher->match_type = match_type;
  1064. }
  1065. }
  1066. static int
  1067. cmd_matcher_words_left(struct cmd_matcher *matcher)
  1068. {
  1069. return matcher->word_index < vector_active(matcher->vline);
  1070. }
  1071. static const char*
  1072. cmd_matcher_get_word(struct cmd_matcher *matcher)
  1073. {
  1074. assert(cmd_matcher_words_left(matcher));
  1075. return vector_slot(matcher->vline, matcher->word_index);
  1076. }
  1077. static enum matcher_rv
  1078. cmd_matcher_match_terminal(struct cmd_matcher *matcher,
  1079. struct cmd_token *token,
  1080. int *argc, const char **argv)
  1081. {
  1082. const char *word;
  1083. enum match_type word_match;
  1084. assert(token->type == TOKEN_TERMINAL);
  1085. if (!cmd_matcher_words_left(matcher))
  1086. {
  1087. if (CMD_OPTION(token->cmd))
  1088. return MATCHER_OK; /* missing optional args are NOT pushed as NULL */
  1089. else
  1090. return MATCHER_INCOMPLETE;
  1091. }
  1092. word = cmd_matcher_get_word(matcher);
  1093. word_match = cmd_word_match(token, matcher->filter, word);
  1094. if (word_match == no_match)
  1095. return MATCHER_NO_MATCH;
  1096. /* We have to record the input word as argument if it matched
  1097. * against a variable. */
  1098. if (CMD_VARARG(token->cmd)
  1099. || CMD_VARIABLE(token->cmd)
  1100. || CMD_OPTION(token->cmd))
  1101. {
  1102. if (push_argument(argc, argv, word))
  1103. return MATCHER_EXCEED_ARGC_MAX;
  1104. }
  1105. cmd_matcher_record_match(matcher, word_match, token);
  1106. matcher->word_index++;
  1107. /* A vararg token should consume all left over words as arguments */
  1108. if (CMD_VARARG(token->cmd))
  1109. while (cmd_matcher_words_left(matcher))
  1110. {
  1111. word = cmd_matcher_get_word(matcher);
  1112. if (word && strlen(word))
  1113. push_argument(argc, argv, word);
  1114. matcher->word_index++;
  1115. }
  1116. return MATCHER_OK;
  1117. }
  1118. static enum matcher_rv
  1119. cmd_matcher_match_multiple(struct cmd_matcher *matcher,
  1120. struct cmd_token *token,
  1121. int *argc, const char **argv)
  1122. {
  1123. enum match_type multiple_match;
  1124. unsigned int multiple_index;
  1125. const char *word;
  1126. const char *arg;
  1127. struct cmd_token *word_token;
  1128. enum match_type word_match;
  1129. assert(token->type == TOKEN_MULTIPLE);
  1130. multiple_match = no_match;
  1131. if (!cmd_matcher_words_left(matcher))
  1132. return MATCHER_INCOMPLETE;
  1133. word = cmd_matcher_get_word(matcher);
  1134. for (multiple_index = 0;
  1135. multiple_index < vector_active(token->multiple);
  1136. multiple_index++)
  1137. {
  1138. word_token = vector_slot(token->multiple, multiple_index);
  1139. word_match = cmd_word_match(word_token, matcher->filter, word);
  1140. if (word_match == no_match)
  1141. continue;
  1142. cmd_matcher_record_match(matcher, word_match, word_token);
  1143. if (word_match > multiple_match)
  1144. {
  1145. multiple_match = word_match;
  1146. arg = word;
  1147. }
  1148. /* To mimic the behavior of the old command implementation, we
  1149. * tolerate any ambiguities here :/ */
  1150. }
  1151. matcher->word_index++;
  1152. if (multiple_match == no_match)
  1153. return MATCHER_NO_MATCH;
  1154. if (push_argument(argc, argv, arg))
  1155. return MATCHER_EXCEED_ARGC_MAX;
  1156. return MATCHER_OK;
  1157. }
  1158. static enum matcher_rv
  1159. cmd_matcher_read_keywords(struct cmd_matcher *matcher,
  1160. struct cmd_token *token,
  1161. vector args_vector)
  1162. {
  1163. unsigned int i;
  1164. unsigned long keyword_mask;
  1165. unsigned int keyword_found;
  1166. enum match_type keyword_match;
  1167. enum match_type word_match;
  1168. vector keyword_vector;
  1169. struct cmd_token *word_token;
  1170. const char *word;
  1171. int keyword_argc;
  1172. const char **keyword_argv;
  1173. enum matcher_rv rv = MATCHER_NO_MATCH;
  1174. keyword_mask = 0;
  1175. while (1)
  1176. {
  1177. if (!cmd_matcher_words_left(matcher))
  1178. return MATCHER_OK;
  1179. word = cmd_matcher_get_word(matcher);
  1180. keyword_found = -1;
  1181. keyword_match = no_match;
  1182. for (i = 0; i < vector_active(token->keyword); i++)
  1183. {
  1184. if (keyword_mask & (1 << i))
  1185. continue;
  1186. keyword_vector = vector_slot(token->keyword, i);
  1187. word_token = vector_slot(keyword_vector, 0);
  1188. word_match = cmd_word_match(word_token, matcher->filter, word);
  1189. if (word_match == no_match)
  1190. continue;
  1191. cmd_matcher_record_match(matcher, word_match, word_token);
  1192. if (word_match > keyword_match)
  1193. {
  1194. keyword_match = word_match;
  1195. keyword_found = i;
  1196. }
  1197. else if (word_match == keyword_match)
  1198. {
  1199. if (matcher->word_index != matcher->index || args_vector)
  1200. return MATCHER_AMBIGUOUS;
  1201. }
  1202. }
  1203. if (keyword_found == (unsigned int)-1)
  1204. return MATCHER_NO_MATCH;
  1205. matcher->word_index++;
  1206. if (matcher->word_index > matcher->index)
  1207. return MATCHER_OK;
  1208. keyword_mask |= (1 << keyword_found);
  1209. if (args_vector)
  1210. {
  1211. keyword_argc = 0;
  1212. keyword_argv = XMALLOC(MTYPE_TMP, (CMD_ARGC_MAX + 1) * sizeof(char*));
  1213. /* We use -1 as a marker for unused fields as NULL might be a valid value */
  1214. for (i = 0; i < CMD_ARGC_MAX + 1; i++)
  1215. keyword_argv[i] = (void*)-1;
  1216. vector_set_index(args_vector, keyword_found, keyword_argv);
  1217. }
  1218. else
  1219. {
  1220. keyword_argv = NULL;
  1221. }
  1222. keyword_vector = vector_slot(token->keyword, keyword_found);
  1223. /* the keyword itself is at 0. We are only interested in the arguments,
  1224. * so start counting at 1. */
  1225. for (i = 1; i < vector_active(keyword_vector); i++)
  1226. {
  1227. word_token = vector_slot(keyword_vector, i);
  1228. switch (word_token->type)
  1229. {
  1230. case TOKEN_TERMINAL:
  1231. rv = cmd_matcher_match_terminal(matcher, word_token,
  1232. &keyword_argc, keyword_argv);
  1233. break;
  1234. case TOKEN_MULTIPLE:
  1235. rv = cmd_matcher_match_multiple(matcher, word_token,
  1236. &keyword_argc, keyword_argv);
  1237. break;
  1238. case TOKEN_KEYWORD:
  1239. assert(!"Keywords should never be nested.");
  1240. break;
  1241. }
  1242. if (MATCHER_ERROR(rv))
  1243. return rv;
  1244. if (matcher->word_index > matcher->index)
  1245. return MATCHER_OK;
  1246. }
  1247. }
  1248. /* not reached */
  1249. }
  1250. static enum matcher_rv
  1251. cmd_matcher_build_keyword_args(struct cmd_matcher *matcher,
  1252. struct cmd_token *token,
  1253. int *argc, const char **argv,
  1254. vector keyword_args_vector)
  1255. {
  1256. unsigned int i, j;
  1257. const char **keyword_args;
  1258. vector keyword_vector;
  1259. struct cmd_token *word_token;
  1260. const char *arg;
  1261. enum matcher_rv rv;
  1262. rv = MATCHER_OK;
  1263. if (keyword_args_vector == NULL)
  1264. return rv;
  1265. for (i = 0; i < vector_active(token->keyword); i++)
  1266. {
  1267. keyword_vector = vector_slot(token->keyword, i);
  1268. keyword_args = vector_lookup(keyword_args_vector, i);
  1269. if (vector_active(keyword_vector) == 1)
  1270. {
  1271. /* this is a keyword without arguments */
  1272. if (keyword_args)
  1273. {
  1274. word_token = vector_slot(keyword_vector, 0);
  1275. arg = word_token->cmd;
  1276. }
  1277. else
  1278. {
  1279. arg = NULL;
  1280. }
  1281. if (push_argument(argc, argv, arg))
  1282. rv = MATCHER_EXCEED_ARGC_MAX;
  1283. }
  1284. else
  1285. {
  1286. /* this is a keyword with arguments */
  1287. if (keyword_args)
  1288. {
  1289. /* the keyword was present, so just fill in the arguments */
  1290. for (j = 0; keyword_args[j] != (void*)-1; j++)
  1291. if (push_argument(argc, argv, keyword_args[j]))
  1292. rv = MATCHER_EXCEED_ARGC_MAX;
  1293. XFREE(MTYPE_TMP, keyword_args);
  1294. }
  1295. else
  1296. {
  1297. /* the keyword was not present, insert NULL for the arguments
  1298. * the keyword would have taken. */
  1299. for (j = 1; j < vector_active(keyword_vector); j++)
  1300. {
  1301. word_token = vector_slot(keyword_vector, j);
  1302. if ((word_token->type == TOKEN_TERMINAL
  1303. && (CMD_VARARG(word_token->cmd)
  1304. || CMD_VARIABLE(word_token->cmd)
  1305. || CMD_OPTION(word_token->cmd)))
  1306. || word_token->type == TOKEN_MULTIPLE)
  1307. {
  1308. if (push_argument(argc, argv, NULL))
  1309. rv = MATCHER_EXCEED_ARGC_MAX;
  1310. }
  1311. }
  1312. }
  1313. }
  1314. }
  1315. vector_free(keyword_args_vector);
  1316. return rv;
  1317. }
  1318. static enum matcher_rv
  1319. cmd_matcher_match_keyword(struct cmd_matcher *matcher,
  1320. struct cmd_token *token,
  1321. int *argc, const char **argv)
  1322. {
  1323. vector keyword_args_vector;
  1324. enum matcher_rv reader_rv;
  1325. enum matcher_rv builder_rv;
  1326. assert(token->type == TOKEN_KEYWORD);
  1327. if (argc && argv)
  1328. keyword_args_vector = vector_init(VECTOR_MIN_SIZE);
  1329. else
  1330. keyword_args_vector = NULL;
  1331. reader_rv = cmd_matcher_read_keywords(matcher, token, keyword_args_vector);
  1332. builder_rv = cmd_matcher_build_keyword_args(matcher, token, argc,
  1333. argv, keyword_args_vector);
  1334. /* keyword_args_vector is consumed by cmd_matcher_build_keyword_args */
  1335. if (!MATCHER_ERROR(reader_rv) && MATCHER_ERROR(builder_rv))
  1336. return builder_rv;
  1337. return reader_rv;
  1338. }
  1339. static void
  1340. cmd_matcher_init(struct cmd_matcher *matcher,
  1341. struct cmd_element *cmd,
  1342. enum filter_type filter,
  1343. vector vline,
  1344. unsigned int index,
  1345. enum match_type *match_type,
  1346. vector *match)
  1347. {
  1348. memset(matcher, 0, sizeof(*matcher));
  1349. matcher->cmd = cmd;
  1350. matcher->filter = filter;
  1351. matcher->vline = vline;
  1352. matcher->index = index;
  1353. matcher->match_type = match_type;
  1354. if (matcher->match_type)
  1355. *matcher->match_type = no_match;
  1356. matcher->match = match;
  1357. matcher->word_index = 0;
  1358. }
  1359. static enum matcher_rv
  1360. cmd_element_match(struct cmd_element *cmd_element,
  1361. enum filter_type filter,
  1362. vector vline,
  1363. unsigned int index,
  1364. enum match_type *match_type,
  1365. vector *match,
  1366. int *argc,
  1367. const char **argv)
  1368. {
  1369. struct cmd_matcher matcher;
  1370. unsigned int token_index;
  1371. enum matcher_rv rv = MATCHER_NO_MATCH;
  1372. cmd_matcher_init(&matcher, cmd_element, filter,
  1373. vline, index, match_type, match);
  1374. if (argc != NULL)
  1375. *argc = 0;
  1376. for (token_index = 0;
  1377. token_index < vector_active(cmd_element->tokens);
  1378. token_index++)
  1379. {
  1380. struct cmd_token *token = vector_slot(cmd_element->tokens, token_index);
  1381. switch (token->type)
  1382. {
  1383. case TOKEN_TERMINAL:
  1384. rv = cmd_matcher_match_terminal(&matcher, token, argc, argv);
  1385. break;
  1386. case TOKEN_MULTIPLE:
  1387. rv = cmd_matcher_match_multiple(&matcher, token, argc, argv);
  1388. break;
  1389. case TOKEN_KEYWORD:
  1390. rv = cmd_matcher_match_keyword(&matcher, token, argc, argv);
  1391. }
  1392. if (MATCHER_ERROR(rv))
  1393. return rv;
  1394. if (matcher.word_index > index)
  1395. return MATCHER_OK;
  1396. }
  1397. /* return MATCHER_COMPLETE if all words were consumed */
  1398. if (matcher.word_index >= vector_active(vline))
  1399. return MATCHER_COMPLETE;
  1400. /* return MATCHER_COMPLETE also if only an empty word is left. */
  1401. if (matcher.word_index == vector_active(vline) - 1
  1402. && (!vector_slot(vline, matcher.word_index)
  1403. || !strlen((char*)vector_slot(vline, matcher.word_index))))
  1404. return MATCHER_COMPLETE;
  1405. return MATCHER_NO_MATCH; /* command is too long to match */
  1406. }
  1407. /**
  1408. * Filter a given vector of commands against a given commandline and
  1409. * calculate possible completions.
  1410. *
  1411. * @param commands A vector of struct cmd_element*. Commands that don't
  1412. * match against the given command line will be overwritten
  1413. * with NULL in that vector.
  1414. * @param filter Either FILTER_RELAXED or FILTER_STRICT. This basically
  1415. * determines how incomplete commands are handled, compare with
  1416. * cmd_word_match for details.
  1417. * @param vline A vector of char* containing the tokenized commandline.
  1418. * @param index Only match up to the given token of the commandline.
  1419. * @param match_type Record the type of the best match here.
  1420. * @param matches Record the matches here. For each cmd_element in the commands
  1421. * vector, a match vector will be created in the matches vector.
  1422. * That vector will contain all struct command_token* of the
  1423. * cmd_element which matched against the given vline at the given
  1424. * index.
  1425. * @return A code specifying if an error occured. If all went right, it's
  1426. * CMD_SUCCESS.
  1427. */
  1428. static int
  1429. cmd_vector_filter(vector commands,
  1430. enum filter_type filter,
  1431. vector vline,
  1432. unsigned int index,
  1433. enum match_type *match_type,
  1434. vector *matches)
  1435. {
  1436. unsigned int i;
  1437. struct cmd_element *cmd_element;
  1438. enum match_type best_match;
  1439. enum match_type element_match;
  1440. enum matcher_rv matcher_rv;
  1441. best_match = no_match;
  1442. *matches = vector_init(VECTOR_MIN_SIZE);
  1443. for (i = 0; i < vector_active (commands); i++)
  1444. if ((cmd_element = vector_slot (commands, i)) != NULL)
  1445. {
  1446. vector_set_index(*matches, i, NULL);
  1447. matcher_rv = cmd_element_match(cmd_element, filter,
  1448. vline, index,
  1449. &element_match,
  1450. (vector*)&vector_slot(*matches, i),
  1451. NULL, NULL);
  1452. if (MATCHER_ERROR(matcher_rv))
  1453. {
  1454. vector_slot(commands, i) = NULL;
  1455. if (matcher_rv == MATCHER_AMBIGUOUS)
  1456. return CMD_ERR_AMBIGUOUS;
  1457. if (matcher_rv == MATCHER_EXCEED_ARGC_MAX)
  1458. return CMD_ERR_EXEED_ARGC_MAX;
  1459. }
  1460. else if (element_match > best_match)
  1461. {
  1462. best_match = element_match;
  1463. }
  1464. }
  1465. *match_type = best_match;
  1466. return CMD_SUCCESS;
  1467. }
  1468. /**
  1469. * Check whether a given commandline is complete if used for a specific
  1470. * cmd_element.
  1471. *
  1472. * @param cmd_element A cmd_element against which the commandline should be
  1473. * checked.
  1474. * @param vline The tokenized commandline.
  1475. * @return 1 if the given commandline is complete, 0 otherwise.
  1476. */
  1477. static int
  1478. cmd_is_complete(struct cmd_element *cmd_element,
  1479. vector vline)
  1480. {
  1481. enum matcher_rv rv;
  1482. rv = cmd_element_match(cmd_element,
  1483. FILTER_RELAXED,
  1484. vline, -1,
  1485. NULL, NULL,
  1486. NULL, NULL);
  1487. return (rv == MATCHER_COMPLETE);
  1488. }
  1489. /**
  1490. * Parse a given commandline and construct a list of arguments for the
  1491. * given command_element.
  1492. *
  1493. * @param cmd_element The cmd_element for which we want to construct arguments.
  1494. * @param vline The tokenized commandline.
  1495. * @param argc Where to store the argument count.
  1496. * @param argv Where to store the argument list. Should be at least
  1497. * CMD_ARGC_MAX elements long.
  1498. * @return CMD_SUCCESS if everything went alright, an error otherwise.
  1499. */
  1500. static int
  1501. cmd_parse(struct cmd_element *cmd_element,
  1502. vector vline,
  1503. int *argc, const char **argv)
  1504. {
  1505. enum matcher_rv rv = cmd_element_match(cmd_element,
  1506. FILTER_RELAXED,
  1507. vline, -1,
  1508. NULL, NULL,
  1509. argc, argv);
  1510. switch (rv)
  1511. {
  1512. case MATCHER_COMPLETE:
  1513. return CMD_SUCCESS;
  1514. case MATCHER_NO_MATCH:
  1515. return CMD_ERR_NO_MATCH;
  1516. case MATCHER_AMBIGUOUS:
  1517. return CMD_ERR_AMBIGUOUS;
  1518. case MATCHER_EXCEED_ARGC_MAX:
  1519. return CMD_ERR_EXEED_ARGC_MAX;
  1520. default:
  1521. return CMD_ERR_INCOMPLETE;
  1522. }
  1523. }
  1524. /* Check ambiguous match */
  1525. static int
  1526. is_cmd_ambiguous (vector cmd_vector,
  1527. const char *command,
  1528. vector matches,
  1529. enum match_type type)
  1530. {
  1531. unsigned int i;
  1532. unsigned int j;
  1533. const char *str = NULL;
  1534. const char *matched = NULL;
  1535. vector match_vector;
  1536. struct cmd_token *cmd_token;
  1537. if (command == NULL)
  1538. command = "";
  1539. for (i = 0; i < vector_active (matches); i++)
  1540. if ((match_vector = vector_slot (matches, i)) != NULL)
  1541. {
  1542. int match = 0;
  1543. for (j = 0; j < vector_active (match_vector); j++)
  1544. if ((cmd_token = vector_slot (match_vector, j)) != NULL)
  1545. {
  1546. enum match_type ret;
  1547. assert(cmd_token->type == TOKEN_TERMINAL);
  1548. if (cmd_token->type != TOKEN_TERMINAL)
  1549. continue;
  1550. str = cmd_token->cmd;
  1551. switch (type)
  1552. {
  1553. case exact_match:
  1554. if (!(CMD_OPTION (str) || CMD_VARIABLE (str))
  1555. && strcmp (command, str) == 0)
  1556. match++;
  1557. break;
  1558. case partly_match:
  1559. if (!(CMD_OPTION (str) || CMD_VARIABLE (str))
  1560. && strncmp (command, str, strlen (command)) == 0)
  1561. {
  1562. if (matched && strcmp (matched, str) != 0)
  1563. return 1; /* There is ambiguous match. */
  1564. else
  1565. matched = str;
  1566. match++;
  1567. }
  1568. break;
  1569. case range_match:
  1570. if (cmd_range_match (str, command))
  1571. {
  1572. if (matched && strcmp (matched, str) != 0)
  1573. return 1;
  1574. else
  1575. matched = str;
  1576. match++;
  1577. }
  1578. break;
  1579. #ifdef HAVE_IPV6
  1580. case ipv6_match:
  1581. if (CMD_IPV6 (str))
  1582. match++;
  1583. break;
  1584. case ipv6_prefix_match:
  1585. if ((ret = cmd_ipv6_prefix_match (command)) != no_match)
  1586. {
  1587. if (ret == partly_match)
  1588. return 2; /* There is incomplete match. */
  1589. match++;
  1590. }
  1591. break;
  1592. #endif /* HAVE_IPV6 */
  1593. case ipv4_match:
  1594. if (CMD_IPV4 (str))
  1595. match++;
  1596. break;
  1597. case ipv4_prefix_match:
  1598. if ((ret = cmd_ipv4_prefix_match (command)) != no_match)
  1599. {
  1600. if (ret == partly_match)
  1601. return 2; /* There is incomplete match. */
  1602. match++;
  1603. }
  1604. break;
  1605. case extend_match:
  1606. if (CMD_OPTION (str) || CMD_VARIABLE (str))
  1607. match++;
  1608. break;
  1609. case no_match:
  1610. default:
  1611. break;
  1612. }
  1613. }
  1614. if (!match)
  1615. vector_slot (cmd_vector, i) = NULL;
  1616. }
  1617. return 0;
  1618. }
  1619. /* If src matches dst return dst string, otherwise return NULL */
  1620. static const char *
  1621. cmd_entry_function (const char *src, const char *dst)
  1622. {
  1623. /* Skip variable arguments. */
  1624. if (CMD_OPTION (dst) || CMD_VARIABLE (dst) || CMD_VARARG (dst) ||
  1625. CMD_IPV4 (dst) || CMD_IPV4_PREFIX (dst) || CMD_RANGE (dst))
  1626. return NULL;
  1627. /* In case of 'command \t', given src is NULL string. */
  1628. if (src == NULL)
  1629. return dst;
  1630. /* Matched with input string. */
  1631. if (strncmp (src, dst, strlen (src)) == 0)
  1632. return dst;
  1633. return NULL;
  1634. }
  1635. /* If src matches dst return dst string, otherwise return NULL */
  1636. /* This version will return the dst string always if it is
  1637. CMD_VARIABLE for '?' key processing */
  1638. static const char *
  1639. cmd_entry_function_desc (const char *src, const char *dst)
  1640. {
  1641. if (CMD_VARARG (dst))
  1642. return dst;
  1643. if (CMD_RANGE (dst))
  1644. {
  1645. if (cmd_range_match (dst, src))
  1646. return dst;
  1647. else
  1648. return NULL;
  1649. }
  1650. #ifdef HAVE_IPV6
  1651. if (CMD_IPV6 (dst))
  1652. {
  1653. if (cmd_ipv6_match (src))
  1654. return dst;
  1655. else
  1656. return NULL;
  1657. }
  1658. if (CMD_IPV6_PREFIX (dst))
  1659. {
  1660. if (cmd_ipv6_prefix_match (src))
  1661. return dst;
  1662. else
  1663. return NULL;
  1664. }
  1665. #endif /* HAVE_IPV6 */
  1666. if (CMD_IPV4 (dst))
  1667. {
  1668. if (cmd_ipv4_match (src))
  1669. return dst;
  1670. else
  1671. return NULL;
  1672. }
  1673. if (CMD_IPV4_PREFIX (dst))
  1674. {
  1675. if (cmd_ipv4_prefix_match (src))
  1676. return dst;
  1677. else
  1678. return NULL;
  1679. }
  1680. /* Optional or variable commands always match on '?' */
  1681. if (CMD_OPTION (dst) || CMD_VARIABLE (dst))
  1682. return dst;
  1683. /* In case of 'command \t', given src is NULL string. */
  1684. if (src == NULL)
  1685. return dst;
  1686. if (strncmp (src, dst, strlen (src)) == 0)
  1687. return dst;
  1688. else
  1689. return NULL;
  1690. }
  1691. /**
  1692. * Check whether a string is already present in a vector of strings.
  1693. * @param v A vector of char*.
  1694. * @param str A char*.
  1695. * @return 0 if str is already present in the vector, 1 otherwise.
  1696. */
  1697. static int
  1698. cmd_unique_string (vector v, const char *str)
  1699. {
  1700. unsigned int i;
  1701. char *match;
  1702. for (i = 0; i < vector_active (v); i++)
  1703. if ((match = vector_slot (v, i)) != NULL)
  1704. if (strcmp (match, str) == 0)
  1705. return 0;
  1706. return 1;
  1707. }
  1708. /**
  1709. * Check whether a struct cmd_token matching a given string is already
  1710. * present in a vector of struct cmd_token.
  1711. * @param v A vector of struct cmd_token*.
  1712. * @param str A char* which should be searched for.
  1713. * @return 0 if there is a struct cmd_token* with its cmd matching str,
  1714. * 1 otherwise.
  1715. */
  1716. static int
  1717. desc_unique_string (vector v, const char *str)
  1718. {
  1719. unsigned int i;
  1720. struct cmd_token *token;
  1721. for (i = 0; i < vector_active (v); i++)
  1722. if ((token = vector_slot (v, i)) != NULL)
  1723. if (strcmp (token->cmd, str) == 0)
  1724. return 0;
  1725. return 1;
  1726. }
  1727. static int
  1728. cmd_try_do_shortcut (enum node_type node, char* first_word) {
  1729. if ( first_word != NULL &&
  1730. node != AUTH_NODE &&
  1731. node != VIEW_NODE &&
  1732. node != AUTH_ENABLE_NODE &&
  1733. node != ENABLE_NODE &&
  1734. node != RESTRICTED_NODE &&
  1735. 0 == strcmp( "do", first_word ) )
  1736. return 1;
  1737. return 0;
  1738. }
  1739. static void
  1740. cmd_matches_free(vector *matches)
  1741. {
  1742. unsigned int i;
  1743. vector cmd_matches;
  1744. for (i = 0; i < vector_active(*matches); i++)
  1745. if ((cmd_matches = vector_slot(*matches, i)) != NULL)
  1746. vector_free(cmd_matches);
  1747. vector_free(*matches);
  1748. *matches = NULL;
  1749. }
  1750. static int
  1751. cmd_describe_cmp(const void *a, const void *b)
  1752. {
  1753. const struct cmd_token *first = *(struct cmd_token * const *)a;
  1754. const struct cmd_token *second = *(struct cmd_token * const *)b;
  1755. return strcmp(first->cmd, second->cmd);
  1756. }
  1757. static void
  1758. cmd_describe_sort(vector matchvec)
  1759. {
  1760. qsort(matchvec->index, vector_active(matchvec),
  1761. sizeof(void*), cmd_describe_cmp);
  1762. }
  1763. /* '?' describe command support. */
  1764. static vector
  1765. cmd_describe_command_real (vector vline, struct vty *vty, int *status)
  1766. {
  1767. unsigned int i;
  1768. vector cmd_vector;
  1769. #define INIT_MATCHVEC_SIZE 10
  1770. vector matchvec;
  1771. struct cmd_element *cmd_element;
  1772. unsigned int index;
  1773. int ret;
  1774. enum match_type match;
  1775. char *command;
  1776. vector matches = NULL;
  1777. vector match_vector;
  1778. /* Set index. */
  1779. if (vector_active (vline) == 0)
  1780. {
  1781. *status = CMD_ERR_NO_MATCH;
  1782. return NULL;
  1783. }
  1784. index = vector_active (vline) - 1;
  1785. /* Make copy vector of current node's command vector. */
  1786. cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
  1787. /* Prepare match vector */
  1788. matchvec = vector_init (INIT_MATCHVEC_SIZE);
  1789. /* Filter commands and build a list how they could possibly continue. */
  1790. for (i = 0; i <= index; i++)
  1791. {
  1792. command = vector_slot (vline, i);
  1793. if (matches)
  1794. cmd_matches_free(&matches);
  1795. ret = cmd_vector_filter(cmd_vector,
  1796. FILTER_RELAXED,
  1797. vline, i,
  1798. &match,
  1799. &matches);
  1800. if (ret != CMD_SUCCESS)
  1801. {
  1802. vector_free (cmd_vector);
  1803. vector_free (matchvec);
  1804. cmd_matches_free(&matches);
  1805. *status = ret;
  1806. return NULL;
  1807. }
  1808. /* The last match may well be ambigious, so break here */
  1809. if (i == index)
  1810. break;
  1811. if (match == vararg_match)
  1812. {
  1813. /* We found a vararg match - so we can throw out the current matches here
  1814. * and don't need to continue checking the command input */
  1815. unsigned int j, k;
  1816. for (j = 0; j < vector_active (matches); j++)
  1817. if ((match_vector = vector_slot (matches, j)) != NULL)
  1818. for (k = 0; k < vector_active (match_vector); k++)
  1819. {
  1820. struct cmd_token *token = vector_slot (match_vector, k);
  1821. vector_set (matchvec, token);
  1822. }
  1823. *status = CMD_SUCCESS;
  1824. vector_set(matchvec, &token_cr);
  1825. vector_free (cmd_vector);
  1826. cmd_matches_free(&matches);
  1827. cmd_describe_sort(matchvec);
  1828. return matchvec;
  1829. }
  1830. ret = is_cmd_ambiguous(cmd_vector, command, matches, match);
  1831. if (ret == 1)
  1832. {
  1833. vector_free (cmd_vector);
  1834. vector_free (matchvec);
  1835. cmd_matches_free(&matches);
  1836. *status = CMD_ERR_AMBIGUOUS;
  1837. return NULL;
  1838. }
  1839. else if (ret == 2)
  1840. {
  1841. vector_free (cmd_vector);
  1842. vector_free (matchvec);
  1843. cmd_matches_free(&matches);
  1844. *status = CMD_ERR_NO_MATCH;
  1845. return NULL;
  1846. }
  1847. }
  1848. /* Make description vector. */
  1849. for (i = 0; i < vector_active (matches); i++)
  1850. if ((cmd_element = vector_slot (cmd_vector, i)) != NULL)
  1851. {
  1852. unsigned int j;
  1853. const char *last_word;
  1854. vector vline_trimmed;
  1855. last_word = vector_slot(vline, vector_active(vline) - 1);
  1856. if (last_word == NULL || !strlen(last_word))
  1857. {
  1858. vline_trimmed = vector_copy(vline);
  1859. vector_unset(vline_trimmed, vector_active(vline_trimmed) - 1);
  1860. if (cmd_is_complete(cmd_element, vline_trimmed)
  1861. && desc_unique_string(matchvec, command_cr))
  1862. {
  1863. if (match != vararg_match)
  1864. vector_set(matchvec, &token_cr);
  1865. }
  1866. vector_free(vline_trimmed);
  1867. }
  1868. match_vector = vector_slot (matches, i);
  1869. if (match_vector)
  1870. for (j = 0; j < vector_active(match_vector); j++)
  1871. {
  1872. struct cmd_token *token = vector_slot(match_vector, j);
  1873. const char *string;
  1874. string = cmd_entry_function_desc(command, token->cmd);
  1875. if (string && desc_unique_string(matchvec, string))
  1876. vector_set(matchvec, token);
  1877. }
  1878. }
  1879. vector_free (cmd_vector);
  1880. cmd_matches_free(&matches);
  1881. if (vector_slot (matchvec, 0) == NULL)
  1882. {
  1883. vector_free (matchvec);
  1884. *status = CMD_ERR_NO_MATCH;
  1885. return NULL;
  1886. }
  1887. *status = CMD_SUCCESS;
  1888. cmd_describe_sort(matchvec);
  1889. return matchvec;
  1890. }
  1891. vector
  1892. cmd_describe_command (vector vline, struct vty *vty, int *status)
  1893. {
  1894. vector ret;
  1895. if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
  1896. {
  1897. enum node_type onode;
  1898. vector shifted_vline;
  1899. unsigned int index;
  1900. onode = vty->node;
  1901. vty->node = ENABLE_NODE;
  1902. /* We can try it on enable node, cos' the vty is authenticated */
  1903. shifted_vline = vector_init (vector_count(vline));
  1904. /* use memcpy? */
  1905. for (index = 1; index < vector_active (vline); index++)
  1906. {
  1907. vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
  1908. }
  1909. ret = cmd_describe_command_real (shifted_vline, vty, status);
  1910. vector_free(shifted_vline);
  1911. vty->node = onode;
  1912. return ret;
  1913. }
  1914. return cmd_describe_command_real (vline, vty, status);
  1915. }
  1916. /* Check LCD of matched command. */
  1917. static int
  1918. cmd_lcd (char **matched)
  1919. {
  1920. int i;
  1921. int j;
  1922. int lcd = -1;
  1923. char *s1, *s2;
  1924. char c1, c2;
  1925. if (matched[0] == NULL || matched[1] == NULL)
  1926. return 0;
  1927. for (i = 1; matched[i] != NULL; i++)
  1928. {
  1929. s1 = matched[i - 1];
  1930. s2 = matched[i];
  1931. for (j = 0; (c1 = s1[j]) && (c2 = s2[j]); j++)
  1932. if (c1 != c2)
  1933. break;
  1934. if (lcd < 0)
  1935. lcd = j;
  1936. else
  1937. {
  1938. if (lcd > j)
  1939. lcd = j;
  1940. }
  1941. }
  1942. return lcd;
  1943. }
  1944. static int
  1945. cmd_complete_cmp(const void *a, const void *b)
  1946. {
  1947. const char *first = *(char * const *)a;
  1948. const char *second = *(char * const *)b;
  1949. if (!first)
  1950. {
  1951. if (!second)
  1952. return 0;
  1953. return 1;
  1954. }
  1955. if (!second)
  1956. return -1;
  1957. return strcmp(first, second);
  1958. }
  1959. static void
  1960. cmd_complete_sort(vector matchvec)
  1961. {
  1962. qsort(matchvec->index, vector_active(matchvec),
  1963. sizeof(void*), cmd_complete_cmp);
  1964. }
  1965. /* Command line completion support. */
  1966. static char **
  1967. cmd_complete_command_real (vector vline, struct vty *vty, int *status)
  1968. {
  1969. unsigned int i;
  1970. vector cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
  1971. #define INIT_MATCHVEC_SIZE 10
  1972. vector matchvec;
  1973. unsigned int index;
  1974. char **match_str;
  1975. struct cmd_token *token;
  1976. char *command;
  1977. int lcd;
  1978. vector matches = NULL;
  1979. vector match_vector;
  1980. if (vector_active (vline) == 0)
  1981. {
  1982. vector_free (cmd_vector);
  1983. *status = CMD_ERR_NO_MATCH;
  1984. return NULL;
  1985. }
  1986. else
  1987. index = vector_active (vline) - 1;
  1988. /* First, filter by command string */
  1989. for (i = 0; i <= index; i++)
  1990. {
  1991. command = vector_slot (vline, i);
  1992. enum match_type match;
  1993. int ret;
  1994. if (matches)
  1995. cmd_matches_free(&matches);
  1996. /* First try completion match, if there is exactly match return 1 */
  1997. ret = cmd_vector_filter(cmd_vector,
  1998. FILTER_RELAXED,
  1999. vline, i,
  2000. &match,
  2001. &matches);
  2002. if (ret != CMD_SUCCESS)
  2003. {
  2004. vector_free(cmd_vector);
  2005. cmd_matches_free(&matches);
  2006. *status = ret;
  2007. return NULL;
  2008. }
  2009. /* Break here - the completion mustn't be checked to be non-ambiguous */
  2010. if (i == index)
  2011. break;
  2012. /* If there is exact match then filter ambiguous match else check
  2013. ambiguousness. */
  2014. ret = is_cmd_ambiguous (cmd_vector, command, matches, match);
  2015. if (ret == 1)
  2016. {
  2017. vector_free (cmd_vector);
  2018. cmd_matches_free(&matches);
  2019. *status = CMD_ERR_AMBIGUOUS;
  2020. return NULL;
  2021. }
  2022. /*
  2023. else if (ret == 2)
  2024. {
  2025. vector_free (cmd_vector);
  2026. cmd_matches_free(&matches);
  2027. *status = CMD_ERR_NO_MATCH;
  2028. return NULL;
  2029. }
  2030. */
  2031. }
  2032. /* Prepare match vector. */
  2033. matchvec = vector_init (INIT_MATCHVEC_SIZE);
  2034. /* Build the possible list of continuations into a list of completions */
  2035. for (i = 0; i < vector_active (matches); i++)
  2036. if ((match_vector = vector_slot (matches, i)))
  2037. {
  2038. const char *string;
  2039. unsigned int j;
  2040. for (j = 0; j < vector_active (match_vector); j++)
  2041. if ((token = vector_slot (match_vector, j)))
  2042. {
  2043. if ((string =
  2044. cmd_entry_function (vector_slot (vline, index),
  2045. token->cmd)))
  2046. if (cmd_unique_string (matchvec, string))
  2047. vector_set (matchvec, XSTRDUP (MTYPE_TMP, string));
  2048. }
  2049. }
  2050. /* We don't need cmd_vector any more. */
  2051. vector_free (cmd_vector);
  2052. cmd_matches_free(&matches);
  2053. /* No matched command */
  2054. if (vector_slot (matchvec, 0) == NULL)
  2055. {
  2056. vector_free (matchvec);
  2057. /* In case of 'command \t' pattern. Do you need '?' command at
  2058. the end of the line. */
  2059. if (vector_slot (vline, index) == '\0')
  2060. *status = CMD_ERR_NOTHING_TODO;
  2061. else
  2062. *status = CMD_ERR_NO_MATCH;
  2063. return NULL;
  2064. }
  2065. /* Only one matched */
  2066. if (vector_slot (matchvec, 1) == NULL)
  2067. {
  2068. match_str = (char **) matchvec->index;
  2069. vector_only_wrapper_free (matchvec);
  2070. *status = CMD_COMPLETE_FULL_MATCH;
  2071. return match_str;
  2072. }
  2073. /* Make it sure last element is NULL. */
  2074. vector_set (matchvec, NULL);
  2075. /* Check LCD of matched strings. */
  2076. if (vector_slot (vline, index) != NULL)
  2077. {
  2078. lcd = cmd_lcd ((char **) matchvec->index);
  2079. if (lcd)
  2080. {
  2081. int len = strlen (vector_slot (vline, index));
  2082. if (len < lcd)
  2083. {
  2084. char *lcdstr;
  2085. lcdstr = XMALLOC (MTYPE_TMP, lcd + 1);
  2086. memcpy (lcdstr, matchvec->index[0], lcd);
  2087. lcdstr[lcd] = '\0';
  2088. /* match_str = (char **) &lcdstr; */
  2089. /* Free matchvec. */
  2090. for (i = 0; i < vector_active (matchvec); i++)
  2091. {
  2092. if (vector_slot (matchvec, i))
  2093. XFREE (MTYPE_TMP, vector_slot (matchvec, i));
  2094. }
  2095. vector_free (matchvec);
  2096. /* Make new matchvec. */
  2097. matchvec = vector_init (INIT_MATCHVEC_SIZE);
  2098. vector_set (matchvec, lcdstr);
  2099. match_str = (char **) matchvec->index;
  2100. vector_only_wrapper_free (matchvec);
  2101. *status = CMD_COMPLETE_MATCH;
  2102. return match_str;
  2103. }
  2104. }
  2105. }
  2106. match_str = (char **) matchvec->index;
  2107. cmd_complete_sort(matchvec);
  2108. vector_only_wrapper_free (matchvec);
  2109. *status = CMD_COMPLETE_LIST_MATCH;
  2110. return match_str;
  2111. }
  2112. char **
  2113. cmd_complete_command (vector vline, struct vty *vty, int *status)
  2114. {
  2115. char **ret;
  2116. if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
  2117. {
  2118. enum node_type onode;
  2119. vector shifted_vline;
  2120. unsigned int index;
  2121. onode = vty->node;
  2122. vty->node = ENABLE_NODE;
  2123. /* We can try it on enable node, cos' the vty is authenticated */
  2124. shifted_vline = vector_init (vector_count(vline));
  2125. /* use memcpy? */
  2126. for (index = 1; index < vector_active (vline); index++)
  2127. {
  2128. vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
  2129. }
  2130. ret = cmd_complete_command_real (shifted_vline, vty, status);
  2131. vector_free(shifted_vline);
  2132. vty->node = onode;
  2133. return ret;
  2134. }
  2135. return cmd_complete_command_real (vline, vty, status);
  2136. }
  2137. /* return parent node */
  2138. /* MUST eventually converge on CONFIG_NODE */
  2139. enum node_type
  2140. node_parent ( enum node_type node )
  2141. {
  2142. enum node_type ret;
  2143. assert (node > CONFIG_NODE);
  2144. switch (node)
  2145. {
  2146. case BGP_VPNV4_NODE:
  2147. case BGP_IPV4_NODE:
  2148. case BGP_IPV4M_NODE:
  2149. case BGP_IPV6_NODE:
  2150. case BGP_IPV6M_NODE:
  2151. ret = BGP_NODE;
  2152. break;
  2153. case KEYCHAIN_KEY_NODE:
  2154. ret = KEYCHAIN_NODE;
  2155. break;
  2156. default:
  2157. ret = CONFIG_NODE;
  2158. }
  2159. return ret;
  2160. }
  2161. /* Execute command by argument vline vector. */
  2162. static int
  2163. cmd_execute_command_real (vector vline,
  2164. enum filter_type filter,
  2165. struct vty *vty,
  2166. struct cmd_element **cmd)
  2167. {
  2168. unsigned int i;
  2169. unsigned int index;
  2170. vector cmd_vector;
  2171. struct cmd_element *cmd_element;
  2172. struct cmd_element *matched_element;
  2173. unsigned int matched_count, incomplete_count;
  2174. int argc;
  2175. const char *argv[CMD_ARGC_MAX];
  2176. enum match_type match = 0;
  2177. char *command;
  2178. int ret;
  2179. vector matches;
  2180. /* Make copy of command elements. */
  2181. cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
  2182. for (index = 0; index < vector_active (vline); index++)
  2183. {
  2184. command = vector_slot (vline, index);
  2185. ret = cmd_vector_filter(cmd_vector,
  2186. filter,
  2187. vline, index,
  2188. &match,
  2189. &matches);
  2190. if (ret != CMD_SUCCESS)
  2191. {
  2192. cmd_matches_free(&matches);
  2193. return ret;
  2194. }
  2195. if (match == vararg_match)
  2196. {
  2197. cmd_matches_free(&matches);
  2198. break;
  2199. }
  2200. ret = is_cmd_ambiguous (cmd_vector, command, matches, match);
  2201. cmd_matches_free(&matches);
  2202. if (ret == 1)
  2203. {
  2204. vector_free(cmd_vector);
  2205. return CMD_ERR_AMBIGUOUS;
  2206. }
  2207. else if (ret == 2)
  2208. {
  2209. vector_free(cmd_vector);
  2210. return CMD_ERR_NO_MATCH;
  2211. }
  2212. }
  2213. /* Check matched count. */
  2214. matched_element = NULL;
  2215. matched_count = 0;
  2216. incomplete_count = 0;
  2217. for (i = 0; i < vector_active (cmd_vector); i++)
  2218. if ((cmd_element = vector_slot (cmd_vector, i)))
  2219. {
  2220. if (cmd_is_complete(cmd_element, vline))
  2221. {
  2222. matched_element = cmd_element;
  2223. matched_count++;
  2224. }
  2225. else
  2226. {
  2227. incomplete_count++;
  2228. }
  2229. }
  2230. /* Finish of using cmd_vector. */
  2231. vector_free (cmd_vector);
  2232. /* To execute command, matched_count must be 1. */
  2233. if (matched_count == 0)
  2234. {
  2235. if (incomplete_count)
  2236. return CMD_ERR_INCOMPLETE;
  2237. else
  2238. return CMD_ERR_NO_MATCH;
  2239. }
  2240. if (matched_count > 1)
  2241. return CMD_ERR_AMBIGUOUS;
  2242. ret = cmd_parse(matched_element, vline, &argc, argv);
  2243. if (ret != CMD_SUCCESS)
  2244. return ret;
  2245. /* For vtysh execution. */
  2246. if (cmd)
  2247. *cmd = matched_element;
  2248. if (matched_element->daemon)
  2249. return CMD_SUCCESS_DAEMON;
  2250. /* Execute matched command. */
  2251. return (*matched_element->func) (matched_element, vty, argc, argv);
  2252. }
  2253. /**
  2254. * Execute a given command, handling things like "do ..." and checking
  2255. * whether the given command might apply at a parent node if doesn't
  2256. * apply for the current node.
  2257. *
  2258. * @param vline Command line input, vector of char* where each element is
  2259. * one input token.
  2260. * @param vty The vty context in which the command should be executed.
  2261. * @param cmd Pointer where the struct cmd_element of the matched command
  2262. * will be stored, if any. May be set to NULL if this info is
  2263. * not needed.
  2264. * @param vtysh If set != 0, don't lookup the command at parent nodes.
  2265. * @return The status of the command that has been executed or an error code
  2266. * as to why no command could be executed.
  2267. */
  2268. int
  2269. cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd,
  2270. int vtysh) {
  2271. int ret, saved_ret, tried = 0;
  2272. enum node_type onode, try_node;
  2273. onode = try_node = vty->node;
  2274. if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
  2275. {
  2276. vector shifted_vline;
  2277. unsigned int index;
  2278. vty->node = ENABLE_NODE;
  2279. /* We can try it on enable node, cos' the vty is authenticated */
  2280. shifted_vline = vector_init (vector_count(vline));
  2281. /* use memcpy? */
  2282. for (index = 1; index < vector_active (vline); index++)
  2283. {
  2284. vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
  2285. }
  2286. ret = cmd_execute_command_real (shifted_vline, FILTER_RELAXED, vty, cmd);
  2287. vector_free(shifted_vline);
  2288. vty->node = onode;
  2289. return ret;
  2290. }
  2291. saved_ret = ret = cmd_execute_command_real (vline, FILTER_RELAXED, vty, cmd);
  2292. if (vtysh)
  2293. return saved_ret;
  2294. /* This assumes all nodes above CONFIG_NODE are childs of CONFIG_NODE */
  2295. while ( ret != CMD_SUCCESS && ret != CMD_WARNING
  2296. && vty->node > CONFIG_NODE )
  2297. {
  2298. try_node = node_parent(try_node);
  2299. vty->node = try_node;
  2300. ret = cmd_execute_command_real (vline, FILTER_RELAXED, vty, cmd);
  2301. tried = 1;
  2302. if (ret == CMD_SUCCESS || ret == CMD_WARNING)
  2303. {
  2304. /* succesfull command, leave the node as is */
  2305. return ret;
  2306. }
  2307. }
  2308. /* no command succeeded, reset the vty to the original node and
  2309. return the error for this node */
  2310. if ( tried )
  2311. vty->node = onode;
  2312. return saved_ret;
  2313. }
  2314. /**
  2315. * Execute a given command, matching it strictly against the current node.
  2316. * This mode is used when reading config files.
  2317. *
  2318. * @param vline Command line input, vector of char* where each element is
  2319. * one input token.
  2320. * @param vty The vty context in which the command should be executed.
  2321. * @param cmd Pointer where the struct cmd_element* of the matched command
  2322. * will be stored, if any. May be set to NULL if this info is
  2323. * not needed.
  2324. * @return The status of the command that has been executed or an error code
  2325. * as to why no command could be executed.
  2326. */
  2327. int
  2328. cmd_execute_command_strict (vector vline, struct vty *vty,
  2329. struct cmd_element **cmd)
  2330. {
  2331. return cmd_execute_command_real(vline, FILTER_STRICT, vty, cmd);
  2332. }
  2333. /* Configration make from file. */
  2334. int
  2335. config_from_file (struct vty *vty, FILE *fp, unsigned int *line_num)
  2336. {
  2337. int ret;
  2338. *line_num = 0;
  2339. vector vline;
  2340. while (fgets (vty->buf, VTY_BUFSIZ, fp))
  2341. {
  2342. ++(*line_num);
  2343. vline = cmd_make_strvec (vty->buf);
  2344. /* In case of comment line */
  2345. if (vline == NULL)
  2346. continue;
  2347. /* Execute configuration command : this is strict match */
  2348. ret = cmd_execute_command_strict (vline, vty, NULL);
  2349. /* Try again with setting node to CONFIG_NODE */
  2350. while (ret != CMD_SUCCESS && ret != CMD_WARNING
  2351. && ret != CMD_ERR_NOTHING_TODO && vty->node != CONFIG_NODE)
  2352. {
  2353. vty->node = node_parent(vty->node);
  2354. ret = cmd_execute_command_strict (vline, vty, NULL);
  2355. }
  2356. cmd_free_strvec (vline);
  2357. if (ret != CMD_SUCCESS && ret != CMD_WARNING
  2358. && ret != CMD_ERR_NOTHING_TODO)
  2359. return ret;
  2360. }
  2361. return CMD_SUCCESS;
  2362. }
  2363. /* Configration from terminal */
  2364. DEFUN (config_terminal,
  2365. config_terminal_cmd,
  2366. "configure terminal",
  2367. "Configuration from vty interface\n"
  2368. "Configuration terminal\n")
  2369. {
  2370. if (vty_config_lock (vty))
  2371. vty->node = CONFIG_NODE;
  2372. else
  2373. {
  2374. vty_out (vty, "VTY configuration is locked by other VTY%s", VTY_NEWLINE);
  2375. return CMD_WARNING;
  2376. }
  2377. return CMD_SUCCESS;
  2378. }
  2379. /* Enable command */
  2380. DEFUN (enable,
  2381. config_enable_cmd,
  2382. "enable",
  2383. "Turn on privileged mode command\n")
  2384. {
  2385. /* If enable password is NULL, change to ENABLE_NODE */
  2386. if ((host.enable == NULL && host.enable_encrypt == NULL) ||
  2387. vty->type == VTY_SHELL_SERV)
  2388. vty->node = ENABLE_NODE;
  2389. else
  2390. vty->node = AUTH_ENABLE_NODE;
  2391. return CMD_SUCCESS;
  2392. }
  2393. /* Disable command */
  2394. DEFUN (disable,
  2395. config_disable_cmd,
  2396. "disable",
  2397. "Turn off privileged mode command\n")
  2398. {
  2399. if (vty->node == ENABLE_NODE)
  2400. vty->node = VIEW_NODE;
  2401. return CMD_SUCCESS;
  2402. }
  2403. /* Down vty node level. */
  2404. DEFUN (config_exit,
  2405. config_exit_cmd,
  2406. "exit",
  2407. "Exit current mode and down to previous mode\n")
  2408. {
  2409. switch (vty->node)
  2410. {
  2411. case VIEW_NODE:
  2412. case ENABLE_NODE:
  2413. case RESTRICTED_NODE:
  2414. if (vty_shell (vty))
  2415. exit (0);
  2416. else
  2417. vty->status = VTY_CLOSE;
  2418. break;
  2419. case CONFIG_NODE:
  2420. vty->node = ENABLE_NODE;
  2421. vty_config_unlock (vty);
  2422. break;
  2423. case INTERFACE_NODE:
  2424. case ZEBRA_NODE:
  2425. case BGP_NODE:
  2426. case RIP_NODE:
  2427. case RIPNG_NODE:
  2428. case BABEL_NODE:
  2429. case OSPF_NODE:
  2430. case OSPF6_NODE:
  2431. case ISIS_NODE:
  2432. case KEYCHAIN_NODE:
  2433. case MASC_NODE:
  2434. case RMAP_NODE:
  2435. case VTY_NODE:
  2436. vty->node = CONFIG_NODE;
  2437. break;
  2438. case BGP_VPNV4_NODE:
  2439. case BGP_IPV4_NODE:
  2440. case BGP_IPV4M_NODE:
  2441. case BGP_IPV6_NODE:
  2442. case BGP_IPV6M_NODE:
  2443. vty->node = BGP_NODE;
  2444. break;
  2445. case KEYCHAIN_KEY_NODE:
  2446. vty->node = KEYCHAIN_NODE;
  2447. break;
  2448. default:
  2449. break;
  2450. }
  2451. return CMD_SUCCESS;
  2452. }
  2453. /* quit is alias of exit. */
  2454. ALIAS (config_exit,
  2455. config_quit_cmd,
  2456. "quit",
  2457. "Exit current mode and down to previous mode\n")
  2458. /* End of configuration. */
  2459. DEFUN (config_end,
  2460. config_end_cmd,
  2461. "end",
  2462. "End current mode and change to enable mode.")
  2463. {
  2464. switch (vty->node)
  2465. {
  2466. case VIEW_NODE:
  2467. case ENABLE_NODE:
  2468. case RESTRICTED_NODE:
  2469. /* Nothing to do. */
  2470. break;
  2471. case CONFIG_NODE:
  2472. case INTERFACE_NODE:
  2473. case ZEBRA_NODE:
  2474. case RIP_NODE:
  2475. case RIPNG_NODE:
  2476. case BABEL_NODE:
  2477. case BGP_NODE:
  2478. case BGP_VPNV4_NODE:
  2479. case BGP_IPV4_NODE:
  2480. case BGP_IPV4M_NODE:
  2481. case BGP_IPV6_NODE:
  2482. case BGP_IPV6M_NODE:
  2483. case RMAP_NODE:
  2484. case OSPF_NODE:
  2485. case OSPF6_NODE:
  2486. case ISIS_NODE:
  2487. case KEYCHAIN_NODE:
  2488. case KEYCHAIN_KEY_NODE:
  2489. case MASC_NODE:
  2490. case VTY_NODE:
  2491. vty_config_unlock (vty);
  2492. vty->node = ENABLE_NODE;
  2493. break;
  2494. default:
  2495. break;
  2496. }
  2497. return CMD_SUCCESS;
  2498. }
  2499. /* Show version. */
  2500. DEFUN (show_version,
  2501. show_version_cmd,
  2502. "show version",
  2503. SHOW_STR
  2504. "Displays zebra version\n")
  2505. {
  2506. vty_out (vty, "Quagga %s (%s).%s", QUAGGA_VERSION, host.name?host.name:"",
  2507. VTY_NEWLINE);
  2508. vty_out (vty, "%s%s%s", QUAGGA_COPYRIGHT, GIT_INFO, VTY_NEWLINE);
  2509. return CMD_SUCCESS;
  2510. }
  2511. /* Help display function for all node. */
  2512. DEFUN (config_help,
  2513. config_help_cmd,
  2514. "help",
  2515. "Description of the interactive help system\n")
  2516. {
  2517. vty_out (vty,
  2518. "Quagga VTY provides advanced help feature. When you need help,%s\
  2519. anytime at the command line please press '?'.%s\
  2520. %s\
  2521. If nothing matches, the help list will be empty and you must backup%s\
  2522. until entering a '?' shows the available options.%s\
  2523. Two styles of help are provided:%s\
  2524. 1. Full help is available when you are ready to enter a%s\
  2525. command argument (e.g. 'show ?') and describes each possible%s\
  2526. argument.%s\
  2527. 2. Partial help is provided when an abbreviated argument is entered%s\
  2528. and you want to know what arguments match the input%s\
  2529. (e.g. 'show me?'.)%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
  2530. VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
  2531. VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
  2532. return CMD_SUCCESS;
  2533. }
  2534. /* Help display function for all node. */
  2535. DEFUN (config_list,
  2536. config_list_cmd,
  2537. "list",
  2538. "Print command list\n")
  2539. {
  2540. unsigned int i;
  2541. struct cmd_node *cnode = vector_slot (cmdvec, vty->node);
  2542. struct cmd_element *cmd;
  2543. for (i = 0; i < vector_active (cnode->cmd_vector); i++)
  2544. if ((cmd = vector_slot (cnode->cmd_vector, i)) != NULL
  2545. && !(cmd->attr == CMD_ATTR_DEPRECATED
  2546. || cmd->attr == CMD_ATTR_HIDDEN))
  2547. vty_out (vty, " %s%s", cmd->string,
  2548. VTY_NEWLINE);
  2549. return CMD_SUCCESS;
  2550. }
  2551. /* Write current configuration into file. */
  2552. DEFUN (config_write_file,
  2553. config_write_file_cmd,
  2554. "write file",
  2555. "Write running configuration to memory, network, or terminal\n"
  2556. "Write to configuration file\n")
  2557. {
  2558. unsigned int i;
  2559. int fd;
  2560. struct cmd_node *node;
  2561. char *config_file;
  2562. char *config_file_tmp = NULL;
  2563. char *config_file_sav = NULL;
  2564. int ret = CMD_WARNING;
  2565. struct vty *file_vty;
  2566. /* Check and see if we are operating under vtysh configuration */
  2567. if (host.config == NULL)
  2568. {
  2569. vty_out (vty, "Can't save to configuration file, using vtysh.%s",
  2570. VTY_NEWLINE);
  2571. return CMD_WARNING;
  2572. }
  2573. /* Get filename. */
  2574. config_file = host.config;
  2575. config_file_sav =
  2576. XMALLOC (MTYPE_TMP, strlen (config_file) + strlen (CONF_BACKUP_EXT) + 1);
  2577. strcpy (config_file_sav, config_file);
  2578. strcat (config_file_sav, CONF_BACKUP_EXT);
  2579. config_file_tmp = XMALLOC (MTYPE_TMP, strlen (config_file) + 8);
  2580. sprintf (config_file_tmp, "%s.XXXXXX", config_file);
  2581. /* Open file to configuration write. */
  2582. fd = mkstemp (config_file_tmp);
  2583. if (fd < 0)
  2584. {
  2585. vty_out (vty, "Can't open configuration file %s.%s", config_file_tmp,
  2586. VTY_NEWLINE);
  2587. goto finished;
  2588. }
  2589. /* Make vty for configuration file. */
  2590. file_vty = vty_new ();
  2591. file_vty->fd = fd;
  2592. file_vty->type = VTY_FILE;
  2593. /* Config file header print. */
  2594. vty_out (file_vty, "!\n! Zebra configuration saved from vty\n! ");
  2595. vty_time_print (file_vty, 1);
  2596. vty_out (file_vty, "!\n");
  2597. for (i = 0; i < vector_active (cmdvec); i++)
  2598. if ((node = vector_slot (cmdvec, i)) && node->func)
  2599. {
  2600. if ((*node->func) (file_vty))
  2601. vty_out (file_vty, "!\n");
  2602. }
  2603. vty_close (file_vty);
  2604. if (unlink (config_file_sav) != 0)
  2605. if (errno != ENOENT)
  2606. {
  2607. vty_out (vty, "Can't unlink backup configuration file %s.%s", config_file_sav,
  2608. VTY_NEWLINE);
  2609. goto finished;
  2610. }
  2611. if (link (config_file, config_file_sav) != 0)
  2612. {
  2613. vty_out (vty, "Can't backup old configuration file %s.%s", config_file_sav,
  2614. VTY_NEWLINE);
  2615. goto finished;
  2616. }
  2617. sync ();
  2618. if (unlink (config_file) != 0)
  2619. {
  2620. vty_out (vty, "Can't unlink configuration file %s.%s", config_file,
  2621. VTY_NEWLINE);
  2622. goto finished;
  2623. }
  2624. if (link (config_file_tmp, config_file) != 0)
  2625. {
  2626. vty_out (vty, "Can't save configuration file %s.%s", config_file,
  2627. VTY_NEWLINE);
  2628. goto finished;
  2629. }
  2630. sync ();
  2631. if (chmod (config_file, CONFIGFILE_MASK) != 0)
  2632. {
  2633. vty_out (vty, "Can't chmod configuration file %s: %s (%d).%s",
  2634. config_file, safe_strerror(errno), errno, VTY_NEWLINE);
  2635. goto finished;
  2636. }
  2637. vty_out (vty, "Configuration saved to %s%s", config_file,
  2638. VTY_NEWLINE);
  2639. ret = CMD_SUCCESS;
  2640. finished:
  2641. unlink (config_file_tmp);
  2642. XFREE (MTYPE_TMP, config_file_tmp);
  2643. XFREE (MTYPE_TMP, config_file_sav);
  2644. return ret;
  2645. }
  2646. ALIAS (config_write_file,
  2647. config_write_cmd,
  2648. "write",
  2649. "Write running configuration to memory, network, or terminal\n")
  2650. ALIAS (config_write_file,
  2651. config_write_memory_cmd,
  2652. "write memory",
  2653. "Write running configuration to memory, network, or terminal\n"
  2654. "Write configuration to the file (same as write file)\n")
  2655. ALIAS (config_write_file,
  2656. copy_runningconfig_startupconfig_cmd,
  2657. "copy running-config startup-config",
  2658. "Copy configuration\n"
  2659. "Copy running config to... \n"
  2660. "Copy running config to startup config (same as write file)\n")
  2661. /* Write current configuration into the terminal. */
  2662. DEFUN (config_write_terminal,
  2663. config_write_terminal_cmd,
  2664. "write terminal",
  2665. "Write running configuration to memory, network, or terminal\n"
  2666. "Write to terminal\n")
  2667. {
  2668. unsigned int i;
  2669. struct cmd_node *node;
  2670. if (vty->type == VTY_SHELL_SERV)
  2671. {
  2672. for (i = 0; i < vector_active (cmdvec); i++)
  2673. if ((node = vector_slot (cmdvec, i)) && node->func && node->vtysh)
  2674. {
  2675. if ((*node->func) (vty))
  2676. vty_out (vty, "!%s", VTY_NEWLINE);
  2677. }
  2678. }
  2679. else
  2680. {
  2681. vty_out (vty, "%sCurrent configuration:%s", VTY_NEWLINE,
  2682. VTY_NEWLINE);
  2683. vty_out (vty, "!%s", VTY_NEWLINE);
  2684. for (i = 0; i < vector_active (cmdvec); i++)
  2685. if ((node = vector_slot (cmdvec, i)) && node->func)
  2686. {
  2687. if ((*node->func) (vty))
  2688. vty_out (vty, "!%s", VTY_NEWLINE);
  2689. }
  2690. vty_out (vty, "end%s",VTY_NEWLINE);
  2691. }
  2692. return CMD_SUCCESS;
  2693. }
  2694. /* Write current configuration into the terminal. */
  2695. ALIAS (config_write_terminal,
  2696. show_running_config_cmd,
  2697. "show running-config",
  2698. SHOW_STR
  2699. "running configuration\n")
  2700. /* Write startup configuration into the terminal. */
  2701. DEFUN (show_startup_config,
  2702. show_startup_config_cmd,
  2703. "show startup-config",
  2704. SHOW_STR
  2705. "Contentes of startup configuration\n")
  2706. {
  2707. char buf[BUFSIZ];
  2708. FILE *confp;
  2709. confp = fopen (host.config, "r");
  2710. if (confp == NULL)
  2711. {
  2712. vty_out (vty, "Can't open configuration file [%s]%s",
  2713. host.config, VTY_NEWLINE);
  2714. return CMD_WARNING;
  2715. }
  2716. while (fgets (buf, BUFSIZ, confp))
  2717. {
  2718. char *cp = buf;
  2719. while (*cp != '\r' && *cp != '\n' && *cp != '\0')
  2720. cp++;
  2721. *cp = '\0';
  2722. vty_out (vty, "%s%s", buf, VTY_NEWLINE);
  2723. }
  2724. fclose (confp);
  2725. return CMD_SUCCESS;
  2726. }
  2727. /* Hostname configuration */
  2728. DEFUN (config_hostname,
  2729. hostname_cmd,
  2730. "hostname WORD",
  2731. "Set system's network name\n"
  2732. "This system's network name\n")
  2733. {
  2734. if (!isalpha((int) *argv[0]))
  2735. {
  2736. vty_out (vty, "Please specify string starting with alphabet%s", VTY_NEWLINE);
  2737. return CMD_WARNING;
  2738. }
  2739. if (host.name)
  2740. XFREE (MTYPE_HOST, host.name);
  2741. host.name = XSTRDUP (MTYPE_HOST, argv[0]);
  2742. return CMD_SUCCESS;
  2743. }
  2744. DEFUN (config_no_hostname,
  2745. no_hostname_cmd,
  2746. "no hostname [HOSTNAME]",
  2747. NO_STR
  2748. "Reset system's network name\n"
  2749. "Host name of this router\n")
  2750. {
  2751. if (host.name)
  2752. XFREE (MTYPE_HOST, host.name);
  2753. host.name = NULL;
  2754. return CMD_SUCCESS;
  2755. }
  2756. /* VTY interface password set. */
  2757. DEFUN (config_password, password_cmd,
  2758. "password (8|) WORD",
  2759. "Assign the terminal connection password\n"
  2760. "Specifies a HIDDEN password will follow\n"
  2761. "dummy string \n"
  2762. "The HIDDEN line password string\n")
  2763. {
  2764. /* Argument check. */
  2765. if (argc == 0)
  2766. {
  2767. vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
  2768. return CMD_WARNING;
  2769. }
  2770. if (argc == 2)
  2771. {
  2772. if (*argv[0] == '8')
  2773. {
  2774. if (host.password)
  2775. XFREE (MTYPE_HOST, host.password);
  2776. host.password = NULL;
  2777. if (host.password_encrypt)
  2778. XFREE (MTYPE_HOST, host.password_encrypt);
  2779. host.password_encrypt = XSTRDUP (MTYPE_HOST, argv[1]);
  2780. return CMD_SUCCESS;
  2781. }
  2782. else
  2783. {
  2784. vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
  2785. return CMD_WARNING;
  2786. }
  2787. }
  2788. if (!isalnum ((int) *argv[0]))
  2789. {
  2790. vty_out (vty,
  2791. "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
  2792. return CMD_WARNING;
  2793. }
  2794. if (host.password)
  2795. XFREE (MTYPE_HOST, host.password);
  2796. host.password = NULL;
  2797. if (host.encrypt)
  2798. {
  2799. if (host.password_encrypt)
  2800. XFREE (MTYPE_HOST, host.password_encrypt);
  2801. host.password_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (argv[0]));
  2802. }
  2803. else
  2804. host.password = XSTRDUP (MTYPE_HOST, argv[0]);
  2805. return CMD_SUCCESS;
  2806. }
  2807. ALIAS (config_password, password_text_cmd,
  2808. "password LINE",
  2809. "Assign the terminal connection password\n"
  2810. "The UNENCRYPTED (cleartext) line password\n")
  2811. /* VTY enable password set. */
  2812. DEFUN (config_enable_password, enable_password_cmd,
  2813. "enable password (8|) WORD",
  2814. "Modify enable password parameters\n"
  2815. "Assign the privileged level password\n"
  2816. "Specifies a HIDDEN password will follow\n"
  2817. "dummy string \n"
  2818. "The HIDDEN 'enable' password string\n")
  2819. {
  2820. /* Argument check. */
  2821. if (argc == 0)
  2822. {
  2823. vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
  2824. return CMD_WARNING;
  2825. }
  2826. /* Crypt type is specified. */
  2827. if (argc == 2)
  2828. {
  2829. if (*argv[0] == '8')
  2830. {
  2831. if (host.enable)
  2832. XFREE (MTYPE_HOST, host.enable);
  2833. host.enable = NULL;
  2834. if (host.enable_encrypt)
  2835. XFREE (MTYPE_HOST, host.enable_encrypt);
  2836. host.enable_encrypt = XSTRDUP (MTYPE_HOST, argv[1]);
  2837. return CMD_SUCCESS;
  2838. }
  2839. else
  2840. {
  2841. vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
  2842. return CMD_WARNING;
  2843. }
  2844. }
  2845. if (!isalnum ((int) *argv[0]))
  2846. {
  2847. vty_out (vty,
  2848. "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
  2849. return CMD_WARNING;
  2850. }
  2851. if (host.enable)
  2852. XFREE (MTYPE_HOST, host.enable);
  2853. host.enable = NULL;
  2854. /* Plain password input. */
  2855. if (host.encrypt)
  2856. {
  2857. if (host.enable_encrypt)
  2858. XFREE (MTYPE_HOST, host.enable_encrypt);
  2859. host.enable_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (argv[0]));
  2860. }
  2861. else
  2862. host.enable = XSTRDUP (MTYPE_HOST, argv[0]);
  2863. return CMD_SUCCESS;
  2864. }
  2865. ALIAS (config_enable_password,
  2866. enable_password_text_cmd,
  2867. "enable password LINE",
  2868. "Modify enable password parameters\n"
  2869. "Assign the privileged level password\n"
  2870. "The UNENCRYPTED (cleartext) 'enable' password\n")
  2871. /* VTY enable password delete. */
  2872. DEFUN (no_config_enable_password, no_enable_password_cmd,
  2873. "no enable password",
  2874. NO_STR
  2875. "Modify enable password parameters\n"
  2876. "Assign the privileged level password\n")
  2877. {
  2878. if (host.enable)
  2879. XFREE (MTYPE_HOST, host.enable);
  2880. host.enable = NULL;
  2881. if (host.enable_encrypt)
  2882. XFREE (MTYPE_HOST, host.enable_encrypt);
  2883. host.enable_encrypt = NULL;
  2884. return CMD_SUCCESS;
  2885. }
  2886. DEFUN (service_password_encrypt,
  2887. service_password_encrypt_cmd,
  2888. "service password-encryption",
  2889. "Set up miscellaneous service\n"
  2890. "Enable encrypted passwords\n")
  2891. {
  2892. if (host.encrypt)
  2893. return CMD_SUCCESS;
  2894. host.encrypt = 1;
  2895. if (host.password)
  2896. {
  2897. if (host.password_encrypt)
  2898. XFREE (MTYPE_HOST, host.password_encrypt);
  2899. host.password_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (host.password));
  2900. }
  2901. if (host.enable)
  2902. {
  2903. if (host.enable_encrypt)
  2904. XFREE (MTYPE_HOST, host.enable_encrypt);
  2905. host.enable_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (host.enable));
  2906. }
  2907. return CMD_SUCCESS;
  2908. }
  2909. DEFUN (no_service_password_encrypt,
  2910. no_service_password_encrypt_cmd,
  2911. "no service password-encryption",
  2912. NO_STR
  2913. "Set up miscellaneous service\n"
  2914. "Enable encrypted passwords\n")
  2915. {
  2916. if (! host.encrypt)
  2917. return CMD_SUCCESS;
  2918. host.encrypt = 0;
  2919. if (host.password_encrypt)
  2920. XFREE (MTYPE_HOST, host.password_encrypt);
  2921. host.password_encrypt = NULL;
  2922. if (host.enable_encrypt)
  2923. XFREE (MTYPE_HOST, host.enable_encrypt);
  2924. host.enable_encrypt = NULL;
  2925. return CMD_SUCCESS;
  2926. }
  2927. DEFUN (config_terminal_length, config_terminal_length_cmd,
  2928. "terminal length <0-512>",
  2929. "Set terminal line parameters\n"
  2930. "Set number of lines on a screen\n"
  2931. "Number of lines on screen (0 for no pausing)\n")
  2932. {
  2933. int lines;
  2934. char *endptr = NULL;
  2935. lines = strtol (argv[0], &endptr, 10);
  2936. if (lines < 0 || lines > 512 || *endptr != '\0')
  2937. {
  2938. vty_out (vty, "length is malformed%s", VTY_NEWLINE);
  2939. return CMD_WARNING;
  2940. }
  2941. vty->lines = lines;
  2942. return CMD_SUCCESS;
  2943. }
  2944. DEFUN (config_terminal_no_length, config_terminal_no_length_cmd,
  2945. "terminal no length",
  2946. "Set terminal line parameters\n"
  2947. NO_STR
  2948. "Set number of lines on a screen\n")
  2949. {
  2950. vty->lines = -1;
  2951. return CMD_SUCCESS;
  2952. }
  2953. DEFUN (service_terminal_length, service_terminal_length_cmd,
  2954. "service terminal-length <0-512>",
  2955. "Set up miscellaneous service\n"
  2956. "System wide terminal length configuration\n"
  2957. "Number of lines of VTY (0 means no line control)\n")
  2958. {
  2959. int lines;
  2960. char *endptr = NULL;
  2961. lines = strtol (argv[0], &endptr, 10);
  2962. if (lines < 0 || lines > 512 || *endptr != '\0')
  2963. {
  2964. vty_out (vty, "length is malformed%s", VTY_NEWLINE);
  2965. return CMD_WARNING;
  2966. }
  2967. host.lines = lines;
  2968. return CMD_SUCCESS;
  2969. }
  2970. DEFUN (no_service_terminal_length, no_service_terminal_length_cmd,
  2971. "no service terminal-length [<0-512>]",
  2972. NO_STR
  2973. "Set up miscellaneous service\n"
  2974. "System wide terminal length configuration\n"
  2975. "Number of lines of VTY (0 means no line control)\n")
  2976. {
  2977. host.lines = -1;
  2978. return CMD_SUCCESS;
  2979. }
  2980. DEFUN_HIDDEN (do_echo,
  2981. echo_cmd,
  2982. "echo .MESSAGE",
  2983. "Echo a message back to the vty\n"
  2984. "The message to echo\n")
  2985. {
  2986. char *message;
  2987. vty_out (vty, "%s%s", ((message = argv_concat(argv, argc, 0)) ? message : ""),
  2988. VTY_NEWLINE);
  2989. if (message)
  2990. XFREE(MTYPE_TMP, message);
  2991. return CMD_SUCCESS;
  2992. }
  2993. DEFUN (config_logmsg,
  2994. config_logmsg_cmd,
  2995. "logmsg "LOG_LEVELS" .MESSAGE",
  2996. "Send a message to enabled logging destinations\n"
  2997. LOG_LEVEL_DESC
  2998. "The message to send\n")
  2999. {
  3000. int level;
  3001. char *message;
  3002. if ((level = level_match(argv[0])) == ZLOG_DISABLED)
  3003. return CMD_ERR_NO_MATCH;
  3004. zlog(NULL, level, "%s", ((message = argv_concat(argv, argc, 1)) ? message : ""));
  3005. if (message)
  3006. XFREE(MTYPE_TMP, message);
  3007. return CMD_SUCCESS;
  3008. }
  3009. DEFUN (show_logging,
  3010. show_logging_cmd,
  3011. "show logging",
  3012. SHOW_STR
  3013. "Show current logging configuration\n")
  3014. {
  3015. struct zlog *zl = zlog_default;
  3016. vty_out (vty, "Syslog logging: ");
  3017. if (zl->maxlvl[ZLOG_DEST_SYSLOG] == ZLOG_DISABLED)
  3018. vty_out (vty, "disabled");
  3019. else
  3020. vty_out (vty, "level %s, facility %s, ident %s",
  3021. zlog_priority[zl->maxlvl[ZLOG_DEST_SYSLOG]],
  3022. facility_name(zl->facility), zl->ident);
  3023. vty_out (vty, "%s", VTY_NEWLINE);
  3024. vty_out (vty, "Stdout logging: ");
  3025. if (zl->maxlvl[ZLOG_DEST_STDOUT] == ZLOG_DISABLED)
  3026. vty_out (vty, "disabled");
  3027. else
  3028. vty_out (vty, "level %s",
  3029. zlog_priority[zl->maxlvl[ZLOG_DEST_STDOUT]]);
  3030. vty_out (vty, "%s", VTY_NEWLINE);
  3031. vty_out (vty, "Monitor logging: ");
  3032. if (zl->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
  3033. vty_out (vty, "disabled");
  3034. else
  3035. vty_out (vty, "level %s",
  3036. zlog_priority[zl->maxlvl[ZLOG_DEST_MONITOR]]);
  3037. vty_out (vty, "%s", VTY_NEWLINE);
  3038. vty_out (vty, "File logging: ");
  3039. if ((zl->maxlvl[ZLOG_DEST_FILE] == ZLOG_DISABLED) ||
  3040. !zl->fp)
  3041. vty_out (vty, "disabled");
  3042. else
  3043. vty_out (vty, "level %s, filename %s",
  3044. zlog_priority[zl->maxlvl[ZLOG_DEST_FILE]],
  3045. zl->filename);
  3046. vty_out (vty, "%s", VTY_NEWLINE);
  3047. vty_out (vty, "Protocol name: %s%s",
  3048. zlog_proto_names[zl->protocol], VTY_NEWLINE);
  3049. vty_out (vty, "Record priority: %s%s",
  3050. (zl->record_priority ? "enabled" : "disabled"), VTY_NEWLINE);
  3051. vty_out (vty, "Timestamp precision: %d%s",
  3052. zl->timestamp_precision, VTY_NEWLINE);
  3053. return CMD_SUCCESS;
  3054. }
  3055. DEFUN (config_log_stdout,
  3056. config_log_stdout_cmd,
  3057. "log stdout",
  3058. "Logging control\n"
  3059. "Set stdout logging level\n")
  3060. {
  3061. zlog_set_level (NULL, ZLOG_DEST_STDOUT, zlog_default->default_lvl);
  3062. return CMD_SUCCESS;
  3063. }
  3064. DEFUN (config_log_stdout_level,
  3065. config_log_stdout_level_cmd,
  3066. "log stdout "LOG_LEVELS,
  3067. "Logging control\n"
  3068. "Set stdout logging level\n"
  3069. LOG_LEVEL_DESC)
  3070. {
  3071. int level;
  3072. if ((level = level_match(argv[0])) == ZLOG_DISABLED)
  3073. return CMD_ERR_NO_MATCH;
  3074. zlog_set_level (NULL, ZLOG_DEST_STDOUT, level);
  3075. return CMD_SUCCESS;
  3076. }
  3077. DEFUN (no_config_log_stdout,
  3078. no_config_log_stdout_cmd,
  3079. "no log stdout [LEVEL]",
  3080. NO_STR
  3081. "Logging control\n"
  3082. "Cancel logging to stdout\n"
  3083. "Logging level\n")
  3084. {
  3085. zlog_set_level (NULL, ZLOG_DEST_STDOUT, ZLOG_DISABLED);
  3086. return CMD_SUCCESS;
  3087. }
  3088. DEFUN (config_log_monitor,
  3089. config_log_monitor_cmd,
  3090. "log monitor",
  3091. "Logging control\n"
  3092. "Set terminal line (monitor) logging level\n")
  3093. {
  3094. zlog_set_level (NULL, ZLOG_DEST_MONITOR, zlog_default->default_lvl);
  3095. return CMD_SUCCESS;
  3096. }
  3097. DEFUN (config_log_monitor_level,
  3098. config_log_monitor_level_cmd,
  3099. "log monitor "LOG_LEVELS,
  3100. "Logging control\n"
  3101. "Set terminal line (monitor) logging level\n"
  3102. LOG_LEVEL_DESC)
  3103. {
  3104. int level;
  3105. if ((level = level_match(argv[0])) == ZLOG_DISABLED)
  3106. return CMD_ERR_NO_MATCH;
  3107. zlog_set_level (NULL, ZLOG_DEST_MONITOR, level);
  3108. return CMD_SUCCESS;
  3109. }
  3110. DEFUN (no_config_log_monitor,
  3111. no_config_log_monitor_cmd,
  3112. "no log monitor [LEVEL]",
  3113. NO_STR
  3114. "Logging control\n"
  3115. "Disable terminal line (monitor) logging\n"
  3116. "Logging level\n")
  3117. {
  3118. zlog_set_level (NULL, ZLOG_DEST_MONITOR, ZLOG_DISABLED);
  3119. return CMD_SUCCESS;
  3120. }
  3121. static int
  3122. set_log_file(struct vty *vty, const char *fname, int loglevel)
  3123. {
  3124. int ret;
  3125. char *p = NULL;
  3126. const char *fullpath;
  3127. /* Path detection. */
  3128. if (! IS_DIRECTORY_SEP (*fname))
  3129. {
  3130. char cwd[MAXPATHLEN+1];
  3131. cwd[MAXPATHLEN] = '\0';
  3132. if (getcwd (cwd, MAXPATHLEN) == NULL)
  3133. {
  3134. zlog_err ("config_log_file: Unable to alloc mem!");
  3135. return CMD_WARNING;
  3136. }
  3137. if ( (p = XMALLOC (MTYPE_TMP, strlen (cwd) + strlen (fname) + 2))
  3138. == NULL)
  3139. {
  3140. zlog_err ("config_log_file: Unable to alloc mem!");
  3141. return CMD_WARNING;
  3142. }
  3143. sprintf (p, "%s/%s", cwd, fname);
  3144. fullpath = p;
  3145. }
  3146. else
  3147. fullpath = fname;
  3148. ret = zlog_set_file (NULL, fullpath, loglevel);
  3149. if (p)
  3150. XFREE (MTYPE_TMP, p);
  3151. if (!ret)
  3152. {
  3153. vty_out (vty, "can't open logfile %s\n", fname);
  3154. return CMD_WARNING;
  3155. }
  3156. if (host.logfile)
  3157. XFREE (MTYPE_HOST, host.logfile);
  3158. host.logfile = XSTRDUP (MTYPE_HOST, fname);
  3159. return CMD_SUCCESS;
  3160. }
  3161. DEFUN (config_log_file,
  3162. config_log_file_cmd,
  3163. "log file FILENAME",
  3164. "Logging control\n"
  3165. "Logging to file\n"
  3166. "Logging filename\n")
  3167. {
  3168. return set_log_file(vty, argv[0], zlog_default->default_lvl);
  3169. }
  3170. DEFUN (config_log_file_level,
  3171. config_log_file_level_cmd,
  3172. "log file FILENAME "LOG_LEVELS,
  3173. "Logging control\n"
  3174. "Logging to file\n"
  3175. "Logging filename\n"
  3176. LOG_LEVEL_DESC)
  3177. {
  3178. int level;
  3179. if ((level = level_match(argv[1])) == ZLOG_DISABLED)
  3180. return CMD_ERR_NO_MATCH;
  3181. return set_log_file(vty, argv[0], level);
  3182. }
  3183. DEFUN (no_config_log_file,
  3184. no_config_log_file_cmd,
  3185. "no log file [FILENAME]",
  3186. NO_STR
  3187. "Logging control\n"
  3188. "Cancel logging to file\n"
  3189. "Logging file name\n")
  3190. {
  3191. zlog_reset_file (NULL);
  3192. if (host.logfile)
  3193. XFREE (MTYPE_HOST, host.logfile);
  3194. host.logfile = NULL;
  3195. return CMD_SUCCESS;
  3196. }
  3197. ALIAS (no_config_log_file,
  3198. no_config_log_file_level_cmd,
  3199. "no log file FILENAME LEVEL",
  3200. NO_STR
  3201. "Logging control\n"
  3202. "Cancel logging to file\n"
  3203. "Logging file name\n"
  3204. "Logging level\n")
  3205. DEFUN (config_log_syslog,
  3206. config_log_syslog_cmd,
  3207. "log syslog",
  3208. "Logging control\n"
  3209. "Set syslog logging level\n")
  3210. {
  3211. zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
  3212. return CMD_SUCCESS;
  3213. }
  3214. DEFUN (config_log_syslog_level,
  3215. config_log_syslog_level_cmd,
  3216. "log syslog "LOG_LEVELS,
  3217. "Logging control\n"
  3218. "Set syslog logging level\n"
  3219. LOG_LEVEL_DESC)
  3220. {
  3221. int level;
  3222. if ((level = level_match(argv[0])) == ZLOG_DISABLED)
  3223. return CMD_ERR_NO_MATCH;
  3224. zlog_set_level (NULL, ZLOG_DEST_SYSLOG, level);
  3225. return CMD_SUCCESS;
  3226. }
  3227. DEFUN_DEPRECATED (config_log_syslog_facility,
  3228. config_log_syslog_facility_cmd,
  3229. "log syslog facility "LOG_FACILITIES,
  3230. "Logging control\n"
  3231. "Logging goes to syslog\n"
  3232. "(Deprecated) Facility parameter for syslog messages\n"
  3233. LOG_FACILITY_DESC)
  3234. {
  3235. int facility;
  3236. if ((facility = facility_match(argv[0])) < 0)
  3237. return CMD_ERR_NO_MATCH;
  3238. zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
  3239. zlog_default->facility = facility;
  3240. return CMD_SUCCESS;
  3241. }
  3242. DEFUN (no_config_log_syslog,
  3243. no_config_log_syslog_cmd,
  3244. "no log syslog [LEVEL]",
  3245. NO_STR
  3246. "Logging control\n"
  3247. "Cancel logging to syslog\n"
  3248. "Logging level\n")
  3249. {
  3250. zlog_set_level (NULL, ZLOG_DEST_SYSLOG, ZLOG_DISABLED);
  3251. return CMD_SUCCESS;
  3252. }
  3253. ALIAS (no_config_log_syslog,
  3254. no_config_log_syslog_facility_cmd,
  3255. "no log syslog facility "LOG_FACILITIES,
  3256. NO_STR
  3257. "Logging control\n"
  3258. "Logging goes to syslog\n"
  3259. "Facility parameter for syslog messages\n"
  3260. LOG_FACILITY_DESC)
  3261. DEFUN (config_log_facility,
  3262. config_log_facility_cmd,
  3263. "log facility "LOG_FACILITIES,
  3264. "Logging control\n"
  3265. "Facility parameter for syslog messages\n"
  3266. LOG_FACILITY_DESC)
  3267. {
  3268. int facility;
  3269. if ((facility = facility_match(argv[0])) < 0)
  3270. return CMD_ERR_NO_MATCH;
  3271. zlog_default->facility = facility;
  3272. return CMD_SUCCESS;
  3273. }
  3274. DEFUN (no_config_log_facility,
  3275. no_config_log_facility_cmd,
  3276. "no log facility [FACILITY]",
  3277. NO_STR
  3278. "Logging control\n"
  3279. "Reset syslog facility to default (daemon)\n"
  3280. "Syslog facility\n")
  3281. {
  3282. zlog_default->facility = LOG_DAEMON;
  3283. return CMD_SUCCESS;
  3284. }
  3285. DEFUN_DEPRECATED (config_log_trap,
  3286. config_log_trap_cmd,
  3287. "log trap "LOG_LEVELS,
  3288. "Logging control\n"
  3289. "(Deprecated) Set logging level and default for all destinations\n"
  3290. LOG_LEVEL_DESC)
  3291. {
  3292. int new_level ;
  3293. int i;
  3294. if ((new_level = level_match(argv[0])) == ZLOG_DISABLED)
  3295. return CMD_ERR_NO_MATCH;
  3296. zlog_default->default_lvl = new_level;
  3297. for (i = 0; i < ZLOG_NUM_DESTS; i++)
  3298. if (zlog_default->maxlvl[i] != ZLOG_DISABLED)
  3299. zlog_default->maxlvl[i] = new_level;
  3300. return CMD_SUCCESS;
  3301. }
  3302. DEFUN_DEPRECATED (no_config_log_trap,
  3303. no_config_log_trap_cmd,
  3304. "no log trap [LEVEL]",
  3305. NO_STR
  3306. "Logging control\n"
  3307. "Permit all logging information\n"
  3308. "Logging level\n")
  3309. {
  3310. zlog_default->default_lvl = LOG_DEBUG;
  3311. return CMD_SUCCESS;
  3312. }
  3313. DEFUN (config_log_record_priority,
  3314. config_log_record_priority_cmd,
  3315. "log record-priority",
  3316. "Logging control\n"
  3317. "Log the priority of the message within the message\n")
  3318. {
  3319. zlog_default->record_priority = 1 ;
  3320. return CMD_SUCCESS;
  3321. }
  3322. DEFUN (no_config_log_record_priority,
  3323. no_config_log_record_priority_cmd,
  3324. "no log record-priority",
  3325. NO_STR
  3326. "Logging control\n"
  3327. "Do not log the priority of the message within the message\n")
  3328. {
  3329. zlog_default->record_priority = 0 ;
  3330. return CMD_SUCCESS;
  3331. }
  3332. DEFUN (config_log_timestamp_precision,
  3333. config_log_timestamp_precision_cmd,
  3334. "log timestamp precision <0-6>",
  3335. "Logging control\n"
  3336. "Timestamp configuration\n"
  3337. "Set the timestamp precision\n"
  3338. "Number of subsecond digits\n")
  3339. {
  3340. if (argc != 1)
  3341. {
  3342. vty_out (vty, "Insufficient arguments%s", VTY_NEWLINE);
  3343. return CMD_WARNING;
  3344. }
  3345. VTY_GET_INTEGER_RANGE("Timestamp Precision",
  3346. zlog_default->timestamp_precision, argv[0], 0, 6);
  3347. return CMD_SUCCESS;
  3348. }
  3349. DEFUN (no_config_log_timestamp_precision,
  3350. no_config_log_timestamp_precision_cmd,
  3351. "no log timestamp precision",
  3352. NO_STR
  3353. "Logging control\n"
  3354. "Timestamp configuration\n"
  3355. "Reset the timestamp precision to the default value of 0\n")
  3356. {
  3357. zlog_default->timestamp_precision = 0 ;
  3358. return CMD_SUCCESS;
  3359. }
  3360. DEFUN (banner_motd_file,
  3361. banner_motd_file_cmd,
  3362. "banner motd file [FILE]",
  3363. "Set banner\n"
  3364. "Banner for motd\n"
  3365. "Banner from a file\n"
  3366. "Filename\n")
  3367. {
  3368. if (host.motdfile)
  3369. XFREE (MTYPE_HOST, host.motdfile);
  3370. host.motdfile = XSTRDUP (MTYPE_HOST, argv[0]);
  3371. return CMD_SUCCESS;
  3372. }
  3373. DEFUN (banner_motd_default,
  3374. banner_motd_default_cmd,
  3375. "banner motd default",
  3376. "Set banner string\n"
  3377. "Strings for motd\n"
  3378. "Default string\n")
  3379. {
  3380. host.motd = default_motd;
  3381. return CMD_SUCCESS;
  3382. }
  3383. DEFUN (no_banner_motd,
  3384. no_banner_motd_cmd,
  3385. "no banner motd",
  3386. NO_STR
  3387. "Set banner string\n"
  3388. "Strings for motd\n")
  3389. {
  3390. host.motd = NULL;
  3391. if (host.motdfile)
  3392. XFREE (MTYPE_HOST, host.motdfile);
  3393. host.motdfile = NULL;
  3394. return CMD_SUCCESS;
  3395. }
  3396. /* Set config filename. Called from vty.c */
  3397. void
  3398. host_config_set (char *filename)
  3399. {
  3400. if (host.config)
  3401. XFREE (MTYPE_HOST, host.config);
  3402. host.config = XSTRDUP (MTYPE_HOST, filename);
  3403. }
  3404. void
  3405. install_default (enum node_type node)
  3406. {
  3407. install_element (node, &config_exit_cmd);
  3408. install_element (node, &config_quit_cmd);
  3409. install_element (node, &config_end_cmd);
  3410. install_element (node, &config_help_cmd);
  3411. install_element (node, &config_list_cmd);
  3412. install_element (node, &config_write_terminal_cmd);
  3413. install_element (node, &config_write_file_cmd);
  3414. install_element (node, &config_write_memory_cmd);
  3415. install_element (node, &config_write_cmd);
  3416. install_element (node, &show_running_config_cmd);
  3417. }
  3418. /* Initialize command interface. Install basic nodes and commands. */
  3419. void
  3420. cmd_init (int terminal)
  3421. {
  3422. command_cr = XSTRDUP(MTYPE_CMD_TOKENS, "<cr>");
  3423. token_cr.type = TOKEN_TERMINAL;
  3424. token_cr.cmd = command_cr;
  3425. token_cr.desc = XSTRDUP(MTYPE_CMD_TOKENS, "");
  3426. /* Allocate initial top vector of commands. */
  3427. cmdvec = vector_init (VECTOR_MIN_SIZE);
  3428. /* Default host value settings. */
  3429. host.name = NULL;
  3430. host.password = NULL;
  3431. host.enable = NULL;
  3432. host.logfile = NULL;
  3433. host.config = NULL;
  3434. host.lines = -1;
  3435. host.motd = default_motd;
  3436. host.motdfile = NULL;
  3437. /* Install top nodes. */
  3438. install_node (&view_node, NULL);
  3439. install_node (&enable_node, NULL);
  3440. install_node (&auth_node, NULL);
  3441. install_node (&auth_enable_node, NULL);
  3442. install_node (&restricted_node, NULL);
  3443. install_node (&config_node, config_write_host);
  3444. /* Each node's basic commands. */
  3445. install_element (VIEW_NODE, &show_version_cmd);
  3446. if (terminal)
  3447. {
  3448. install_element (VIEW_NODE, &config_list_cmd);
  3449. install_element (VIEW_NODE, &config_exit_cmd);
  3450. install_element (VIEW_NODE, &config_quit_cmd);
  3451. install_element (VIEW_NODE, &config_help_cmd);
  3452. install_element (VIEW_NODE, &config_enable_cmd);
  3453. install_element (VIEW_NODE, &config_terminal_length_cmd);
  3454. install_element (VIEW_NODE, &config_terminal_no_length_cmd);
  3455. install_element (VIEW_NODE, &show_logging_cmd);
  3456. install_element (VIEW_NODE, &echo_cmd);
  3457. install_element (RESTRICTED_NODE, &config_list_cmd);
  3458. install_element (RESTRICTED_NODE, &config_exit_cmd);
  3459. install_element (RESTRICTED_NODE, &config_quit_cmd);
  3460. install_element (RESTRICTED_NODE, &config_help_cmd);
  3461. install_element (RESTRICTED_NODE, &config_enable_cmd);
  3462. install_element (RESTRICTED_NODE, &config_terminal_length_cmd);
  3463. install_element (RESTRICTED_NODE, &config_terminal_no_length_cmd);
  3464. install_element (RESTRICTED_NODE, &echo_cmd);
  3465. }
  3466. if (terminal)
  3467. {
  3468. install_default (ENABLE_NODE);
  3469. install_element (ENABLE_NODE, &config_disable_cmd);
  3470. install_element (ENABLE_NODE, &config_terminal_cmd);
  3471. install_element (ENABLE_NODE, &copy_runningconfig_startupconfig_cmd);
  3472. }
  3473. install_element (ENABLE_NODE, &show_startup_config_cmd);
  3474. install_element (ENABLE_NODE, &show_version_cmd);
  3475. if (terminal)
  3476. {
  3477. install_element (ENABLE_NODE, &config_terminal_length_cmd);
  3478. install_element (ENABLE_NODE, &config_terminal_no_length_cmd);
  3479. install_element (ENABLE_NODE, &show_logging_cmd);
  3480. install_element (ENABLE_NODE, &echo_cmd);
  3481. install_element (ENABLE_NODE, &config_logmsg_cmd);
  3482. install_default (CONFIG_NODE);
  3483. }
  3484. install_element (CONFIG_NODE, &hostname_cmd);
  3485. install_element (CONFIG_NODE, &no_hostname_cmd);
  3486. if (terminal)
  3487. {
  3488. install_element (CONFIG_NODE, &password_cmd);
  3489. install_element (CONFIG_NODE, &password_text_cmd);
  3490. install_element (CONFIG_NODE, &enable_password_cmd);
  3491. install_element (CONFIG_NODE, &enable_password_text_cmd);
  3492. install_element (CONFIG_NODE, &no_enable_password_cmd);
  3493. install_element (CONFIG_NODE, &config_log_stdout_cmd);
  3494. install_element (CONFIG_NODE, &config_log_stdout_level_cmd);
  3495. install_element (CONFIG_NODE, &no_config_log_stdout_cmd);
  3496. install_element (CONFIG_NODE, &config_log_monitor_cmd);
  3497. install_element (CONFIG_NODE, &config_log_monitor_level_cmd);
  3498. install_element (CONFIG_NODE, &no_config_log_monitor_cmd);
  3499. install_element (CONFIG_NODE, &config_log_file_cmd);
  3500. install_element (CONFIG_NODE, &config_log_file_level_cmd);
  3501. install_element (CONFIG_NODE, &no_config_log_file_cmd);
  3502. install_element (CONFIG_NODE, &no_config_log_file_level_cmd);
  3503. install_element (CONFIG_NODE, &config_log_syslog_cmd);
  3504. install_element (CONFIG_NODE, &config_log_syslog_level_cmd);
  3505. install_element (CONFIG_NODE, &config_log_syslog_facility_cmd);
  3506. install_element (CONFIG_NODE, &no_config_log_syslog_cmd);
  3507. install_element (CONFIG_NODE, &no_config_log_syslog_facility_cmd);
  3508. install_element (CONFIG_NODE, &config_log_facility_cmd);
  3509. install_element (CONFIG_NODE, &no_config_log_facility_cmd);
  3510. install_element (CONFIG_NODE, &config_log_trap_cmd);
  3511. install_element (CONFIG_NODE, &no_config_log_trap_cmd);
  3512. install_element (CONFIG_NODE, &config_log_record_priority_cmd);
  3513. install_element (CONFIG_NODE, &no_config_log_record_priority_cmd);
  3514. install_element (CONFIG_NODE, &config_log_timestamp_precision_cmd);
  3515. install_element (CONFIG_NODE, &no_config_log_timestamp_precision_cmd);
  3516. install_element (CONFIG_NODE, &service_password_encrypt_cmd);
  3517. install_element (CONFIG_NODE, &no_service_password_encrypt_cmd);
  3518. install_element (CONFIG_NODE, &banner_motd_default_cmd);
  3519. install_element (CONFIG_NODE, &banner_motd_file_cmd);
  3520. install_element (CONFIG_NODE, &no_banner_motd_cmd);
  3521. install_element (CONFIG_NODE, &service_terminal_length_cmd);
  3522. install_element (CONFIG_NODE, &no_service_terminal_length_cmd);
  3523. install_element (VIEW_NODE, &show_thread_cpu_cmd);
  3524. install_element (ENABLE_NODE, &show_thread_cpu_cmd);
  3525. install_element (RESTRICTED_NODE, &show_thread_cpu_cmd);
  3526. install_element (ENABLE_NODE, &clear_thread_cpu_cmd);
  3527. install_element (VIEW_NODE, &show_work_queues_cmd);
  3528. install_element (ENABLE_NODE, &show_work_queues_cmd);
  3529. }
  3530. srand(time(NULL));
  3531. }
  3532. static void
  3533. cmd_terminate_token(struct cmd_token *token)
  3534. {
  3535. unsigned int i, j;
  3536. vector keyword_vect;
  3537. if (token->multiple)
  3538. {
  3539. for (i = 0; i < vector_active(token->multiple); i++)
  3540. cmd_terminate_token(vector_slot(token->multiple, i));
  3541. vector_free(token->multiple);
  3542. token->multiple = NULL;
  3543. }
  3544. if (token->keyword)
  3545. {
  3546. for (i = 0; i < vector_active(token->keyword); i++)
  3547. {
  3548. keyword_vect = vector_slot(token->keyword, i);
  3549. for (j = 0; j < vector_active(keyword_vect); j++)
  3550. cmd_terminate_token(vector_slot(keyword_vect, j));
  3551. vector_free(keyword_vect);
  3552. }
  3553. vector_free(token->keyword);
  3554. token->keyword = NULL;
  3555. }
  3556. XFREE(MTYPE_CMD_TOKENS, token->cmd);
  3557. XFREE(MTYPE_CMD_TOKENS, token->desc);
  3558. XFREE(MTYPE_CMD_TOKENS, token);
  3559. }
  3560. static void
  3561. cmd_terminate_element(struct cmd_element *cmd)
  3562. {
  3563. unsigned int i;
  3564. if (cmd->tokens == NULL)
  3565. return;
  3566. for (i = 0; i < vector_active(cmd->tokens); i++)
  3567. cmd_terminate_token(vector_slot(cmd->tokens, i));
  3568. vector_free(cmd->tokens);
  3569. cmd->tokens = NULL;
  3570. }
  3571. void
  3572. cmd_terminate ()
  3573. {
  3574. unsigned int i, j;
  3575. struct cmd_node *cmd_node;
  3576. struct cmd_element *cmd_element;
  3577. vector cmd_node_v;
  3578. if (cmdvec)
  3579. {
  3580. for (i = 0; i < vector_active (cmdvec); i++)
  3581. if ((cmd_node = vector_slot (cmdvec, i)) != NULL)
  3582. {
  3583. cmd_node_v = cmd_node->cmd_vector;
  3584. for (j = 0; j < vector_active (cmd_node_v); j++)
  3585. if ((cmd_element = vector_slot (cmd_node_v, j)) != NULL)
  3586. cmd_terminate_element(cmd_element);
  3587. vector_free (cmd_node_v);
  3588. }
  3589. vector_free (cmdvec);
  3590. cmdvec = NULL;
  3591. }
  3592. if (command_cr)
  3593. XFREE(MTYPE_CMD_TOKENS, command_cr);
  3594. if (token_cr.desc)
  3595. XFREE(MTYPE_CMD_TOKENS, token_cr.desc);
  3596. if (host.name)
  3597. XFREE (MTYPE_HOST, host.name);
  3598. if (host.password)
  3599. XFREE (MTYPE_HOST, host.password);
  3600. if (host.password_encrypt)
  3601. XFREE (MTYPE_HOST, host.password_encrypt);
  3602. if (host.enable)
  3603. XFREE (MTYPE_HOST, host.enable);
  3604. if (host.enable_encrypt)
  3605. XFREE (MTYPE_HOST, host.enable_encrypt);
  3606. if (host.logfile)
  3607. XFREE (MTYPE_HOST, host.logfile);
  3608. if (host.motdfile)
  3609. XFREE (MTYPE_HOST, host.motdfile);
  3610. if (host.config)
  3611. XFREE (MTYPE_HOST, host.config);
  3612. }