17b5038d7SDag-Erling Smørgrav /*
27b5038d7SDag-Erling Smørgrav * util.c
37b5038d7SDag-Erling Smørgrav * some handy function needed in drill and not implemented
47b5038d7SDag-Erling Smørgrav * in ldns
57b5038d7SDag-Erling Smørgrav * (c) 2005 NLnet Labs
67b5038d7SDag-Erling Smørgrav *
77b5038d7SDag-Erling Smørgrav * See the file LICENSE for the license
87b5038d7SDag-Erling Smørgrav *
97b5038d7SDag-Erling Smørgrav */
107b5038d7SDag-Erling Smørgrav
117b5038d7SDag-Erling Smørgrav #include "drill.h"
127b5038d7SDag-Erling Smørgrav #include <ldns/ldns.h>
137b5038d7SDag-Erling Smørgrav
147b5038d7SDag-Erling Smørgrav #include <errno.h>
157b5038d7SDag-Erling Smørgrav
162787e39aSDag-Erling Smørgrav static int
read_line(FILE * input,char * line,size_t len)177b5038d7SDag-Erling Smørgrav read_line(FILE *input, char *line, size_t len)
187b5038d7SDag-Erling Smørgrav {
192787e39aSDag-Erling Smørgrav int i;
20*17d15b25SDag-Erling Smørgrav int c;
217b5038d7SDag-Erling Smørgrav
222787e39aSDag-Erling Smørgrav for (i = 0; i < (int)len-1; i++) {
23*17d15b25SDag-Erling Smørgrav c = getc(input);
247b5038d7SDag-Erling Smørgrav if (c == EOF) {
257b5038d7SDag-Erling Smørgrav return -1;
267b5038d7SDag-Erling Smørgrav } else if (c != '\n') {
277b5038d7SDag-Erling Smørgrav line[i] = c;
287b5038d7SDag-Erling Smørgrav } else {
297b5038d7SDag-Erling Smørgrav break;
307b5038d7SDag-Erling Smørgrav }
317b5038d7SDag-Erling Smørgrav }
327b5038d7SDag-Erling Smørgrav line[i] = '\0';
337b5038d7SDag-Erling Smørgrav return i;
347b5038d7SDag-Erling Smørgrav }
357b5038d7SDag-Erling Smørgrav
367b5038d7SDag-Erling Smørgrav /* key_list must be initialized with ldns_rr_list_new() */
377b5038d7SDag-Erling Smørgrav ldns_status
read_key_file(const char * filename,ldns_rr_list * key_list,bool silently)382787e39aSDag-Erling Smørgrav read_key_file(const char *filename, ldns_rr_list *key_list, bool silently)
397b5038d7SDag-Erling Smørgrav {
407b5038d7SDag-Erling Smørgrav int line_len = 0;
417b5038d7SDag-Erling Smørgrav int line_nr = 0;
427b5038d7SDag-Erling Smørgrav int key_count = 0;
432787e39aSDag-Erling Smørgrav char line[LDNS_MAX_LINELEN];
447b5038d7SDag-Erling Smørgrav ldns_status status;
457b5038d7SDag-Erling Smørgrav FILE *input_file;
467b5038d7SDag-Erling Smørgrav ldns_rr *rr;
477b5038d7SDag-Erling Smørgrav
487b5038d7SDag-Erling Smørgrav input_file = fopen(filename, "r");
497b5038d7SDag-Erling Smørgrav if (!input_file) {
502787e39aSDag-Erling Smørgrav if (! silently) {
517b5038d7SDag-Erling Smørgrav fprintf(stderr, "Error opening %s: %s\n",
527b5038d7SDag-Erling Smørgrav filename, strerror(errno));
532787e39aSDag-Erling Smørgrav }
547b5038d7SDag-Erling Smørgrav return LDNS_STATUS_ERR;
557b5038d7SDag-Erling Smørgrav }
567b5038d7SDag-Erling Smørgrav while (line_len >= 0) {
577b5038d7SDag-Erling Smørgrav line_len = (int) read_line(input_file, line, sizeof(line));
587b5038d7SDag-Erling Smørgrav line_nr++;
597b5038d7SDag-Erling Smørgrav if (line_len > 0 && line[0] != ';') {
607b5038d7SDag-Erling Smørgrav status = ldns_rr_new_frm_str(&rr, line, 0, NULL, NULL);
617b5038d7SDag-Erling Smørgrav if (status != LDNS_STATUS_OK) {
622787e39aSDag-Erling Smørgrav if (! silently) {
637b5038d7SDag-Erling Smørgrav fprintf(stderr,
642787e39aSDag-Erling Smørgrav "Error parsing DNSKEY RR "
652787e39aSDag-Erling Smørgrav "in line %d: %s\n", line_nr,
662787e39aSDag-Erling Smørgrav ldns_get_errorstr_by_id(status)
672787e39aSDag-Erling Smørgrav );
682787e39aSDag-Erling Smørgrav }
697b5038d7SDag-Erling Smørgrav } else if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_DNSKEY ||
707b5038d7SDag-Erling Smørgrav ldns_rr_get_type(rr) == LDNS_RR_TYPE_DS) {
717b5038d7SDag-Erling Smørgrav ldns_rr_list_push_rr(key_list, rr);
727b5038d7SDag-Erling Smørgrav key_count++;
737b5038d7SDag-Erling Smørgrav } else {
747b5038d7SDag-Erling Smørgrav ldns_rr_free(rr);
757b5038d7SDag-Erling Smørgrav }
767b5038d7SDag-Erling Smørgrav }
777b5038d7SDag-Erling Smørgrav }
782787e39aSDag-Erling Smørgrav fclose(input_file);
797b5038d7SDag-Erling Smørgrav if (key_count > 0) {
807b5038d7SDag-Erling Smørgrav return LDNS_STATUS_OK;
817b5038d7SDag-Erling Smørgrav } else {
827b5038d7SDag-Erling Smørgrav /*fprintf(stderr, "No keys read\n");*/
837b5038d7SDag-Erling Smørgrav return LDNS_STATUS_ERR;
847b5038d7SDag-Erling Smørgrav }
857b5038d7SDag-Erling Smørgrav }
867b5038d7SDag-Erling Smørgrav
877b5038d7SDag-Erling Smørgrav ldns_rdf *
ldns_rdf_new_addr_frm_str(char * str)887b5038d7SDag-Erling Smørgrav ldns_rdf_new_addr_frm_str(char *str)
897b5038d7SDag-Erling Smørgrav {
907b5038d7SDag-Erling Smørgrav ldns_rdf *a;
917b5038d7SDag-Erling Smørgrav
927b5038d7SDag-Erling Smørgrav a = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_A, str);
937b5038d7SDag-Erling Smørgrav if (!a) {
947b5038d7SDag-Erling Smørgrav /* maybe ip6 */
957b5038d7SDag-Erling Smørgrav a = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_AAAA, str);
967b5038d7SDag-Erling Smørgrav if (!a) {
977b5038d7SDag-Erling Smørgrav return NULL;
987b5038d7SDag-Erling Smørgrav }
997b5038d7SDag-Erling Smørgrav }
1007b5038d7SDag-Erling Smørgrav return a;
1017b5038d7SDag-Erling Smørgrav }
1027b5038d7SDag-Erling Smørgrav
1037b5038d7SDag-Erling Smørgrav static inline void
local_print_ds(FILE * out,const char * pre,ldns_rr * ds)1047b5038d7SDag-Erling Smørgrav local_print_ds(FILE* out, const char* pre, ldns_rr* ds)
1057b5038d7SDag-Erling Smørgrav {
1067b5038d7SDag-Erling Smørgrav if (out && ds) {
1077b5038d7SDag-Erling Smørgrav fprintf(out, "%s", pre);
1087b5038d7SDag-Erling Smørgrav ldns_rr_print(out, ds);
1097b5038d7SDag-Erling Smørgrav ldns_rr_free(ds);
1107b5038d7SDag-Erling Smørgrav }
1117b5038d7SDag-Erling Smørgrav }
1127b5038d7SDag-Erling Smørgrav
1137b5038d7SDag-Erling Smørgrav /*
1147b5038d7SDag-Erling Smørgrav * For all keys in a packet print the DS
1157b5038d7SDag-Erling Smørgrav */
1167b5038d7SDag-Erling Smørgrav void
print_ds_of_keys(ldns_pkt * p)1177b5038d7SDag-Erling Smørgrav print_ds_of_keys(ldns_pkt *p)
1187b5038d7SDag-Erling Smørgrav {
1197b5038d7SDag-Erling Smørgrav ldns_rr_list *keys;
1207b5038d7SDag-Erling Smørgrav uint16_t i;
1217b5038d7SDag-Erling Smørgrav ldns_rr *ds;
1227b5038d7SDag-Erling Smørgrav
1237b5038d7SDag-Erling Smørgrav /* TODO fix the section stuff, here or in ldns */
1247b5038d7SDag-Erling Smørgrav keys = ldns_pkt_rr_list_by_type(p, LDNS_RR_TYPE_DNSKEY,
1257b5038d7SDag-Erling Smørgrav LDNS_SECTION_ANSWER);
1267b5038d7SDag-Erling Smørgrav
1277b5038d7SDag-Erling Smørgrav /* this also returns the question section rr, which does not
1287b5038d7SDag-Erling Smørgrav * have any data.... and this inturn crashes everything */
1297b5038d7SDag-Erling Smørgrav
1307b5038d7SDag-Erling Smørgrav if (keys) {
1317b5038d7SDag-Erling Smørgrav for (i = 0; i < ldns_rr_list_rr_count(keys); i++) {
1327b5038d7SDag-Erling Smørgrav fprintf(stdout, ";\n; equivalent DS records for key %u:\n",
1337b5038d7SDag-Erling Smørgrav (unsigned int)ldns_calc_keytag(ldns_rr_list_rr(keys, i)));
1347b5038d7SDag-Erling Smørgrav
1357b5038d7SDag-Erling Smørgrav ds = ldns_key_rr2ds(ldns_rr_list_rr(keys, i), LDNS_SHA1);
1367b5038d7SDag-Erling Smørgrav local_print_ds(stdout, "; sha1: ", ds);
1377b5038d7SDag-Erling Smørgrav ds = ldns_key_rr2ds(ldns_rr_list_rr(keys, i), LDNS_SHA256);
1387b5038d7SDag-Erling Smørgrav local_print_ds(stdout, "; sha256: ", ds);
1397b5038d7SDag-Erling Smørgrav }
1402787e39aSDag-Erling Smørgrav ldns_rr_list_deep_free(keys);
1417b5038d7SDag-Erling Smørgrav }
1427b5038d7SDag-Erling Smørgrav }
1437b5038d7SDag-Erling Smørgrav
1447b5038d7SDag-Erling Smørgrav static void
print_class_type(FILE * fp,ldns_rr * r)1457b5038d7SDag-Erling Smørgrav print_class_type(FILE *fp, ldns_rr *r)
1467b5038d7SDag-Erling Smørgrav {
1477b5038d7SDag-Erling Smørgrav ldns_lookup_table *lt;
1487b5038d7SDag-Erling Smørgrav lt = ldns_lookup_by_id(ldns_rr_classes, ldns_rr_get_class(r));
1497b5038d7SDag-Erling Smørgrav if (lt) {
1507b5038d7SDag-Erling Smørgrav fprintf(fp, " %s", lt->name);
1517b5038d7SDag-Erling Smørgrav } else {
1527b5038d7SDag-Erling Smørgrav fprintf(fp, " CLASS%d", ldns_rr_get_class(r));
1537b5038d7SDag-Erling Smørgrav }
1547b5038d7SDag-Erling Smørgrav /* okay not THE way - but the quickest */
1557b5038d7SDag-Erling Smørgrav switch (ldns_rr_get_type(r)) {
1567b5038d7SDag-Erling Smørgrav case LDNS_RR_TYPE_RRSIG:
1577b5038d7SDag-Erling Smørgrav fprintf(fp, " RRSIG ");
1587b5038d7SDag-Erling Smørgrav break;
1597b5038d7SDag-Erling Smørgrav case LDNS_RR_TYPE_DNSKEY:
1607b5038d7SDag-Erling Smørgrav fprintf(fp, " DNSKEY ");
1617b5038d7SDag-Erling Smørgrav break;
1627b5038d7SDag-Erling Smørgrav case LDNS_RR_TYPE_DS:
1637b5038d7SDag-Erling Smørgrav fprintf(fp, " DS ");
1647b5038d7SDag-Erling Smørgrav break;
1657b5038d7SDag-Erling Smørgrav default:
1667b5038d7SDag-Erling Smørgrav break;
1677b5038d7SDag-Erling Smørgrav }
1687b5038d7SDag-Erling Smørgrav }
1697b5038d7SDag-Erling Smørgrav
1707b5038d7SDag-Erling Smørgrav
1717b5038d7SDag-Erling Smørgrav void
print_ds_abbr(FILE * fp,ldns_rr * ds)1727b5038d7SDag-Erling Smørgrav print_ds_abbr(FILE *fp, ldns_rr *ds)
1737b5038d7SDag-Erling Smørgrav {
1747b5038d7SDag-Erling Smørgrav if (!ds || (ldns_rr_get_type(ds) != LDNS_RR_TYPE_DS)) {
1757b5038d7SDag-Erling Smørgrav return;
1767b5038d7SDag-Erling Smørgrav }
1777b5038d7SDag-Erling Smørgrav
1787b5038d7SDag-Erling Smørgrav ldns_rdf_print(fp, ldns_rr_owner(ds));
1797b5038d7SDag-Erling Smørgrav fprintf(fp, " %d", (int)ldns_rr_ttl(ds));
1807b5038d7SDag-Erling Smørgrav print_class_type(fp, ds);
1817b5038d7SDag-Erling Smørgrav ldns_rdf_print(fp, ldns_rr_rdf(ds, 0)); fprintf(fp, " ");
1827b5038d7SDag-Erling Smørgrav ldns_rdf_print(fp, ldns_rr_rdf(ds, 1)); fprintf(fp, " ");
1837b5038d7SDag-Erling Smørgrav ldns_rdf_print(fp, ldns_rr_rdf(ds, 2)); fprintf(fp, " ");
1847b5038d7SDag-Erling Smørgrav ldns_rdf_print(fp, ldns_rr_rdf(ds, 3)); fprintf(fp, " ");
1857b5038d7SDag-Erling Smørgrav }
1867b5038d7SDag-Erling Smørgrav
1877b5038d7SDag-Erling Smørgrav /* print some of the elements of a signature */
1887b5038d7SDag-Erling Smørgrav void
print_rrsig_abbr(FILE * fp,ldns_rr * sig)1897b5038d7SDag-Erling Smørgrav print_rrsig_abbr(FILE *fp, ldns_rr *sig) {
1907b5038d7SDag-Erling Smørgrav if (!sig || (ldns_rr_get_type(sig) != LDNS_RR_TYPE_RRSIG)) {
1917b5038d7SDag-Erling Smørgrav return;
1927b5038d7SDag-Erling Smørgrav }
1937b5038d7SDag-Erling Smørgrav
1947b5038d7SDag-Erling Smørgrav ldns_rdf_print(fp, ldns_rr_owner(sig));
1957b5038d7SDag-Erling Smørgrav fprintf(fp, " %d", (int)ldns_rr_ttl(sig));
1967b5038d7SDag-Erling Smørgrav print_class_type(fp, sig);
1977b5038d7SDag-Erling Smørgrav
1987b5038d7SDag-Erling Smørgrav /* print a number of rdf's */
1997b5038d7SDag-Erling Smørgrav /* typecovered */
2007b5038d7SDag-Erling Smørgrav ldns_rdf_print(fp, ldns_rr_rdf(sig, 0)); fprintf(fp, " ");
2017b5038d7SDag-Erling Smørgrav /* algo */
2027b5038d7SDag-Erling Smørgrav ldns_rdf_print(fp, ldns_rr_rdf(sig, 1)); fprintf(fp, " ");
2037b5038d7SDag-Erling Smørgrav /* labels */
2047b5038d7SDag-Erling Smørgrav ldns_rdf_print(fp, ldns_rr_rdf(sig, 2)); fprintf(fp, " (\n\t\t\t");
2057b5038d7SDag-Erling Smørgrav /* expir */
2067b5038d7SDag-Erling Smørgrav ldns_rdf_print(fp, ldns_rr_rdf(sig, 4)); fprintf(fp, " ");
2077b5038d7SDag-Erling Smørgrav /* incep */
2087b5038d7SDag-Erling Smørgrav ldns_rdf_print(fp, ldns_rr_rdf(sig, 5)); fprintf(fp, " ");
2097b5038d7SDag-Erling Smørgrav /* key-id */
2107b5038d7SDag-Erling Smørgrav ldns_rdf_print(fp, ldns_rr_rdf(sig, 6)); fprintf(fp, " ");
2117b5038d7SDag-Erling Smørgrav /* key owner */
2127b5038d7SDag-Erling Smørgrav ldns_rdf_print(fp, ldns_rr_rdf(sig, 7)); fprintf(fp, ")");
2137b5038d7SDag-Erling Smørgrav }
2147b5038d7SDag-Erling Smørgrav
2157b5038d7SDag-Erling Smørgrav void
print_dnskey_abbr(FILE * fp,ldns_rr * key)2167b5038d7SDag-Erling Smørgrav print_dnskey_abbr(FILE *fp, ldns_rr *key)
2177b5038d7SDag-Erling Smørgrav {
2187b5038d7SDag-Erling Smørgrav if (!key || (ldns_rr_get_type(key) != LDNS_RR_TYPE_DNSKEY)) {
2197b5038d7SDag-Erling Smørgrav return;
2207b5038d7SDag-Erling Smørgrav }
2217b5038d7SDag-Erling Smørgrav
2227b5038d7SDag-Erling Smørgrav ldns_rdf_print(fp, ldns_rr_owner(key));
2237b5038d7SDag-Erling Smørgrav fprintf(fp, " %d", (int)ldns_rr_ttl(key));
2247b5038d7SDag-Erling Smørgrav print_class_type(fp, key);
2257b5038d7SDag-Erling Smørgrav
2267b5038d7SDag-Erling Smørgrav /* print a number of rdf's */
2277b5038d7SDag-Erling Smørgrav /* flags */
2287b5038d7SDag-Erling Smørgrav ldns_rdf_print(fp, ldns_rr_rdf(key, 0)); fprintf(fp, " ");
2297b5038d7SDag-Erling Smørgrav /* proto */
2307b5038d7SDag-Erling Smørgrav ldns_rdf_print(fp, ldns_rr_rdf(key, 1)); fprintf(fp, " ");
2317b5038d7SDag-Erling Smørgrav /* algo */
2327b5038d7SDag-Erling Smørgrav ldns_rdf_print(fp, ldns_rr_rdf(key, 2));
2337b5038d7SDag-Erling Smørgrav
2347b5038d7SDag-Erling Smørgrav if (ldns_rdf2native_int16(ldns_rr_rdf(key, 0)) == 256) {
2357b5038d7SDag-Erling Smørgrav fprintf(fp, " ;{id = %u (zsk), size = %db}", (unsigned int)ldns_calc_keytag(key),
2367b5038d7SDag-Erling Smørgrav (int)ldns_rr_dnskey_key_size(key));
2377b5038d7SDag-Erling Smørgrav return;
2387b5038d7SDag-Erling Smørgrav }
2397b5038d7SDag-Erling Smørgrav if (ldns_rdf2native_int16(ldns_rr_rdf(key, 0)) == 257) {
2407b5038d7SDag-Erling Smørgrav fprintf(fp, " ;{id = %u (ksk), size = %db}", (unsigned int)ldns_calc_keytag(key),
2417b5038d7SDag-Erling Smørgrav (int)ldns_rr_dnskey_key_size(key));
2427b5038d7SDag-Erling Smørgrav return;
2437b5038d7SDag-Erling Smørgrav }
2447b5038d7SDag-Erling Smørgrav fprintf(fp, " ;{id = %u, size = %db}", (unsigned int)ldns_calc_keytag(key),
2457b5038d7SDag-Erling Smørgrav (int)ldns_rr_dnskey_key_size(key));
2467b5038d7SDag-Erling Smørgrav }
2477b5038d7SDag-Erling Smørgrav
2487b5038d7SDag-Erling Smørgrav void
print_rr_list_abbr(FILE * fp,ldns_rr_list * rrlist,const char * usr)2497b5038d7SDag-Erling Smørgrav print_rr_list_abbr(FILE *fp, ldns_rr_list *rrlist, const char *usr)
2507b5038d7SDag-Erling Smørgrav {
2517b5038d7SDag-Erling Smørgrav size_t i;
2527b5038d7SDag-Erling Smørgrav ldns_rr_type tp;
2537b5038d7SDag-Erling Smørgrav
2547b5038d7SDag-Erling Smørgrav for(i = 0; i < ldns_rr_list_rr_count(rrlist); i++) {
2557b5038d7SDag-Erling Smørgrav tp = ldns_rr_get_type(ldns_rr_list_rr(rrlist, i));
2567b5038d7SDag-Erling Smørgrav if (i == 0 && tp != LDNS_RR_TYPE_RRSIG) {
2577b5038d7SDag-Erling Smørgrav if (usr) {
2587b5038d7SDag-Erling Smørgrav fprintf(fp, "%s ", usr);
2597b5038d7SDag-Erling Smørgrav }
2607b5038d7SDag-Erling Smørgrav }
2617b5038d7SDag-Erling Smørgrav switch(tp) {
2627b5038d7SDag-Erling Smørgrav case LDNS_RR_TYPE_DNSKEY:
2637b5038d7SDag-Erling Smørgrav print_dnskey_abbr(fp, ldns_rr_list_rr(rrlist, i));
2647b5038d7SDag-Erling Smørgrav break;
2657b5038d7SDag-Erling Smørgrav case LDNS_RR_TYPE_RRSIG:
2667b5038d7SDag-Erling Smørgrav print_rrsig_abbr(fp, ldns_rr_list_rr(rrlist, i));
2677b5038d7SDag-Erling Smørgrav break;
2687b5038d7SDag-Erling Smørgrav case LDNS_RR_TYPE_DS:
2697b5038d7SDag-Erling Smørgrav print_ds_abbr(fp, ldns_rr_list_rr(rrlist, i));
2707b5038d7SDag-Erling Smørgrav break;
2717b5038d7SDag-Erling Smørgrav default:
2727b5038d7SDag-Erling Smørgrav /* not handled */
2737b5038d7SDag-Erling Smørgrav break;
2747b5038d7SDag-Erling Smørgrav }
2757b5038d7SDag-Erling Smørgrav fputs("\n", fp);
2767b5038d7SDag-Erling Smørgrav }
2777b5038d7SDag-Erling Smørgrav }
2787b5038d7SDag-Erling Smørgrav
2797b5038d7SDag-Erling Smørgrav void *
xmalloc(size_t s)2807b5038d7SDag-Erling Smørgrav xmalloc(size_t s)
2817b5038d7SDag-Erling Smørgrav {
2827b5038d7SDag-Erling Smørgrav void *p;
2837b5038d7SDag-Erling Smørgrav
2847b5038d7SDag-Erling Smørgrav p = malloc(s);
2857b5038d7SDag-Erling Smørgrav if (!p) {
2867b5038d7SDag-Erling Smørgrav printf("Mem failure\n");
2877b5038d7SDag-Erling Smørgrav exit(EXIT_FAILURE);
2887b5038d7SDag-Erling Smørgrav }
2897b5038d7SDag-Erling Smørgrav return p;
2907b5038d7SDag-Erling Smørgrav }
2917b5038d7SDag-Erling Smørgrav
2927b5038d7SDag-Erling Smørgrav void *
xrealloc(void * p,size_t size)2937b5038d7SDag-Erling Smørgrav xrealloc(void *p, size_t size)
2947b5038d7SDag-Erling Smørgrav {
2957b5038d7SDag-Erling Smørgrav void *q;
2967b5038d7SDag-Erling Smørgrav
2977b5038d7SDag-Erling Smørgrav q = realloc(p, size);
2987b5038d7SDag-Erling Smørgrav if (!q) {
2997b5038d7SDag-Erling Smørgrav printf("Mem failure\n");
3007b5038d7SDag-Erling Smørgrav exit(EXIT_FAILURE);
3017b5038d7SDag-Erling Smørgrav }
3027b5038d7SDag-Erling Smørgrav return q;
3037b5038d7SDag-Erling Smørgrav }
3047b5038d7SDag-Erling Smørgrav
3057b5038d7SDag-Erling Smørgrav void
xfree(void * p)3067b5038d7SDag-Erling Smørgrav xfree(void *p)
3077b5038d7SDag-Erling Smørgrav {
3087b5038d7SDag-Erling Smørgrav if (p) {
3097b5038d7SDag-Erling Smørgrav free(p);
3107b5038d7SDag-Erling Smørgrav }
3117b5038d7SDag-Erling Smørgrav }
312