Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

989 lines
20 KiB

  1. /*++
  2. Copyright (c) 1997-2000 Microsoft Corporation
  3. Module Name:
  4. rrprint.c
  5. Abstract:
  6. Domain Name System (DNS) Library
  7. Print resource record routines.
  8. Author:
  9. Jim Gilroy (jamesg) February, 1997
  10. Revision History:
  11. --*/
  12. #include "local.h"
  13. //
  14. // Private prototypes
  15. //
  16. VOID
  17. printBadDataLength(
  18. IN PRINT_ROUTINE PrintRoutine,
  19. IN OUT PPRINT_CONTEXT pContext,
  20. IN PDNS_RECORD pRecord
  21. );
  22. VOID
  23. ARecordPrint(
  24. IN PRINT_ROUTINE PrintRoutine,
  25. IN OUT PPRINT_CONTEXT pContext,
  26. IN PDNS_RECORD pRecord
  27. )
  28. /*++
  29. Routine Description:
  30. Print A records.
  31. Arguments:
  32. PrintRoutine -- routine to print with
  33. pRecord -- record to print
  34. Return Value:
  35. TRUE if record data equal
  36. FALSE otherwise
  37. --*/
  38. {
  39. WORD dataLength = pRecord->wDataLength;
  40. if ( dataLength == sizeof(IP4_ADDRESS) )
  41. {
  42. PrintRoutine(
  43. pContext,
  44. "\tIP address = %s\n",
  45. IP4_STRING(pRecord->Data.A.IpAddress) );
  46. }
  47. else if ( dataLength % sizeof(DNS_A_DATA) )
  48. {
  49. printBadDataLength( PrintRoutine, pContext, pRecord );
  50. }
  51. else // multiple records
  52. {
  53. PIP4_ADDRESS pip = &pRecord->Data.A.IpAddress;
  54. DnsPrint_Lock();
  55. while ( dataLength )
  56. {
  57. PrintRoutine(
  58. pContext,
  59. "\tIP address = %s\n",
  60. IP4_STRING(*pip) );
  61. dataLength -= sizeof(IP4_ADDRESS);
  62. pip++;
  63. }
  64. DnsPrint_Unlock();
  65. }
  66. }
  67. VOID
  68. PtrRecordPrint(
  69. IN PRINT_ROUTINE PrintRoutine,
  70. IN OUT PPRINT_CONTEXT pContext,
  71. IN PDNS_RECORD pRecord
  72. )
  73. /*++
  74. Routine Description:
  75. Print PTR compatible record.
  76. Includes: NS, PTR, CNAME, MB, MR, MG, MD, MF
  77. Arguments:
  78. PrintRoutine -- routine to print with
  79. pRecord -- record to print
  80. Return Value:
  81. TRUE if record data equal
  82. FALSE otherwise
  83. --*/
  84. {
  85. PrintRoutine(
  86. pContext,
  87. "\tHostName = %s%S\n",
  88. RECSTRING_UTF8( pRecord, pRecord->Data.PTR.pNameHost ),
  89. RECSTRING_WIDE( pRecord, pRecord->Data.PTR.pNameHost )
  90. );
  91. }
  92. VOID
  93. MxRecordPrint(
  94. IN PRINT_ROUTINE PrintRoutine,
  95. IN OUT PPRINT_CONTEXT pContext,
  96. IN PDNS_RECORD pRecord
  97. )
  98. /*++
  99. Routine Description:
  100. Print MX compatible record.
  101. Includes: MX, RT, AFSDB
  102. Arguments:
  103. PrintRoutine -- routine to print with
  104. pRecord -- record to print
  105. Return Value:
  106. TRUE if record data equal
  107. FALSE otherwise
  108. --*/
  109. {
  110. PrintRoutine(
  111. pContext,
  112. "\tPreference = %d\n"
  113. "\tExchange = %s%S\n",
  114. pRecord->Data.MX.wPreference,
  115. RECSTRING_UTF8( pRecord, pRecord->Data.MX.pNameExchange ),
  116. RECSTRING_WIDE( pRecord, pRecord->Data.MX.pNameExchange )
  117. );
  118. }
  119. VOID
  120. SoaRecordPrint(
  121. IN PRINT_ROUTINE PrintRoutine,
  122. IN OUT PPRINT_CONTEXT pContext,
  123. IN PDNS_RECORD pRecord
  124. )
  125. /*++
  126. Routine Description:
  127. Print SOA record.
  128. Arguments:
  129. PrintRoutine -- routine to print with
  130. pRecord -- record to print
  131. Return Value:
  132. TRUE if record data equal
  133. FALSE otherwise
  134. --*/
  135. {
  136. PrintRoutine(
  137. pContext,
  138. "\tPrimary = %s%S\n"
  139. "\tAdmin = %s%S\n"
  140. "\tSerial = %d\n"
  141. "\tRefresh = %d\n"
  142. "\tRetry = %d\n"
  143. "\tExpire = %d\n"
  144. "\tDefault TTL = %d\n",
  145. RECSTRING_UTF8( pRecord, pRecord->Data.SOA.pNamePrimaryServer ),
  146. RECSTRING_WIDE( pRecord, pRecord->Data.SOA.pNamePrimaryServer ),
  147. RECSTRING_UTF8( pRecord, pRecord->Data.SOA.pNameAdministrator ),
  148. RECSTRING_WIDE( pRecord, pRecord->Data.SOA.pNameAdministrator ),
  149. pRecord->Data.SOA.dwSerialNo,
  150. pRecord->Data.SOA.dwRefresh,
  151. pRecord->Data.SOA.dwRetry,
  152. pRecord->Data.SOA.dwExpire,
  153. pRecord->Data.SOA.dwDefaultTtl );
  154. }
  155. VOID
  156. MinfoRecordPrint(
  157. IN PRINT_ROUTINE PrintRoutine,
  158. IN OUT PPRINT_CONTEXT pContext,
  159. IN PDNS_RECORD pRecord
  160. )
  161. /*++
  162. Routine Description:
  163. Print MINFO and RP records.
  164. Arguments:
  165. PrintRoutine -- routine to print with
  166. pRecord -- record to print
  167. Return Value:
  168. TRUE if record data equal
  169. FALSE otherwise
  170. --*/
  171. {
  172. PrintRoutine(
  173. pContext,
  174. "\tMailbox = %s%S\n"
  175. "\tErrorsMbox = %s%S\n",
  176. RECSTRING_UTF8( pRecord, pRecord->Data.MINFO.pNameMailbox ),
  177. RECSTRING_WIDE( pRecord, pRecord->Data.MINFO.pNameMailbox ),
  178. RECSTRING_UTF8( pRecord, pRecord->Data.MINFO.pNameErrorsMailbox ),
  179. RECSTRING_WIDE( pRecord, pRecord->Data.MINFO.pNameErrorsMailbox )
  180. );
  181. }
  182. VOID
  183. TxtRecordPrint(
  184. IN PRINT_ROUTINE PrintRoutine,
  185. IN OUT PPRINT_CONTEXT pContext,
  186. IN PDNS_RECORD pRecord
  187. )
  188. /*++
  189. Routine Description:
  190. Print TXT compatible records.
  191. Includes: TXT, X25, HINFO, ISDN
  192. Arguments:
  193. PrintRoutine -- routine to print with
  194. pRecord -- record to print
  195. Return Value:
  196. TRUE if record data equal
  197. FALSE otherwise
  198. --*/
  199. {
  200. LPTSTR * ppstring;
  201. INT i;
  202. INT count;
  203. count = pRecord->Data.TXT.dwStringCount;
  204. ppstring = pRecord->Data.TXT.pStringArray;
  205. DnsPrint_Lock();
  206. PrintRoutine(
  207. pContext,
  208. "\tStringCount = %d\n",
  209. count );
  210. for( i=1; i<=count; i++ )
  211. {
  212. PrintRoutine(
  213. pContext,
  214. "\tString[%d] = %s%S\n",
  215. i,
  216. RECSTRING_UTF8( pRecord, *ppstring ),
  217. RECSTRING_WIDE( pRecord, *ppstring )
  218. );
  219. ppstring++;
  220. }
  221. DnsPrint_Unlock();
  222. }
  223. VOID
  224. AaaaRecordPrint(
  225. IN PRINT_ROUTINE PrintRoutine,
  226. IN OUT PPRINT_CONTEXT pContext,
  227. IN PDNS_RECORD pRecord
  228. )
  229. /*++
  230. Routine Description:
  231. Print flat data records.
  232. Includes AAAA type.
  233. Arguments:
  234. PrintRoutine -- routine to print with
  235. pRecord -- record to print
  236. Return Value:
  237. TRUE if record data equal
  238. FALSE otherwise
  239. --*/
  240. {
  241. CHAR ip6String[ IP6_ADDRESS_STRING_LENGTH ];
  242. Dns_Ip6AddressToString_A(
  243. ip6String,
  244. (PIP6_ADDRESS) &pRecord->Data.AAAA.Ip6Address );
  245. PrintRoutine(
  246. pContext,
  247. "\tIP6 Address = %s\n",
  248. ip6String );
  249. }
  250. VOID
  251. SrvRecordPrint(
  252. IN PRINT_ROUTINE PrintRoutine,
  253. IN OUT PPRINT_CONTEXT pContext,
  254. IN PDNS_RECORD pRecord
  255. )
  256. /*++
  257. Routine Description:
  258. Print SRV record.
  259. Arguments:
  260. PrintRoutine -- routine to print with
  261. pRecord -- record to print
  262. Return Value:
  263. TRUE if record data equal
  264. FALSE otherwise
  265. --*/
  266. {
  267. PrintRoutine(
  268. pContext,
  269. "\tPriority = %d\n"
  270. "\tWeight = %d\n"
  271. "\tPort = %d\n"
  272. "\tTarget Host = %s%S\n",
  273. pRecord->Data.SRV.wPriority,
  274. pRecord->Data.SRV.wWeight,
  275. pRecord->Data.SRV.wPort,
  276. RECSTRING_UTF8( pRecord, pRecord->Data.SRV.pNameTarget ),
  277. RECSTRING_WIDE( pRecord, pRecord->Data.SRV.pNameTarget )
  278. );
  279. }
  280. VOID
  281. AtmaRecordPrint(
  282. IN PRINT_ROUTINE PrintRoutine,
  283. IN OUT PPRINT_CONTEXT pContext,
  284. IN PDNS_RECORD pRecord
  285. )
  286. /*++
  287. Routine Description:
  288. Print ATMA record.
  289. Arguments:
  290. PrintRoutine -- routine to print with
  291. pRecord -- record to print
  292. Return Value:
  293. TRUE if record data equal
  294. FALSE otherwise
  295. --*/
  296. {
  297. PrintRoutine(
  298. pContext,
  299. "\tAddress type = %d\n",
  300. pRecord->Data.ATMA.AddressType );
  301. if ( pRecord->Data.ATMA.Address &&
  302. pRecord->Data.ATMA.AddressType == DNS_ATMA_FORMAT_E164 )
  303. {
  304. PrintRoutine(
  305. pContext,
  306. "\tAddress = %s\n",
  307. pRecord->Data.ATMA.Address );
  308. }
  309. else if ( pRecord->Data.ATMA.Address )
  310. {
  311. DnsPrint_RawOctets(
  312. PrintRoutine,
  313. pContext,
  314. "\tAddress = ",
  315. "\t ", // no line header
  316. pRecord->Data.ATMA.Address,
  317. pRecord->wDataLength - 1
  318. );
  319. }
  320. }
  321. VOID
  322. TsigRecordPrint(
  323. IN PRINT_ROUTINE PrintRoutine,
  324. IN OUT PPRINT_CONTEXT pContext,
  325. IN PDNS_RECORD pRecord
  326. )
  327. /*++
  328. Routine Description:
  329. Print TSIG record.
  330. Arguments:
  331. PrintRoutine -- routine to print with
  332. pRecord -- record to print
  333. Return Value:
  334. TRUE if record data equal
  335. FALSE otherwise
  336. --*/
  337. {
  338. DnsPrint_Lock();
  339. if ( pRecord->Data.TSIG.bPacketPointers )
  340. {
  341. DnsPrint_PacketName(
  342. PrintRoutine,
  343. pContext,
  344. "\tAlgorithm = ",
  345. pRecord->Data.TSIG.pAlgorithmPacket,
  346. NULL, // no packet context
  347. NULL,
  348. "\n" );
  349. }
  350. else
  351. {
  352. PrintRoutine(
  353. pContext,
  354. "\tAlgorithm = %s%S\n",
  355. RECSTRING_UTF8( pRecord, pRecord->Data.TSIG.pNameAlgorithm ),
  356. RECSTRING_WIDE( pRecord, pRecord->Data.TSIG.pNameAlgorithm )
  357. );
  358. }
  359. PrintRoutine(
  360. pContext,
  361. "\tSigned Time = %I64u\n"
  362. "\tFudge Time = %u\n"
  363. "\tSig Length = %u\n"
  364. "\tSig Ptr = %p\n"
  365. "\tXid = %u\n"
  366. "\tError = %u\n"
  367. "\tOtherLength = %u\n"
  368. "\tOther Ptr = %p\n",
  369. pRecord->Data.TSIG.i64CreateTime,
  370. pRecord->Data.TSIG.wFudgeTime,
  371. pRecord->Data.TSIG.wSigLength,
  372. pRecord->Data.TSIG.pSignature,
  373. pRecord->Data.TSIG.wOriginalXid,
  374. pRecord->Data.TSIG.wError,
  375. pRecord->Data.TSIG.wOtherLength,
  376. pRecord->Data.TSIG.pOtherData
  377. );
  378. if ( pRecord->Data.TSIG.pSignature )
  379. {
  380. DnsPrint_RawOctets(
  381. PrintRoutine,
  382. pContext,
  383. "Signature:",
  384. NULL, // no line header
  385. pRecord->Data.TSIG.pSignature,
  386. pRecord->Data.TSIG.wSigLength
  387. );
  388. }
  389. if ( pRecord->Data.TSIG.pOtherData )
  390. {
  391. DnsPrint_RawOctets(
  392. PrintRoutine,
  393. pContext,
  394. "Other Data:",
  395. NULL, // no line header
  396. pRecord->Data.TSIG.pOtherData,
  397. pRecord->Data.TSIG.wOtherLength
  398. );
  399. }
  400. DnsPrint_Unlock();
  401. }
  402. VOID
  403. TkeyRecordPrint(
  404. IN PRINT_ROUTINE PrintRoutine,
  405. IN OUT PPRINT_CONTEXT pContext,
  406. IN PDNS_RECORD pRecord
  407. )
  408. /*++
  409. Routine Description:
  410. Print TKEY record.
  411. Arguments:
  412. PrintRoutine -- routine to print with
  413. pRecord -- record to print
  414. Return Value:
  415. TRUE if record data equal
  416. FALSE otherwise
  417. --*/
  418. {
  419. DnsPrint_Lock();
  420. if ( pRecord->Data.TKEY.bPacketPointers )
  421. {
  422. DnsPrint_PacketName(
  423. PrintRoutine,
  424. pContext,
  425. "\tAlgorithm = ",
  426. pRecord->Data.TKEY.pAlgorithmPacket,
  427. NULL, // no packet context
  428. NULL,
  429. "\n" );
  430. }
  431. else
  432. {
  433. PrintRoutine(
  434. pContext,
  435. "\tAlgorithm = %s%S\n",
  436. RECSTRING_UTF8( pRecord, pRecord->Data.TKEY.pNameAlgorithm ),
  437. RECSTRING_WIDE( pRecord, pRecord->Data.TKEY.pNameAlgorithm )
  438. );
  439. }
  440. PrintRoutine(
  441. pContext,
  442. "\tCreate Time = %d\n"
  443. "\tExpire Time = %d\n"
  444. "\tMode = %d\n"
  445. "\tError = %d\n"
  446. "\tKey Length = %d\n"
  447. "\tKey Ptr = %p\n"
  448. "\tOtherLength = %d\n"
  449. "\tOther Ptr = %p\n",
  450. pRecord->Data.TKEY.dwCreateTime,
  451. pRecord->Data.TKEY.dwExpireTime,
  452. pRecord->Data.TKEY.wMode,
  453. pRecord->Data.TKEY.wError,
  454. pRecord->Data.TKEY.wKeyLength,
  455. pRecord->Data.TKEY.pKey,
  456. pRecord->Data.TKEY.wOtherLength,
  457. pRecord->Data.TKEY.pOtherData
  458. );
  459. if ( pRecord->Data.TKEY.pKey )
  460. {
  461. DnsPrint_RawOctets(
  462. PrintRoutine,
  463. pContext,
  464. "Key:",
  465. NULL, // no line header
  466. pRecord->Data.TKEY.pKey,
  467. pRecord->Data.TKEY.wKeyLength
  468. );
  469. }
  470. if ( pRecord->Data.TKEY.pOtherData )
  471. {
  472. DnsPrint_RawOctets(
  473. PrintRoutine,
  474. pContext,
  475. "Other Data:",
  476. NULL, // no line header
  477. pRecord->Data.TKEY.pOtherData,
  478. pRecord->Data.TKEY.wOtherLength
  479. );
  480. }
  481. DnsPrint_Unlock();
  482. }
  483. //
  484. // RR Print Dispatch Table
  485. //
  486. typedef VOID (* RR_PRINT_FUNCTION)(
  487. PRINT_ROUTINE,
  488. PPRINT_CONTEXT,
  489. PDNS_RECORD );
  490. // extern RR_PRINT_FUNCTION RRPrintTable[];
  491. RR_PRINT_FUNCTION RRPrintTable[] =
  492. {
  493. NULL, // ZERO
  494. ARecordPrint, // A
  495. PtrRecordPrint, // NS
  496. PtrRecordPrint, // MD
  497. PtrRecordPrint, // MF
  498. PtrRecordPrint, // CNAME
  499. SoaRecordPrint, // SOA
  500. PtrRecordPrint, // MB
  501. PtrRecordPrint, // MG
  502. PtrRecordPrint, // MR
  503. NULL, // NULL
  504. NULL, //WksRecordPrint, // WKS
  505. PtrRecordPrint, // PTR
  506. TxtRecordPrint, // HINFO
  507. MinfoRecordPrint, // MINFO
  508. MxRecordPrint, // MX
  509. TxtRecordPrint, // TXT
  510. MinfoRecordPrint, // RP
  511. MxRecordPrint, // AFSDB
  512. TxtRecordPrint, // X25
  513. TxtRecordPrint, // ISDN
  514. MxRecordPrint, // RT
  515. NULL, // NSAP
  516. NULL, // NSAPPTR
  517. NULL, // SIG
  518. NULL, // KEY
  519. NULL, // PX
  520. NULL, // GPOS
  521. AaaaRecordPrint, // AAAA
  522. NULL, // LOC
  523. NULL, // NXT
  524. NULL, // EID
  525. NULL, // NIMLOC
  526. SrvRecordPrint, // SRV
  527. AtmaRecordPrint, // ATMA
  528. NULL, // NAPTR
  529. NULL, // KX
  530. NULL, // CERT
  531. NULL, // A6
  532. NULL, // DNAME
  533. NULL, // SINK
  534. NULL, // OPT
  535. NULL, // 42
  536. NULL, // 43
  537. NULL, // 44
  538. NULL, // 45
  539. NULL, // 46
  540. NULL, // 47
  541. NULL, // 48
  542. //
  543. // NOTE: last type indexed by type ID MUST be set
  544. // as MAX_SELF_INDEXED_TYPE #define in record.h
  545. // (see note above in record info table)
  546. //
  547. // Pseudo record types
  548. //
  549. TkeyRecordPrint, // TKEY
  550. TsigRecordPrint, // TSIG
  551. //
  552. // MS only types
  553. //
  554. NULL, // WINS
  555. NULL, // WINSR
  556. };
  557. //
  558. // Generic print record functions
  559. //
  560. VOID
  561. DnsPrint_Record(
  562. IN PRINT_ROUTINE PrintRoutine,
  563. IN OUT PPRINT_CONTEXT pContext,
  564. IN LPSTR pszHeader,
  565. IN PDNS_RECORD pRecord,
  566. IN PDNS_RECORD pPreviousRecord OPTIONAL
  567. )
  568. /*++
  569. Routine Description:
  570. Print record.
  571. Arguments:
  572. PrintRoutine -- routine to print with
  573. pszHeader -- header message
  574. pRecord -- record to print
  575. pPreviousRecord -- previous record in RR set (if any)
  576. Return Value:
  577. None.
  578. --*/
  579. {
  580. WORD type = pRecord->wType;
  581. WORD dataLength = pRecord->wDataLength;
  582. WORD index;
  583. DnsPrint_Lock();
  584. if ( pszHeader )
  585. {
  586. PrintRoutine(
  587. pContext,
  588. pszHeader );
  589. }
  590. if ( !pRecord )
  591. {
  592. PrintRoutine(
  593. pContext,
  594. "ERROR: Null record ptr to print!\n" );
  595. goto Unlock;
  596. }
  597. //
  598. // print record info
  599. //
  600. // same as previous -- skip duplicated info
  601. // must match
  602. // - name ptr (or have no name)
  603. // - type
  604. // - flags that make set (section)
  605. if ( pPreviousRecord &&
  606. (!pRecord->pName || pPreviousRecord->pName == pRecord->pName) &&
  607. pPreviousRecord->wType == type &&
  608. pPreviousRecord->Flags.S.Section == pRecord->Flags.S.Section )
  609. {
  610. PrintRoutine(
  611. pContext,
  612. " Next record in set:\n"
  613. "\tPtr = %p, pNext = %p\n"
  614. "\tFlags = %08x\n"
  615. "\tTTL = %d\n"
  616. "\tReserved = %d\n"
  617. "\tDataLength = %d\n",
  618. pRecord,
  619. pRecord->pNext,
  620. pRecord->Flags.DW,
  621. pRecord->dwTtl,
  622. pRecord->dwReserved,
  623. dataLength );
  624. }
  625. //
  626. // different from previous -- full print
  627. //
  628. else
  629. {
  630. PrintRoutine(
  631. pContext,
  632. " Record:\n"
  633. "\tPtr = %p, pNext = %p\n"
  634. "\tOwner = %s%S\n"
  635. "\tType = %s (%d)\n"
  636. "\tFlags = %08x\n"
  637. "\t\tSection = %d\n"
  638. "\t\tDelete = %d\n"
  639. "\t\tCharSet = %d\n"
  640. "\tTTL = %d\n"
  641. "\tReserved = %d\n"
  642. "\tDataLength = %d\n",
  643. pRecord,
  644. pRecord->pNext,
  645. RECSTRING_UTF8( pRecord, pRecord->pName ),
  646. RECSTRING_WIDE( pRecord, pRecord->pName ),
  647. Dns_RecordStringForType( type ),
  648. type,
  649. pRecord->Flags.DW,
  650. pRecord->Flags.S.Section,
  651. pRecord->Flags.S.Delete,
  652. pRecord->Flags.S.CharSet,
  653. pRecord->dwTtl,
  654. pRecord->dwReserved,
  655. dataLength );
  656. }
  657. //
  658. // if no data -- done
  659. //
  660. if ( ! dataLength )
  661. {
  662. goto Unlock;
  663. }
  664. //
  665. // print data
  666. //
  667. index = INDEX_FOR_TYPE( type );
  668. DNS_ASSERT( index <= MAX_RECORD_TYPE_INDEX );
  669. if ( index && RRPrintTable[ index ] )
  670. {
  671. RRPrintTable[ index ](
  672. PrintRoutine,
  673. pContext,
  674. pRecord );
  675. }
  676. else if ( !index )
  677. {
  678. PrintRoutine(
  679. pContext,
  680. "\tUnknown type: can not print data\n" );
  681. }
  682. else
  683. {
  684. // DCR: should do raw bytes print
  685. PrintRoutine(
  686. pContext,
  687. "\tNo print routine for this type\n" );
  688. }
  689. Unlock:
  690. DnsPrint_Unlock();
  691. }
  692. VOID
  693. printBadDataLength(
  694. IN PRINT_ROUTINE PrintRoutine,
  695. IN OUT PPRINT_CONTEXT pContext,
  696. IN PDNS_RECORD pRecord
  697. )
  698. /*++
  699. Routine Description:
  700. Prints waring on bad data in record.
  701. Arguments:
  702. PrintRoutine -- routine to print with
  703. pRecord -- record with bad data
  704. Return Value:
  705. None.
  706. --*/
  707. {
  708. PrintRoutine(
  709. pContext,
  710. "\tERROR: Invalid record data length for this type.\n" );
  711. }
  712. VOID
  713. DnsPrint_RecordSet(
  714. IN PRINT_ROUTINE PrintRoutine,
  715. IN OUT PPRINT_CONTEXT pContext,
  716. IN LPSTR pszHeader,
  717. IN PDNS_RECORD pRecord
  718. )
  719. /*++
  720. Routine Description:
  721. Print record set.
  722. Arguments:
  723. PrintRoutine -- routine to print with
  724. pRecord -- record set to print
  725. Return Value:
  726. None
  727. --*/
  728. {
  729. PDNS_RECORD pprevious;
  730. DnsPrint_Lock();
  731. if ( pszHeader )
  732. {
  733. PrintRoutine(
  734. pContext,
  735. pszHeader );
  736. }
  737. if ( !pRecord )
  738. {
  739. PrintRoutine(
  740. pContext,
  741. " No Records in list.\n" );
  742. goto Unlock;
  743. }
  744. //
  745. // print all records in set
  746. //
  747. pprevious = NULL;
  748. while ( pRecord )
  749. {
  750. DnsPrint_Record(
  751. PrintRoutine,
  752. pContext,
  753. NULL,
  754. pRecord,
  755. pprevious );
  756. pprevious = pRecord;
  757. pRecord = pRecord->pNext;
  758. }
  759. PrintRoutine(
  760. pContext,
  761. "\n" );
  762. Unlock:
  763. DnsPrint_Unlock();
  764. }
  765. //
  766. // End rrprint.c
  767. //