]>
git.saurik.com Git - apple/mdnsresponder.git/blob - ServiceRegistration/config-parse.c
1 /* -*- Mode: C; tab-width: 4; c-file-style: "bsd"; c-basic-offset: 4; fill-column: 108 -*-
3 * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
4 * Copyright (c) 2018 Apple Computer, Inc. All rights reserved.
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
20 //*************************************************************************************************************
22 // General purpose stupid little parser, currently used by dnssd-proxy for its configuration file
24 //*************************************************************************************************************
27 #include <stdio.h> // For printf()
28 #include <stdlib.h> // For malloc()
29 #include <string.h> // For strrchr(), strcmp()
30 #include <time.h> // For "struct tm" etc.
31 #include <signal.h> // For SIGINT, SIGTERM
33 #include <netdb.h> // For gethostbyname()
34 #include <sys/socket.h> // For AF_INET, AF_INET6, etc.
35 #include <net/if.h> // For IF_NAMESIZE
36 #include <netinet/in.h> // For INADDR_NONE
37 #include <netinet/tcp.h> // For SOL_TCP, TCP_NOTSENT_LOWAT
38 #include <arpa/inet.h> // For inet_addr()
44 #include "config-parse.h"
48 #define LogMsg(fmt, ...) fprintf(stderr, fmt "\n", ##__VA_ARGS__)
51 // Parse one line of a config file.
52 // A line consists of a verb followed by one or more hunks of text.
53 // We parse the verb first, then that tells us how many hunks of text to expect.
54 // Each hunk is space-delineated; the last hunk can contain spaces.
55 static bool config_parse_line(void *context
, const char *filename
, char *line
, int lineno
,
56 config_file_verb_t
*verbs
, int num_verbs
)
60 char *hunks
[MAXCFHUNKS
];
62 config_file_verb_t
*config_file_verb
= NULL
;
67 // Skip leading spaces.
68 while (*sp
&& (*sp
== ' ' || *sp
== '\t'))
71 // If this is a blank line with spaces on it or a comment line, we ignore it.
72 if (!*sp
|| *sp
== '#')
75 hunks
[num_hunks
++] = sp
;
77 while (*sp
&& (*sp
!= ' ' && *sp
!= '\t')) {
84 for (i
= 0; i
< num_verbs
; i
++) {
85 // If the verb name matches, or the verb name is NULL (meaning whatever doesn't
86 // match a preceding verb), we've found our verb.
87 if (verbs
[i
].name
== NULL
|| !strcmp(verbs
[i
].name
, hunks
[0])) {
88 config_file_verb
= &verbs
[i
];
92 if (config_file_verb
== NULL
) {
93 LogMsg("cfParseLine: unknown verb %s at line %d", hunks
[0], lineno
);
97 } while (*sp
&& num_hunks
< MAXCFHUNKS
&& config_file_verb
->max_hunks
> num_hunks
);
99 // If we didn't get the hunks we needed, bail.
100 if (config_file_verb
->min_hunks
> num_hunks
) {
101 LogMsg("config_file_parse_line: error: verb %s requires between %d and %d modifiers; %d given at line %d",
102 hunks
[0], config_file_verb
->min_hunks
, config_file_verb
->max_hunks
, num_hunks
, lineno
);
106 return config_file_verb
->handler(context
, filename
, hunks
, num_hunks
, lineno
);
109 // Parse a configuration file
110 bool config_parse(void *context
, const char *filename
, config_file_verb_t
*verbs
, int num_verbs
)
113 char *buf
, *line
, *eof
, *eol
, *nextCR
, *nextNL
;
119 file
= open(filename
, O_RDONLY
);
121 LogMsg("cfParse: fatal: %s: %s", filename
, strerror(errno
));
125 // Get the length of the file.
126 flen
= lseek(file
, 0, SEEK_END
);
127 lseek(file
, 0, SEEK_SET
);
128 buf
= malloc(flen
+ 1);
130 LogMsg("cfParse: fatal: not enough memory for %s", filename
);
134 // Just in case we have a read() syscall that doesn't always read the whole file at once
136 while (have
< flen
) {
137 len
= read(file
, &buf
[have
], flen
- have
);
139 LogMsg("cfParse: fatal: read of %s at %lld len %lld: %s",
140 filename
, (long long)have
, (long long)(flen
- have
), strerror(errno
));
144 LogMsg("cfParse: fatal: read of %s at %lld len %lld: zero bytes read",
145 filename
, (long long)have
, (long long)(flen
- have
));
155 buf
[flen
] = 0; // NUL terminate.
158 // Parse through the file line by line.
161 while (line
< eof
) { // < because NUL at eof could be last eol.
162 nextCR
= strchr(line
, '\r');
163 nextNL
= strchr(line
, '\n');
165 // Added complexity for CR/LF agnostic line endings. Necessary?
166 if (nextNL
!= NULL
) {
167 if (nextCR
!= NULL
&& nextCR
< nextNL
)
178 // If this isn't a blank line or a comment line, parse it.
179 if (eol
- line
!= 1 && line
[0] != '#') {
181 // If we get a bad config line, we're going to return failure later, but continue parsing now.
182 if (!config_parse_line(context
, filename
, line
, lineno
, verbs
, num_verbs
))