1 /************************************************************************
2 Copyright 1988, 1991 by Carnegie Mellon University
6 Permission to use, copy, modify, and distribute this software and its
7 documentation for any purpose and without fee is hereby granted, provided
8 that the above copyright notice appear in all copies and that both that
9 copyright notice and this permission notice appear in supporting
10 documentation, and that the name of Carnegie Mellon University not be used
11 in advertising or publicity pertaining to distribution of the software
12 without specific, written prior permission.
14 CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
15 SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
16 IN NO EVENT SHALL CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
17 DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
18 PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
19 ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
22 $FreeBSD: src/libexec/bootpd/readfile.c,v 1.6.2.2 2001/10/14 21:25:02 iedowse Exp $
24 ************************************************************************/
27 * bootpd configuration file reading code.
29 * The routines in this file deal with reading, interpreting, and storing
30 * the information found in the bootpd configuration file (usually
35 #include <sys/errno.h>
36 #include <sys/types.h>
40 #include <netinet/in.h>
51 /* Yes, memcpy is OK here (no overlapped copies). */
52 #define bcopy(a,b,c) memcpy(b,a,c)
53 #define bzero(p,l) memset(p,0,l)
54 #define bcmp(a,b,c) memcmp(a,b,c)
66 #define HASHTABLESIZE 257 /* Hash table size (prime) */
68 /* Non-standard hardware address type (see bootp.h) */
69 #define HTYPE_DIRECT 0
71 /* Error codes returned by eval_symbol: */
73 #define E_END_OF_ENTRY (-1)
74 #define E_SYNTAX_ERROR (-2)
75 #define E_UNKNOWN_SYMBOL (-3)
76 #define E_BAD_IPADDR (-4)
77 #define E_BAD_HWADDR (-5)
78 #define E_BAD_LONGWORD (-6)
79 #define E_BAD_HWATYPE (-7)
80 #define E_BAD_PATHNAME (-8)
81 #define E_BAD_VALUE (-9)
85 #define SYM_BOOTFILE 1
86 #define SYM_COOKIE_SERVER 2
87 #define SYM_DOMAIN_SERVER 3
92 #define SYM_IMPRESS_SERVER 8
94 #define SYM_LOG_SERVER 10
95 #define SYM_LPR_SERVER 11
96 #define SYM_NAME_SERVER 12
97 #define SYM_RLP_SERVER 13
98 #define SYM_SUBNET_MASK 14
99 #define SYM_TIME_OFFSET 15
100 #define SYM_TIME_SERVER 16
101 #define SYM_VENDOR_MAGIC 17
102 #define SYM_SIMILAR_ENTRY 18
103 #define SYM_NAME_SWITCH 19
104 #define SYM_BOOTSIZE 20
105 #define SYM_BOOT_SERVER 22
106 #define SYM_TFTPDIR 23
107 #define SYM_DUMP_FILE 24
108 #define SYM_DOMAIN_NAME 25
109 #define SYM_SWAP_SERVER 26
110 #define SYM_ROOT_PATH 27
111 #define SYM_EXTEN_FILE 28
112 #define SYM_REPLY_ADDR 29
113 #define SYM_NIS_DOMAIN 30 /* RFC 1533 */
114 #define SYM_NIS_SERVER 31 /* RFC 1533 */
115 #define SYM_NTP_SERVER 32 /* RFC 1533 */
116 #define SYM_EXEC_FILE 33 /* YORK_EX_OPTION */
117 #define SYM_MSG_SIZE 34
118 #define SYM_MIN_WAIT 35
119 /* XXX - Add new tags here */
121 #define OP_ADDITION 1 /* Operations on tags */
122 #define OP_DELETION 2
125 #define MAXINADDRS 16 /* Max size of an IP address list */
126 #define MAXBUFLEN 256 /* Max temp buffer space */
127 #define MAXENTRYLEN 2048 /* Max size of an entire entry */
132 * Structure used to map a configuration-file symbol (such as "ds") to a
148 PRIVATE
int nhosts
; /* Number of hosts (/w hw or IP address) */
149 PRIVATE
int nentries
; /* Total number of entries */
150 PRIVATE int32 modtime
= 0; /* Last modification time of bootptab */
151 PRIVATE
char *current_hostname
; /* Name of the current entry. */
152 PRIVATE
char current_tagname
[8];
155 * List of symbolic names used in the bootptab file. The order and actual
156 * values of the symbol codes (SYM_. . .) are unimportant, but they must
160 PRIVATE
struct symbolmap symbol_list
[] = {
161 {"bf", SYM_BOOTFILE
},
162 {"bs", SYM_BOOTSIZE
},
163 {"cs", SYM_COOKIE_SERVER
},
164 {"df", SYM_DUMP_FILE
},
165 {"dn", SYM_DOMAIN_NAME
},
166 {"ds", SYM_DOMAIN_SERVER
},
167 {"ef", SYM_EXTEN_FILE
},
168 {"ex", SYM_EXEC_FILE
}, /* YORK_EX_OPTION */
172 {"hn", SYM_NAME_SWITCH
},
174 {"im", SYM_IMPRESS_SERVER
},
176 {"lg", SYM_LOG_SERVER
},
177 {"lp", SYM_LPR_SERVER
},
178 {"ms", SYM_MSG_SIZE
},
179 {"mw", SYM_MIN_WAIT
},
180 {"ns", SYM_NAME_SERVER
},
181 {"nt", SYM_NTP_SERVER
},
182 {"ra", SYM_REPLY_ADDR
},
183 {"rl", SYM_RLP_SERVER
},
184 {"rp", SYM_ROOT_PATH
},
185 {"sa", SYM_BOOT_SERVER
},
186 {"sm", SYM_SUBNET_MASK
},
187 {"sw", SYM_SWAP_SERVER
},
188 {"tc", SYM_SIMILAR_ENTRY
},
190 {"to", SYM_TIME_OFFSET
},
191 {"ts", SYM_TIME_SERVER
},
192 {"vm", SYM_VENDOR_MAGIC
},
193 {"yd", SYM_NIS_DOMAIN
},
194 {"ys", SYM_NIS_SERVER
},
195 /* XXX - Add new tags here */
200 * List of symbolic names for hardware types. Name translates into
201 * hardware type code listed with it. Names must begin with a letter
202 * and must be all lowercase. This is searched linearly, so put
203 * commonly-used entries near the beginning.
206 PRIVATE
struct htypename htnamemap
[] = {
207 {"ethernet", HTYPE_ETHERNET
},
208 {"ethernet3", HTYPE_EXP_ETHERNET
},
209 {"ether", HTYPE_ETHERNET
},
210 {"ether3", HTYPE_EXP_ETHERNET
},
211 {"ieee802", HTYPE_IEEE802
},
212 {"tr", HTYPE_IEEE802
},
213 {"token-ring", HTYPE_IEEE802
},
214 {"pronet", HTYPE_PRONET
},
215 {"chaos", HTYPE_CHAOS
},
216 {"arcnet", HTYPE_ARCNET
},
217 {"ax.25", HTYPE_AX25
},
218 {"direct", HTYPE_DIRECT
},
219 {"serial", HTYPE_DIRECT
},
220 {"slip", HTYPE_DIRECT
},
221 {"ppp", HTYPE_DIRECT
}
227 * Externals and forward declarations.
230 extern boolean
iplookcmp();
231 boolean
nmcmp(hash_datum
*, hash_datum
*);
236 del_string(struct shared_string
*);
238 del_bindata(struct shared_bindata
*);
240 del_iplist(struct in_addr_list
*);
242 eat_whitespace(char **);
244 eval_symbol(char **, struct host
*);
246 fill_defaults(struct host
*, char **);
248 free_host(hash_datum
*);
249 PRIVATE
struct in_addr_list
*
250 get_addresses(char **);
251 PRIVATE
struct shared_string
*
252 get_shared_string(char **);
254 get_string(char **, char *, u_int
*);
260 hwinscmp(hash_datum
*, hash_datum
*);
262 interp_byte(char **, byte
*);
266 nullcmp(hash_datum
*, hash_datum
*);
268 process_entry(struct host
*, char *);
270 process_generic(char **, struct shared_bindata
**, u_int
);
272 prs_haddr(char **, u_int
);
274 prs_inetaddr(char **, u_int32
*);
276 read_entry(FILE *, char *, u_int
*);
282 * Vendor magic cookies for CMU and RFC1048
284 u_char vm_cmu
[4] = VM_CMU
;
285 u_char vm_rfc1048
[4] = VM_RFC1048
;
290 hash_tbl
*hwhashtable
;
291 hash_tbl
*iphashtable
;
292 hash_tbl
*nmhashtable
;
295 * Allocate hash tables for hardware address, ip address, and hostname
296 * (shared by bootpd and bootpef)
301 hwhashtable
= hash_Init(HASHTABLESIZE
);
302 iphashtable
= hash_Init(HASHTABLESIZE
);
303 nmhashtable
= hash_Init(HASHTABLESIZE
);
304 if (!(hwhashtable
&& iphashtable
&& nmhashtable
)) {
305 report(LOG_ERR
, "Unable to allocate hash tables.");
312 * Read bootptab database file. Avoid rereading the file if the
313 * write date hasn't changed since the last time we read it.
322 unsigned hashcode
, buflen
;
323 static char buffer
[MAXENTRYLEN
];
326 * Check the last modification time.
328 if (stat(bootptab
, &st
) < 0) {
329 report(LOG_ERR
, "stat on \"%s\": %s",
330 bootptab
, get_errmsg());
336 strcpy(timestr
, ctime(&(st
.st_mtime
)));
337 /* zap the newline */
339 report(LOG_INFO
, "bootptab mtime: %s",
344 (st
.st_mtime
== modtime
) &&
347 * hasn't been modified or deleted yet.
352 report(LOG_INFO
, "reading %s\"%s\"",
353 (modtime
!= 0L) ? "new " : "",
357 * Open bootptab file.
359 if ((fp
= fopen(bootptab
, "r")) == NULL
) {
360 report(LOG_ERR
, "error opening \"%s\": %s", bootptab
, get_errmsg());
364 * Record file modification time.
366 if (fstat(fileno(fp
), &st
) < 0) {
367 report(LOG_ERR
, "fstat: %s", get_errmsg());
371 modtime
= st
.st_mtime
;
374 * Entirely erase all hash tables.
376 hash_Reset(hwhashtable
, free_host
);
377 hash_Reset(iphashtable
, free_host
);
378 hash_Reset(nmhashtable
, free_host
);
383 buflen
= sizeof(buffer
);
384 read_entry(fp
, buffer
, &buflen
);
385 if (buflen
== 0) { /* More entries? */
388 hp
= (struct host
*) smalloc(sizeof(struct host
));
389 bzero((char *) hp
, sizeof(*hp
));
390 /* the link count it zero */
393 * Get individual info
395 if (process_entry(hp
, buffer
) < 0) {
397 free_host((hash_datum
*) hp
);
401 * If this is not a dummy entry, and the IP or HW
402 * address is not yet set, try to get them here.
403 * Dummy entries have . as first char of name.
405 if (goodname(hp
->hostname
->string
)) {
406 char *hn
= hp
->hostname
->string
;
408 if (hp
->flags
.iaddr
== 0) {
409 if (lookup_ipa(hn
, &value
)) {
410 report(LOG_ERR
, "can not get IP addr for %s", hn
);
411 report(LOG_ERR
, "(dummy names should start with '.')");
413 hp
->iaddr
.s_addr
= value
;
414 hp
->flags
.iaddr
= TRUE
;
417 /* Set default subnet mask. */
418 if (hp
->flags
.subnet_mask
== 0) {
419 if (lookup_netmask(hp
->iaddr
.s_addr
, &value
)) {
420 report(LOG_ERR
, "can not get netmask for %s", hn
);
422 hp
->subnet_mask
.s_addr
= value
;
423 hp
->flags
.subnet_mask
= TRUE
;
427 if (hp
->flags
.iaddr
) {
430 /* Register by HW addr if known. */
431 if (hp
->flags
.htype
&& hp
->flags
.haddr
) {
432 /* We will either insert it or free it. */
434 hashcode
= hash_HashFunction(hp
->haddr
, haddrlength(hp
->htype
));
435 if (hash_Insert(hwhashtable
, hashcode
, hwinscmp
, hp
, hp
) < 0) {
436 report(LOG_NOTICE
, "duplicate %s address: %s",
438 haddrtoa(hp
->haddr
, haddrlength(hp
->htype
)));
439 free_host((hash_datum
*) hp
);
443 /* Register by IP addr if known. */
444 if (hp
->flags
.iaddr
) {
445 hashcode
= hash_HashFunction((u_char
*) & (hp
->iaddr
.s_addr
), 4);
446 if (hash_Insert(iphashtable
, hashcode
, nullcmp
, hp
, hp
) < 0) {
448 "hash_Insert() failed on IP address insertion");
450 /* Just inserted the host struct in a new hash list. */
454 /* Register by Name (always known) */
455 hashcode
= hash_HashFunction((u_char
*) hp
->hostname
->string
,
456 strlen(hp
->hostname
->string
));
457 if (hash_Insert(nmhashtable
, hashcode
, nullcmp
,
458 hp
->hostname
->string
, hp
) < 0) {
460 "hash_Insert() failed on insertion of hostname: \"%s\"",
461 hp
->hostname
->string
);
463 /* Just inserted the host struct in a new hash list. */
472 report(LOG_INFO
, "read %d entries (%d hosts) from \"%s\"",
473 nentries
, nhosts
, bootptab
);
480 * Read an entire host entry from the file pointed to by "fp" and insert it
481 * into the memory pointed to by "buffer". Leading whitespace and comments
482 * starting with "#" are ignored (removed). Backslashes (\) always quote
483 * the next character except that newlines preceded by a backslash cause
484 * line-continuation onto the next line. The entry is terminated by a
485 * newline character which is not preceded by a backslash. Sequences
486 * surrounded by double quotes are taken literally (including newlines, but
489 * The "bufsiz" parameter points to an unsigned int which specifies the
490 * maximum permitted buffer size. Upon return, this value will be replaced
491 * with the actual length of the entry (not including the null terminator).
493 * This code is a little scary. . . . I don't like using gotos in C
494 * either, but I first wrote this as an FSM diagram and gotos seemed like
495 * the easiest way to implement it. Maybe later I'll clean it up.
499 read_entry(FILE *fp
, char *buffer
, unsigned *bufsiz
)
506 * Eat whitespace, blank lines, and comment lines.
511 goto done
; /* Exit if end-of-file */
514 goto top
; /* Skip over whitespace */
517 while (TRUE
) { /* Eat comments after # */
520 goto done
; /* Exit if end-of-file */
523 goto top
; /* Try to read the next line */
527 ungetc(c
, fp
); /* Other character, push it back to reprocess it */
531 * Now we're actually reading a data entry. Get each character and
532 * assemble it into the data buffer, processing special characters like
533 * double quotes (") and backslashes (\).
541 goto done
; /* Exit on EOF or newline */
543 c
= fgetc(fp
); /* Backslash, read a new character */
545 goto done
; /* Exit on EOF */
547 *buffer
++ = c
; /* Store the literal character */
549 if (length
< *bufsiz
- 1) {
555 *buffer
++ = '"'; /* Store double-quote */
557 if (length
>= *bufsiz
- 1) {
560 while (TRUE
) { /* Special quote processing loop */
564 goto done
; /* Exit on EOF . . . */
566 *buffer
++ = '"';/* Store matching quote */
568 if (length
< *bufsiz
- 1) {
569 goto mainloop
; /* And continue main loop */
574 if ((c
= fgetc(fp
)) < 0) { /* Backslash */
575 goto done
; /* EOF. . . .*/
576 } /* else fall through */
578 *buffer
++ = c
; /* Other character, store it */
580 if (length
>= *bufsiz
- 1) {
586 *buffer
++ = c
; /* Store colons */
588 if (length
>= *bufsiz
- 1) {
591 do { /* But remove whitespace after them */
593 if ((c
< 0) || (c
== '\n')) {
596 } while (isspace(c
)); /* Skip whitespace */
598 if (c
== '\\') { /* Backslash quotes next character */
604 goto top
; /* Backslash-newline continuation */
607 /* fall through if "other" character */
609 *buffer
++ = c
; /* Store other characters */
611 if (length
>= *bufsiz
- 1) {
615 goto mainloop
; /* Keep going */
618 *buffer
= '\0'; /* Terminate string */
619 *bufsiz
= length
; /* Tell the caller its length */
625 * Parse out all the various tags and parameters in the host entry pointed
626 * to by "src". Stuff all the data into the appropriate fields of the
627 * host structure pointed to by "host". If there is any problem with the
628 * entry, an error message is reported via report(), no further processing
629 * is done, and -1 is returned. Successful calls return 0.
631 * (Some errors probably shouldn't be so completely fatal. . . .)
635 process_entry(struct host
*host
, char *src
)
640 if (!host
|| *src
== '\0') {
643 host
->hostname
= get_shared_string(&src
);
645 /* Be more liberal for the benefit of dummy tag names. */
646 if (!goodname(host
->hostname
->string
)) {
647 report(LOG_ERR
, "bad hostname: \"%s\"", host
->hostname
->string
);
648 del_string(host
->hostname
);
652 current_hostname
= host
->hostname
->string
;
655 retval
= eval_symbol(&src
, host
);
656 if (retval
== SUCCESS
) {
660 if (retval
== E_END_OF_ENTRY
) {
661 /* The default subnet mask is set in readtab() */
664 /* Some kind of error. */
669 case E_UNKNOWN_SYMBOL
:
670 msg
= "unknown symbol";
673 msg
= "bad INET address";
676 msg
= "bad hardware address";
679 msg
= "bad longword value";
682 msg
= "bad HW address type";
685 msg
= "bad pathname (need leading '/')";
691 msg
= "unknown error";
694 report(LOG_ERR
, "in entry named \"%s\", symbol \"%s\": %s",
695 current_hostname
, current_tagname
, msg
);
702 * Macros for use in the function below:
705 /* Parse one INET address stored directly in MEMBER. */
706 #define PARSE_IA1(MEMBER) do \
708 if (optype == OP_BOOLEAN) \
709 return E_SYNTAX_ERROR; \
710 hp->flags.MEMBER = FALSE; \
711 if (optype == OP_ADDITION) { \
712 if (prs_inetaddr(symbol, &value) < 0) \
713 return E_BAD_IPADDR; \
714 hp->MEMBER.s_addr = value; \
715 hp->flags.MEMBER = TRUE; \
719 /* Parse a list of INET addresses pointed to by MEMBER */
720 #define PARSE_IAL(MEMBER) do \
722 if (optype == OP_BOOLEAN) \
723 return E_SYNTAX_ERROR; \
724 if (hp->flags.MEMBER) { \
725 hp->flags.MEMBER = FALSE; \
726 assert(hp->MEMBER); \
727 del_iplist(hp->MEMBER); \
730 if (optype == OP_ADDITION) { \
731 hp->MEMBER = get_addresses(symbol); \
732 if (hp->MEMBER == NULL) \
733 return E_SYNTAX_ERROR; \
734 hp->flags.MEMBER = TRUE; \
738 /* Parse a shared string pointed to by MEMBER */
739 #define PARSE_STR(MEMBER) do \
741 if (optype == OP_BOOLEAN) \
742 return E_SYNTAX_ERROR; \
743 if (hp->flags.MEMBER) { \
744 hp->flags.MEMBER = FALSE; \
745 assert(hp->MEMBER); \
746 del_string(hp->MEMBER); \
749 if (optype == OP_ADDITION) { \
750 hp->MEMBER = get_shared_string(symbol); \
751 if (hp->MEMBER == NULL) \
752 return E_SYNTAX_ERROR; \
753 hp->flags.MEMBER = TRUE; \
757 /* Parse an unsigned integer value for MEMBER */
758 #define PARSE_UINT(MEMBER) do \
760 if (optype == OP_BOOLEAN) \
761 return E_SYNTAX_ERROR; \
762 hp->flags.MEMBER = FALSE; \
763 if (optype == OP_ADDITION) { \
764 value = get_u_long(symbol); \
765 hp->MEMBER = value; \
766 hp->flags.MEMBER = TRUE; \
771 * Evaluate the two-character tag symbol pointed to by "symbol" and place
772 * the data in the structure pointed to by "hp". The pointer pointed to
773 * by "symbol" is updated to point past the source string (but may not
774 * point to the next tag entry).
776 * Obviously, this need a few more comments. . . .
779 eval_symbol(char **symbol
, struct host
*hp
)
781 char tmpstr
[MAXSTRINGLEN
];
783 struct symbolmap
*symbolptr
;
788 int optype
; /* Indicates boolean, addition, or deletion */
790 eat_whitespace(symbol
);
792 /* Make sure this is set before returning. */
793 current_tagname
[0] = (*symbol
)[0];
794 current_tagname
[1] = (*symbol
)[1];
795 current_tagname
[2] = 0;
797 if ((*symbol
)[0] == '\0') {
798 return E_END_OF_ENTRY
;
800 if ((*symbol
)[0] == ':') {
803 if ((*symbol
)[0] == 'T') { /* generic symbol */
805 value
= get_u_long(symbol
);
806 snprintf(current_tagname
, sizeof(current_tagname
),
808 eat_whitespace(symbol
);
809 if ((*symbol
)[0] != '=') {
810 return E_SYNTAX_ERROR
;
813 if (!(hp
->generic
)) {
814 hp
->generic
= (struct shared_bindata
*)
815 smalloc(sizeof(struct shared_bindata
));
817 if (process_generic(symbol
, &(hp
->generic
), (byte
) (value
& 0xFF)))
818 return E_SYNTAX_ERROR
;
819 hp
->flags
.generic
= TRUE
;
823 * Determine the type of operation to be done on this symbol
825 switch ((*symbol
)[2]) {
827 optype
= OP_ADDITION
;
830 optype
= OP_DELETION
;
837 return E_SYNTAX_ERROR
;
840 symbolptr
= symbol_list
;
841 numsymbols
= sizeof(symbol_list
) / sizeof(struct symbolmap
);
842 for (i
= 0; i
< numsymbols
; i
++) {
843 if (((symbolptr
->symbol
)[0] == (*symbol
)[0]) &&
844 ((symbolptr
->symbol
)[1] == (*symbol
)[1])) {
849 if (i
>= numsymbols
) {
850 return E_UNKNOWN_SYMBOL
;
853 * Skip past the = or @ character (to point to the data) if this
854 * isn't a boolean operation. For boolean operations, just skip
855 * over the two-character tag symbol (and nothing else. . . .).
857 (*symbol
) += (optype
== OP_BOOLEAN
) ? 2 : 3;
859 eat_whitespace(symbol
);
861 /* The cases below are in order by symbolcode value. */
862 switch (symbolptr
->symbolcode
) {
868 case SYM_COOKIE_SERVER
:
869 PARSE_IAL(cookie_server
);
872 case SYM_DOMAIN_SERVER
:
873 PARSE_IAL(domain_server
);
881 if (optype
== OP_BOOLEAN
)
882 return E_SYNTAX_ERROR
;
883 hp
->flags
.haddr
= FALSE
;
884 if (optype
== OP_ADDITION
) {
885 /* Default the HW type to Ethernet */
886 if (hp
->flags
.htype
== 0) {
887 hp
->flags
.htype
= TRUE
;
888 hp
->htype
= HTYPE_ETHERNET
;
890 tmphaddr
= prs_haddr(symbol
, hp
->htype
);
893 bcopy(tmphaddr
, hp
->haddr
, haddrlength(hp
->htype
));
894 hp
->flags
.haddr
= TRUE
;
903 if (optype
== OP_BOOLEAN
)
904 return E_SYNTAX_ERROR
;
905 hp
->flags
.htype
= FALSE
;
906 if (optype
== OP_ADDITION
) {
907 value
= 0L; /* Assume an illegal value */
908 eat_whitespace(symbol
);
909 if (isdigit(**symbol
)) {
910 value
= get_u_long(symbol
);
912 len
= sizeof(tmpstr
);
913 (void) get_string(symbol
, tmpstr
, &len
);
915 numsymbols
= sizeof(htnamemap
) /
916 sizeof(struct htypename
);
917 for (i
= 0; i
< numsymbols
; i
++) {
918 if (!strcmp(htnamemap
[i
].name
, tmpstr
)) {
922 if (i
< numsymbols
) {
923 value
= htnamemap
[i
].htype
;
926 if (value
>= hwinfocnt
) {
927 return E_BAD_HWATYPE
;
929 hp
->htype
= (byte
) (value
& 0xFF);
930 hp
->flags
.htype
= TRUE
;
934 case SYM_IMPRESS_SERVER
:
935 PARSE_IAL(impress_server
);
943 PARSE_IAL(log_server
);
947 PARSE_IAL(lpr_server
);
950 case SYM_NAME_SERVER
:
951 PARSE_IAL(name_server
);
955 PARSE_IAL(rlp_server
);
958 case SYM_SUBNET_MASK
:
959 PARSE_IA1(subnet_mask
);
962 case SYM_TIME_OFFSET
:
963 if (optype
== OP_BOOLEAN
)
964 return E_SYNTAX_ERROR
;
965 hp
->flags
.time_offset
= FALSE
;
966 if (optype
== OP_ADDITION
) {
967 len
= sizeof(tmpstr
);
968 (void) get_string(symbol
, tmpstr
, &len
);
969 if (!strncmp(tmpstr
, "auto", 4)) {
970 hp
->time_offset
= secondswest
;
972 if (sscanf(tmpstr
, "%d", (int*)&timeoff
) != 1)
973 return E_BAD_LONGWORD
;
974 hp
->time_offset
= timeoff
;
976 hp
->flags
.time_offset
= TRUE
;
980 case SYM_TIME_SERVER
:
981 PARSE_IAL(time_server
);
984 case SYM_VENDOR_MAGIC
:
985 if (optype
== OP_BOOLEAN
)
986 return E_SYNTAX_ERROR
;
987 hp
->flags
.vm_cookie
= FALSE
;
988 if (optype
== OP_ADDITION
) {
989 if (strncmp(*symbol
, "auto", 4)) {
990 /* The string is not "auto" */
991 if (!strncmp(*symbol
, "rfc", 3)) {
992 bcopy(vm_rfc1048
, hp
->vm_cookie
, 4);
993 } else if (!strncmp(*symbol
, "cmu", 3)) {
994 bcopy(vm_cmu
, hp
->vm_cookie
, 4);
996 if (!isdigit(**symbol
))
998 if (prs_inetaddr(symbol
, &value
) < 0)
1000 bcopy(&value
, hp
->vm_cookie
, 4);
1002 hp
->flags
.vm_cookie
= TRUE
;
1007 case SYM_SIMILAR_ENTRY
:
1010 fill_defaults(hp
, symbol
);
1013 return E_SYNTAX_ERROR
;
1017 case SYM_NAME_SWITCH
:
1020 return E_SYNTAX_ERROR
;
1022 hp
->flags
.send_name
= FALSE
;
1023 hp
->flags
.name_switch
= FALSE
;
1026 hp
->flags
.send_name
= TRUE
;
1027 hp
->flags
.name_switch
= TRUE
;
1035 if (!strncmp(*symbol
, "auto", 4)) {
1036 hp
->flags
.bootsize
= TRUE
;
1037 hp
->flags
.bootsize_auto
= TRUE
;
1039 hp
->bootsize
= (unsigned int) get_u_long(symbol
);
1040 hp
->flags
.bootsize
= TRUE
;
1041 hp
->flags
.bootsize_auto
= FALSE
;
1045 hp
->flags
.bootsize
= FALSE
;
1048 hp
->flags
.bootsize
= TRUE
;
1049 hp
->flags
.bootsize_auto
= TRUE
;
1054 case SYM_BOOT_SERVER
:
1055 PARSE_IA1(bootserver
);
1060 if ((hp
->tftpdir
!= NULL
) &&
1061 (hp
->tftpdir
->string
[0] != '/'))
1062 return E_BAD_PATHNAME
;
1066 PARSE_STR(dump_file
);
1069 case SYM_DOMAIN_NAME
:
1070 PARSE_STR(domain_name
);
1073 case SYM_SWAP_SERVER
:
1074 PARSE_IA1(swap_server
);
1078 PARSE_STR(root_path
);
1081 case SYM_EXTEN_FILE
:
1082 PARSE_STR(exten_file
);
1085 case SYM_REPLY_ADDR
:
1086 PARSE_IA1(reply_addr
);
1089 case SYM_NIS_DOMAIN
:
1090 PARSE_STR(nis_domain
);
1093 case SYM_NIS_SERVER
:
1094 PARSE_IAL(nis_server
);
1097 case SYM_NTP_SERVER
:
1098 PARSE_IAL(ntp_server
);
1101 #ifdef YORK_EX_OPTION
1103 PARSE_STR(exec_file
);
1108 PARSE_UINT(msg_size
);
1109 if (hp
->msg_size
< BP_MINPKTSZ
||
1110 hp
->msg_size
> MAX_MSG_SIZE
)
1115 PARSE_UINT(min_wait
);
1118 /* XXX - Add new tags here */
1121 return E_UNKNOWN_SYMBOL
;
1123 } /* switch symbolcode */
1135 * Read a string from the buffer indirectly pointed to through "src" and
1136 * move it into the buffer pointed to by "dest". A pointer to the maximum
1137 * allowable length of the string (including null-terminator) is passed as
1138 * "length". The actual length of the string which was read is returned in
1139 * the unsigned integer pointed to by "length". This value is the same as
1140 * that which would be returned by applying the strlen() function on the
1141 * destination string (i.e the terminating null is not counted as a
1142 * character). Trailing whitespace is removed from the string. For
1143 * convenience, the function returns the new value of "dest".
1145 * The string is read until the maximum number of characters, an unquoted
1146 * colon (:), or a null character is read. The return string in "dest" is
1151 get_string(char **src
, char *dest
, unsigned *length
)
1153 int n
, len
, quoteflag
;
1158 while ((n
< len
) && (**src
)) {
1159 if (!quoteflag
&& (**src
== ':')) {
1164 quoteflag
= !quoteflag
;
1167 if (**src
== '\\') {
1173 *dest
++ = *(*src
)++;
1178 * Remove that troublesome trailing whitespace. . .
1180 while ((n
> 0) && isspace(dest
[-1])) {
1193 * Read the string indirectly pointed to by "src", update the caller's
1194 * pointer, and return a pointer to a malloc'ed shared_string structure
1195 * containing the string.
1197 * The string is read using the same rules as get_string() above.
1200 PRIVATE
struct shared_string
*
1201 get_shared_string(char **src
)
1203 char retstring
[MAXSTRINGLEN
];
1204 struct shared_string
*s
;
1207 length
= sizeof(retstring
);
1208 (void) get_string(src
, retstring
, &length
);
1210 s
= (struct shared_string
*) smalloc(sizeof(struct shared_string
)
1213 strcpy(s
->string
, retstring
);
1221 * Load RFC1048 generic information directly into a memory buffer.
1223 * "src" indirectly points to the ASCII representation of the generic data.
1224 * "dest" points to a string structure which is updated to point to a new
1225 * string with the new data appended to the old string. The old string is
1228 * The given tag value is inserted with the new data.
1230 * The data may be represented as either a stream of hexadecimal numbers
1231 * representing bytes (any or all bytes may optionally start with '0x' and
1232 * be separated with periods ".") or as a quoted string of ASCII
1233 * characters (the quotes are required).
1237 process_generic(char **src
, struct shared_bindata
**dest
, u_int tagvalue
)
1239 byte tmpbuf
[MAXBUFLEN
];
1241 struct shared_bindata
*bdata
;
1242 u_int newlength
, oldlength
;
1245 *str
++ = (tagvalue
& 0xFF); /* Store tag value */
1246 str
++; /* Skip over length field */
1247 if ((*src
)[0] == '"') { /* ASCII data */
1248 newlength
= sizeof(tmpbuf
) - 2; /* Set maximum allowed length */
1249 (void) get_string(src
, (char *) str
, &newlength
);
1250 newlength
++; /* null terminator */
1251 } else { /* Numeric data */
1253 while (newlength
< sizeof(tmpbuf
) - 2) {
1254 if (interp_byte(src
, str
++) < 0)
1262 if ((*src
)[0] != ':')
1265 tmpbuf
[1] = (newlength
& 0xFF);
1266 oldlength
= ((*dest
)->length
);
1267 bdata
= (struct shared_bindata
*) smalloc(sizeof(struct shared_bindata
)
1268 + oldlength
+ newlength
+ 1);
1269 if (oldlength
> 0) {
1270 bcopy((*dest
)->data
, bdata
->data
, oldlength
);
1272 bcopy(tmpbuf
, bdata
->data
+ oldlength
, newlength
+ 2);
1273 bdata
->length
= oldlength
+ newlength
+ 2;
1274 bdata
->linkcount
= 1;
1285 * Verify that the given string makes sense as a hostname (according to
1286 * Appendix 1, page 29 of RFC882).
1288 * Return TRUE for good names, FALSE otherwise.
1292 goodname(char *hostname
)
1295 if (!isalpha(*hostname
++)) { /* First character must be a letter */
1298 while (isalnum(*hostname
) ||
1299 (*hostname
== '-') ||
1300 (*hostname
== '_') )
1302 hostname
++; /* Alphanumeric or a hyphen */
1304 if (!isalnum(hostname
[-1])) { /* Last must be alphanumeric */
1307 if (*hostname
== '\0') {/* Done? */
1310 } while (*hostname
++ == '.'); /* Dot, loop for next label */
1312 return FALSE
; /* If it's not a dot, lose */
1318 * Null compare function -- always returns FALSE so an element is always
1319 * inserted into a hash table (i.e. there is never a collision with an
1320 * existing element).
1324 nullcmp(hash_datum
*d1
, hash_datum
*d2
)
1331 * Function for comparing a string with the hostname field of a host
1336 nmcmp(hash_datum
*d1
, hash_datum
*d2
)
1338 char *name
= (char *) d1
; /* XXX - OK? */
1339 struct host
*hp
= (struct host
*) d2
;
1341 return !strcmp(name
, hp
->hostname
->string
);
1346 * Compare function to determine whether two hardware addresses are
1347 * equivalent. Returns TRUE if "host1" and "host2" are equivalent, FALSE
1350 * If the hardware addresses of "host1" and "host2" are identical, but
1351 * they are on different IP subnets, this function returns FALSE.
1353 * This function is used when inserting elements into the hardware address
1358 hwinscmp(hash_datum
*d1
, hash_datum
*d2
)
1360 struct host
*host1
= (struct host
*) d1
;
1361 struct host
*host2
= (struct host
*) d2
;
1363 if (host1
->htype
!= host2
->htype
) {
1366 if (bcmp(host1
->haddr
, host2
->haddr
, haddrlength(host1
->htype
))) {
1369 /* XXX - Is the subnet_mask field set yet? */
1370 if ((host1
->subnet_mask
.s_addr
) == (host2
->subnet_mask
.s_addr
)) {
1371 if (((host1
->iaddr
.s_addr
) & (host1
->subnet_mask
.s_addr
)) !=
1372 ((host2
->iaddr
.s_addr
) & (host2
->subnet_mask
.s_addr
)))
1382 * Macros for use in the function below:
1385 #define DUP_COPY(MEMBER) do \
1387 if (!hp->flags.MEMBER) { \
1388 if ((hp->flags.MEMBER = hp2->flags.MEMBER) != 0) { \
1389 hp->MEMBER = hp2->MEMBER; \
1394 #define DUP_LINK(MEMBER) do \
1396 if (!hp->flags.MEMBER) { \
1397 if ((hp->flags.MEMBER = hp2->flags.MEMBER) != 0) { \
1398 assert(hp2->MEMBER); \
1399 hp->MEMBER = hp2->MEMBER; \
1400 (hp->MEMBER->linkcount)++; \
1406 * Process the "similar entry" symbol.
1408 * The host specified as the value of the "tc" symbol is used as a template
1409 * for the current host entry. Symbol values not explicitly set in the
1410 * current host entry are inferred from the template entry.
1413 fill_defaults(struct host
*hp
, char **src
)
1415 unsigned int tlen
, hashcode
;
1417 char tstring
[MAXSTRINGLEN
];
1419 tlen
= sizeof(tstring
);
1420 (void) get_string(src
, tstring
, &tlen
);
1421 hashcode
= hash_HashFunction((u_char
*) tstring
, tlen
);
1422 hp2
= (struct host
*) hash_Lookup(nmhashtable
, hashcode
, nmcmp
, tstring
);
1425 report(LOG_ERR
, "can't find tc=\"%s\"", tstring
);
1429 DUP_LINK(cookie_server
);
1430 DUP_LINK(domain_server
);
1432 /* haddr not copied */
1436 DUP_LINK(impress_server
);
1437 /* iaddr not copied */
1438 DUP_LINK(log_server
);
1439 DUP_LINK(lpr_server
);
1440 DUP_LINK(name_server
);
1441 DUP_LINK(rlp_server
);
1443 DUP_COPY(subnet_mask
);
1444 DUP_COPY(time_offset
);
1445 DUP_LINK(time_server
);
1447 if (!hp
->flags
.vm_cookie
) {
1448 if ((hp
->flags
.vm_cookie
= hp2
->flags
.vm_cookie
)) {
1449 bcopy(hp2
->vm_cookie
, hp
->vm_cookie
, 4);
1452 if (!hp
->flags
.name_switch
) {
1453 if ((hp
->flags
.name_switch
= hp2
->flags
.name_switch
)) {
1454 hp
->flags
.send_name
= hp2
->flags
.send_name
;
1457 if (!hp
->flags
.bootsize
) {
1458 if ((hp
->flags
.bootsize
= hp2
->flags
.bootsize
)) {
1459 hp
->flags
.bootsize_auto
= hp2
->flags
.bootsize_auto
;
1460 hp
->bootsize
= hp2
->bootsize
;
1463 DUP_COPY(bootserver
);
1466 DUP_LINK(dump_file
);
1467 DUP_LINK(domain_name
);
1469 DUP_COPY(swap_server
);
1470 DUP_LINK(root_path
);
1471 DUP_LINK(exten_file
);
1473 DUP_COPY(reply_addr
);
1475 DUP_LINK(nis_domain
);
1476 DUP_LINK(nis_server
);
1477 DUP_LINK(ntp_server
);
1479 #ifdef YORK_EX_OPTION
1480 DUP_LINK(exec_file
);
1486 /* XXX - Add new tags here */
1497 * This function adjusts the caller's pointer to point just past the
1498 * first-encountered colon. If it runs into a null character, it leaves
1499 * the pointer pointing to it.
1508 while (*t
&& (*t
!= ':')) {
1521 * This function adjusts the caller's pointer to point to the first
1522 * non-whitespace character. If it runs into a null character, it leaves
1523 * the pointer pointing to it.
1527 eat_whitespace(char **s
)
1532 while (*t
&& isspace(*t
)) {
1541 * This function converts the given string to all lowercase.
1561 * In many of the functions which follow, a parameter such as "src" or
1562 * "symbol" is passed as a pointer to a pointer to something. This is
1563 * done for the purpose of letting the called function update the
1564 * caller's copy of the parameter (i.e. to effect call-by-reference
1565 * parameter passing). The value of the actual parameter is only used
1566 * to locate the real parameter of interest and then update this indirect
1569 * I'm sure somebody out there won't like this. . . .
1570 * (Yea, because it usually makes code slower... -gwr)
1577 * "src" points to a character pointer which points to an ASCII string of
1578 * whitespace-separated IP addresses. A pointer to an in_addr_list
1579 * structure containing the list of addresses is returned. NULL is
1580 * returned if no addresses were found at all. The pointer pointed to by
1581 * "src" is updated to point to the first non-address (illegal) character.
1584 PRIVATE
struct in_addr_list
*
1585 get_addresses(char **src
)
1587 struct in_addr tmpaddrlist
[MAXINADDRS
];
1588 struct in_addr
*address1
, *address2
;
1589 struct in_addr_list
*result
;
1590 unsigned addrcount
, totalsize
;
1592 address1
= tmpaddrlist
;
1593 for (addrcount
= 0; addrcount
< MAXINADDRS
; addrcount
++) {
1594 while (isspace(**src
) || (**src
== ',')) {
1597 if (!**src
) { /* Quit if nothing more */
1600 if (prs_inetaddr(src
, &(address1
->s_addr
)) < 0) {
1603 address1
++; /* Point to next address slot */
1605 if (addrcount
< 1) {
1608 totalsize
= sizeof(struct in_addr_list
)
1609 + (addrcount
- 1) * sizeof(struct in_addr
);
1610 result
= (struct in_addr_list
*) smalloc(totalsize
);
1611 result
->linkcount
= 1;
1612 result
->addrcount
= addrcount
;
1613 address1
= tmpaddrlist
;
1614 address2
= result
->addr
;
1615 for (; addrcount
> 0; addrcount
--) {
1616 address2
->s_addr
= address1
->s_addr
;
1627 * prs_inetaddr(src, result)
1629 * "src" is a value-result parameter; the pointer it points to is updated
1630 * to point to the next data position. "result" points to an unsigned long
1631 * in which an address is returned.
1633 * This function parses the IP address string in ASCII "dot notation" pointed
1634 * to by (*src) and places the result (in network byte order) in the unsigned
1635 * long pointed to by "result". For malformed addresses, -1 is returned,
1636 * (*src) points to the first illegal character, and the unsigned long pointed
1637 * to by "result" is unchanged. Successful calls return 0.
1641 prs_inetaddr(char **src
, u_int32
*result
)
1643 char tmpstr
[MAXSTRINGLEN
];
1645 u_int32 parts
[4], *pp
;
1649 /* Leading alpha char causes IP addr lookup. */
1650 if (isalpha(**src
)) {
1651 /* Lookup IP address. */
1654 while ((isalnum(*s
) || (*s
== '.') ||
1655 (*s
== '-') || (*s
== '_') ) &&
1656 (t
< &tmpstr
[MAXSTRINGLEN
- 1]) )
1661 n
= lookup_ipa(tmpstr
, result
);
1663 report(LOG_ERR
, "can not get IP addr for %s", tmpstr
);
1668 * Parse an address in Internet format:
1670 * a.b.c (with c treated as 16-bits)
1671 * a.b (with b treated as 24 bits)
1675 /* If it's not a digit, return error. */
1676 if (!isdigit(**src
))
1678 *pp
++ = get_u_long(src
);
1680 if (pp
< (parts
+ 4)) {
1687 /* This is handled by the caller. */
1688 if (**src
&& !(isspace(**src
) || (**src
== ':'))) {
1694 * Construct the address according to
1695 * the number of parts specified.
1699 case 1: /* a -- 32 bits */
1702 case 2: /* a.b -- 8.24 bits */
1703 value
= (parts
[0] << 24) | (parts
[1] & 0xFFFFFF);
1705 case 3: /* a.b.c -- 8.8.16 bits */
1706 value
= (parts
[0] << 24) | ((parts
[1] & 0xFF) << 16) |
1707 (parts
[2] & 0xFFFF);
1709 case 4: /* a.b.c.d -- 8.8.8.8 bits */
1710 value
= (parts
[0] << 24) | ((parts
[1] & 0xFF) << 16) |
1711 ((parts
[2] & 0xFF) << 8) | (parts
[3] & 0xFF);
1716 *result
= htonl(value
);
1723 * "src" points to a pointer which in turn points to a hexadecimal ASCII
1724 * string. This string is interpreted as a hardware address and returned
1725 * as a pointer to the actual hardware address, represented as an array of
1728 * The ASCII string must have the proper number of digits for the specified
1729 * hardware type (e.g. twelve digits for a 48-bit Ethernet address).
1730 * Two-digit sequences (bytes) may be separated with periods (.) and/or
1731 * prefixed with '0x' for readability, but this is not required.
1733 * For bad addresses, the pointer which "src" points to is updated to point
1734 * to the start of the first two-digit sequence which was bad, and the
1735 * function returns a NULL pointer.
1739 prs_haddr(char **src
, u_int htype
)
1741 static byte haddr
[MAXHADDRLEN
];
1743 char tmpstr
[MAXSTRINGLEN
];
1748 hal
= haddrlength(htype
); /* Get length of this address type */
1750 report(LOG_ERR
, "Invalid addr type for HW addr parse");
1753 tmplen
= sizeof(tmpstr
);
1754 get_string(src
, tmpstr
, &tmplen
);
1757 /* If it's a valid host name, try to lookup the HW address. */
1759 /* Lookup Hardware Address for hostname. */
1760 if ((hap
= lookup_hwa(p
, htype
)) != NULL
)
1761 return hap
; /* success */
1762 report(LOG_ERR
, "Add 0x prefix if hex value starts with A-F");
1763 /* OK, assume it must be numeric. */
1767 while (hap
< haddr
+ hal
) {
1768 if ((*p
== '.') || (*p
== ':'))
1770 if (interp_byte(&p
, hap
++) < 0) {
1780 * "src" is a pointer to a character pointer which in turn points to a
1781 * hexadecimal ASCII representation of a byte. This byte is read, the
1782 * character pointer is updated, and the result is deposited into the
1783 * byte pointed to by "retbyte".
1785 * The usual '0x' notation is allowed but not required. The number must be
1786 * a two digit hexadecimal number. If the number is invalid, "src" and
1787 * "retbyte" are left untouched and -1 is returned as the function value.
1788 * Successful calls return 0.
1792 interp_byte(char **src
, byte
*retbyte
)
1796 if ((*src
)[0] == '0' &&
1797 ((*src
)[1] == 'x' ||
1798 (*src
)[1] == 'X')) {
1799 (*src
) += 2; /* allow 0x for hex, but don't require it */
1801 if (!isxdigit((*src
)[0]) || !isxdigit((*src
)[1])) {
1804 if (sscanf(*src
, "%2x", &v
) != 1) {
1808 *retbyte
= (byte
) (v
& 0xFF);
1815 * The parameter "src" points to a character pointer which points to an
1816 * ASCII string representation of an unsigned number. The number is
1817 * returned as an unsigned long and the character pointer is updated to
1818 * point to the first illegal character.
1822 get_u_long(char **src
)
1824 u_int32 value
, base
;
1828 * Collect number up to first illegal character. Values are specified
1829 * as for C: 0x=hex, 0=octal, other=decimal.
1837 if (**src
== 'x' || **src
== 'X') {
1841 while ((c
= **src
)) {
1843 value
= (value
* base
) + (c
- '0');
1847 if (base
== 16 && isxdigit(c
)) {
1848 value
= (value
<< 4) + ((c
& ~32) + 10 - 'A');
1860 * Routines for deletion of data associated with the main data structure.
1865 * Frees the entire host data structure given. Does nothing if the passed
1870 free_host(hash_datum
*hmp
)
1872 struct host
*hostptr
= (struct host
*) hmp
;
1873 if (hostptr
== NULL
)
1875 assert(hostptr
->linkcount
> 0);
1876 if (--(hostptr
->linkcount
))
1877 return; /* Still has references */
1878 del_iplist(hostptr
->cookie_server
);
1879 del_iplist(hostptr
->domain_server
);
1880 del_iplist(hostptr
->gateway
);
1881 del_iplist(hostptr
->impress_server
);
1882 del_iplist(hostptr
->log_server
);
1883 del_iplist(hostptr
->lpr_server
);
1884 del_iplist(hostptr
->name_server
);
1885 del_iplist(hostptr
->rlp_server
);
1886 del_iplist(hostptr
->time_server
);
1887 del_iplist(hostptr
->nis_server
);
1888 del_iplist(hostptr
->ntp_server
);
1891 * XXX - Add new tags here
1892 * (if the value is an IP list)
1895 del_string(hostptr
->hostname
);
1896 del_string(hostptr
->homedir
);
1897 del_string(hostptr
->bootfile
);
1898 del_string(hostptr
->tftpdir
);
1899 del_string(hostptr
->root_path
);
1900 del_string(hostptr
->domain_name
);
1901 del_string(hostptr
->dump_file
);
1902 del_string(hostptr
->exten_file
);
1903 del_string(hostptr
->nis_domain
);
1905 #ifdef YORK_EX_OPTION
1906 del_string(hostptr
->exec_file
);
1910 * XXX - Add new tags here
1911 * (if it is a shared string)
1914 del_bindata(hostptr
->generic
);
1915 free((char *) hostptr
);
1921 * Decrements the linkcount on the given IP address data structure. If the
1922 * linkcount goes to zero, the memory associated with the data is freed.
1926 del_iplist(struct in_addr_list
*iplist
)
1929 if (!(--(iplist
->linkcount
))) {
1930 free((char *) iplist
);
1938 * Decrements the linkcount on a string data structure. If the count
1939 * goes to zero, the memory associated with the string is freed. Does
1940 * nothing if the passed pointer is NULL.
1944 del_string(struct shared_string
*stringptr
)
1947 if (!(--(stringptr
->linkcount
))) {
1948 free((char *) stringptr
);
1956 * Decrements the linkcount on a shared_bindata data structure. If the
1957 * count goes to zero, the memory associated with the data is freed. Does
1958 * nothing if the passed pointer is NULL.
1962 del_bindata(struct shared_bindata
*dataptr
)
1965 if (!(--(dataptr
->linkcount
))) {
1966 free((char *) dataptr
);
1974 /* smalloc() -- safe malloc()
1976 * Always returns a valid pointer (if it returns at all). The allocated
1977 * memory is initialized to all zeros. If malloc() returns an error, a
1978 * message is printed using the report() function and the program aborts
1979 * with a status of 1.
1983 smalloc(unsigned nbytes
)
1987 retvalue
= malloc(nbytes
);
1989 report(LOG_ERR
, "malloc() failure -- exiting");
1992 bzero(retvalue
, nbytes
);
1998 * Compare function to determine whether two hardware addresses are
1999 * equivalent. Returns TRUE if "host1" and "host2" are equivalent, FALSE
2002 * This function is used when retrieving elements from the hardware address
2007 hwlookcmp(hash_datum
*d1
, hash_datum
*d2
)
2009 struct host
*host1
= (struct host
*) d1
;
2010 struct host
*host2
= (struct host
*) d2
;
2012 if (host1
->htype
!= host2
->htype
) {
2015 if (bcmp(host1
->haddr
, host2
->haddr
, haddrlength(host1
->htype
))) {
2023 * Compare function for doing IP address hash table lookup.
2027 iplookcmp(hash_datum
*d1
, hash_datum
*d2
)
2029 struct host
*host1
= (struct host
*) d1
;
2030 struct host
*host2
= (struct host
*) d2
;
2032 return (host1
->iaddr
.s_addr
== host2
->iaddr
.s_addr
);