services_mkdb.c revision 1.8 1 /* $NetBSD: services_mkdb.c,v 1.8 2007/05/13 17:43:59 christos Exp $ */
2
3 /*-
4 * Copyright (c) 1999 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Luke Mewburn and Christos Zoulas.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 #include <sys/cdefs.h>
40 #ifndef lint
41 __RCSID("$NetBSD: services_mkdb.c,v 1.8 2007/05/13 17:43:59 christos Exp $");
42 #endif /* not lint */
43
44
45 #include <sys/param.h>
46
47 #include <db.h>
48 #include <err.h>
49 #include <fcntl.h>
50 #include <netdb.h>
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <string.h>
54 #include <unistd.h>
55 #include <util.h>
56 #include <ctype.h>
57 #include <stringlist.h>
58
59 static char tname[MAXPATHLEN];
60
61 static void cleanup(void);
62 static void store(const char *, size_t, DB *, DBT *, DBT *, int);
63 static void killproto(DBT *);
64 static char *getstring(const char *, size_t, char **, const char *);
65 static void usage(void) __attribute__((__noreturn__));
66
67 static const HASHINFO hinfo = {
68 .bsize = 256,
69 .ffactor = 4,
70 .nelem = 32768,
71 .cachesize = 1024,
72 .hash = NULL,
73 .lorder = 0
74 };
75
76
77 int
78 main(int argc, char *argv[])
79 {
80 DB *db;
81 FILE *fp;
82 int ch;
83 size_t len, line, cnt;
84 char keyb[BUFSIZ], datab[BUFSIZ], *p;
85 DBT data, key;
86 const char *fname = _PATH_SERVICES;
87 const char *dbname = _PATH_SERVICES_DB;
88 int warndup = 1;
89
90 setprogname(argv[0]);
91
92 while ((ch = getopt(argc, argv, "qo:")) != -1)
93 switch (ch) {
94 case 'q':
95 warndup = 0;
96 break;
97 case 'o':
98 dbname = optarg;
99 break;
100 case '?':
101 default:
102 usage();
103 }
104
105 argc -= optind;
106 argv += optind;
107
108 if (argc > 1)
109 usage();
110 if (argc == 1)
111 fname = argv[0];
112
113 if ((fp = fopen(fname, "r")) == NULL)
114 err(1, "Cannot open `%s'", fname);
115
116 if (atexit(cleanup))
117 err(1, "Cannot install exit handler");
118
119 (void)snprintf(tname, sizeof(tname), "%s.tmp", dbname);
120 db = dbopen(tname, O_RDWR | O_CREAT | O_EXCL,
121 (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH), DB_HASH, &hinfo);
122 if (!db)
123 err(1, "Error opening temporary database `%s'", tname);
124
125 key.data = keyb;
126 data.data = datab;
127
128 cnt = line = 0;
129 /* XXX: change NULL to "\0\0#" when fparseln fixed */
130 for (; (p = fparseln(fp, &len, &line, NULL, 0)) != NULL; free(p)) {
131 char *name, *port, *proto, *aliases, *cp, *alias;
132 StringList *sl;
133 size_t i;
134
135 if (len == 0)
136 continue;
137 for (cp = p; *cp && isspace((unsigned char)*cp); cp++)
138 continue;
139 if (*cp == '\0' || *cp == '#')
140 continue;
141
142 if ((name = getstring(fname, line, &cp, "name")) == NULL)
143 continue;
144
145 if ((port = getstring(fname, line, &cp, "port")) == NULL)
146 continue;
147
148 proto = strchr(port, '/');
149 if (proto == NULL || proto[1] == '\0') {
150 warnx("%s, %zu: no protocol found", fname, line);
151 continue;
152 }
153 *proto++ = '\0';
154
155 for (aliases = cp; cp && isspace((unsigned char)*aliases);
156 aliases++)
157 continue;
158
159 /* key `indirect key', data `full line' */
160 data.size = snprintf(datab, sizeof(datab), "%zu", cnt++) + 1;
161 key.size = snprintf(keyb, sizeof(keyb), "%s %s/%s %s",
162 name, port, proto, aliases ? aliases : "") + 1;
163 store(fname, line, db, &data, &key, warndup);
164
165 /* key `\377port/proto', data = `indirect key' */
166 key.size = snprintf(keyb, sizeof(keyb), "\377%s/%s",
167 port, proto) + 1;
168 store(fname, line, db, &key, &data, warndup);
169
170 /* key `\377port', data = `indirect key' */
171 killproto(&key);
172 store(fname, line, db, &key, &data, 0);
173
174 /* build list of aliases */
175 sl = sl_init();
176 (void)sl_add(sl, name);
177 while ((alias = strsep(&cp, " \t")) != NULL) {
178 if (alias[0] == '\0')
179 continue;
180 (void)sl_add(sl, alias);
181 }
182
183 /* add references for service and all aliases */
184 for (i = 0; i < sl->sl_cur; i++) {
185 /* key `\376service/proto', data = `indirect key' */
186 key.size = snprintf(keyb, sizeof(keyb), "\376%s/%s",
187 sl->sl_str[i], proto) + 1;
188 store(fname, line, db, &key, &data, warndup);
189
190 /* key `\376service', data = `indirect key' */
191 killproto(&key);
192 store(fname, line, db, &key, &data, 0);
193 }
194 sl_free(sl, 0);
195 }
196
197 if ((db->close)(db))
198 err(1, "Error closing temporary database `%s'", tname);
199
200 if (rename(tname, dbname) == -1)
201 err(1, "Cannot rename `%s' to `%s'", tname, dbname);
202
203 return 0;
204 }
205
206 /*
207 * cleanup(): Remove temporary files upon exit
208 */
209 static void
210 cleanup(void)
211 {
212 if (tname[0])
213 (void)unlink(tname);
214 }
215
216 static char *
217 getstring(const char *fname, size_t line, char **cp, const char *tag)
218 {
219 char *str;
220
221 while ((str = strsep(cp, " \t")) != NULL && *str == '\0')
222 continue;
223
224 if (str == NULL)
225 warnx("%s, %zu: no %s found", fname, line, tag);
226
227 return str;
228 }
229
230 static void
231 killproto(DBT *key)
232 {
233 char *p, *d = key->data;
234
235 if ((p = strchr(d, '/')) == NULL)
236 abort();
237 *p++ = '\0';
238 key->size = p - d;
239 }
240
241 static void
242 store(const char *fname, size_t line, DB *db, DBT *key, DBT *data, int warndup)
243 {
244 switch ((db->put)(db, key, data, R_NOOVERWRITE)) {
245 case 0:
246 break;
247 case 1:
248 if (warndup)
249 warnx("%s, %zu: duplicate service `%s'",
250 fname, line, &((char *)key->data)[1]);
251 break;
252 case -1:
253 err(1, "put");
254 break;
255 default:
256 abort();
257 break;
258 }
259 }
260
261 static void
262 usage(void)
263 {
264 (void)fprintf(stderr, "Usage: %s [-q] [-o <db>] [<servicefile>]\n",
265 getprogname());
266 exit(1);
267 }
268