services_mkdb.c revision 1.6 1 /* $NetBSD: services_mkdb.c,v 1.6 2007/05/08 20:14: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.6 2007/05/08 20:14: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 int
68 main(int argc, char *argv[])
69 {
70 DB *db;
71 FILE *fp;
72 int ch;
73 size_t len, line, cnt;
74 char keyb[BUFSIZ], datab[BUFSIZ], *p;
75 DBT data, key;
76 const char *fname = _PATH_SERVICES;
77 const char *dbname = _PATH_SERVICES_DB;
78 int warndup = 1;
79
80 setprogname(argv[0]);
81
82 while ((ch = getopt(argc, argv, "qo:")) != -1)
83 switch (ch) {
84 case 'q':
85 warndup = 0;
86 break;
87 case 'o':
88 dbname = optarg;
89 break;
90 case '?':
91 default:
92 usage();
93 }
94
95 argc -= optind;
96 argv += optind;
97
98 if (argc > 1)
99 usage();
100 if (argc == 1)
101 fname = argv[0];
102
103 if ((fp = fopen(fname, "r")) == NULL)
104 err(1, "Cannot open `%s'", fname);
105
106 if (atexit(cleanup))
107 err(1, "Cannot install exit handler");
108
109 (void)snprintf(tname, sizeof(tname), "%s.tmp", dbname);
110 db = dbopen(tname, O_RDWR | O_CREAT | O_EXCL,
111 (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH), DB_HASH, NULL);
112 if (!db)
113 err(1, "Error opening temporary database `%s'", tname);
114
115 key.data = keyb;
116 data.data = datab;
117
118 cnt = line = 0;
119 /* XXX: change NULL to "\0\0#" when fparseln fixed */
120 for (; (p = fparseln(fp, &len, &line, NULL, 0)) != NULL; free(p)) {
121 char *name, *port, *proto, *aliases, *cp, *alias;
122 StringList *sl;
123 size_t i;
124
125 if (len == 0)
126 continue;
127 cp = p;
128
129 if ((name = getstring(fname, line, &cp, "name")) == NULL)
130 continue;
131
132 if ((port = getstring(fname, line, &cp, "port")) == NULL)
133 continue;
134
135 proto = strchr(port, '/');
136 if (proto == NULL || proto[1] == '\0') {
137 warnx("%s, %zu: no protocol found", fname, line);
138 continue;
139 }
140 *proto++ = '\0';
141
142 for (aliases = cp; cp && isspace((unsigned char)*aliases);
143 aliases++)
144 continue;
145
146 /* key `indirect key', data `full line' */
147 data.size = snprintf(datab, sizeof(datab), "%zu", cnt++) + 1;
148 key.size = snprintf(keyb, sizeof(keyb), "%s %s/%s %s",
149 name, port, proto, aliases ? aliases : "") + 1;
150 store(fname, line, db, &data, &key, warndup);
151
152 /* key `\377port/proto', data = `indirect key' */
153 key.size = snprintf(keyb, sizeof(keyb), "\377%s/%s",
154 port, proto) + 1;
155 store(fname, line, db, &key, &data, warndup);
156
157 /* key `\377port', data = `indirect key' */
158 killproto(&key);
159 store(fname, line, db, &key, &data, 0);
160
161 /* build list of aliases */
162 sl = sl_init();
163 (void)sl_add(sl, name);
164 while ((alias = strsep(&cp, " \t")) != NULL) {
165 if (alias[0] == '\0')
166 continue;
167 (void)sl_add(sl, alias);
168 }
169
170 /* add references for service and all aliases */
171 for (i = 0; i < sl->sl_cur; i++) {
172 /* key `\376service/proto', data = `indirect key' */
173 key.size = snprintf(keyb, sizeof(keyb), "\376%s/%s",
174 sl->sl_str[i], proto) + 1;
175 store(fname, line, db, &key, &data, 1);
176
177 /* key `\376service', data = `indirect key' */
178 killproto(&key);
179 store(fname, line, db, &key, &data, 0);
180 }
181 sl_free(sl, 0);
182 }
183
184 if ((db->close)(db))
185 err(1, "Error closing temporary database `%s'", tname);
186
187 if (rename(tname, dbname) == -1)
188 err(1, "Cannot rename `%s' to `%s'", tname, dbname);
189
190 return 0;
191 }
192
193 /*
194 * cleanup(): Remove temporary files upon exit
195 */
196 static void
197 cleanup(void)
198 {
199 if (tname[0])
200 (void)unlink(tname);
201 }
202
203 static char *
204 getstring(const char *fname, size_t line, char **cp, const char *tag)
205 {
206 char *str;
207
208 while ((str = strsep(cp, " \t")) != NULL && *str == '\0')
209 continue;
210
211 if (str == NULL)
212 warnx("%s, %zu: no %s found", fname, line, tag);
213
214 return str;
215 }
216
217 static void
218 killproto(DBT *key)
219 {
220 char *p, *d = key->data;
221
222 if ((p = strchr(d, '/')) == NULL)
223 abort();
224 *p++ = '\0';
225 key->size = p - d;
226 }
227
228 static void
229 store(const char *fname, size_t line, DB *db, DBT *key, DBT *data, int warndup)
230 {
231 switch ((db->put)(db, key, data, R_NOOVERWRITE)) {
232 case 0:
233 break;
234 case 1:
235 if (warndup)
236 warnx("%s, %zu: duplicate service `%s'",
237 fname, line, &((char *)key->data)[1]);
238 break;
239 case -1:
240 err(1, "put");
241 break;
242 default:
243 abort();
244 break;
245 }
246 }
247
248 static void
249 usage(void)
250 {
251 (void)fprintf(stderr, "Usage: %s [-q] [-o <db>] [<servicefile>]\n",
252 getprogname());
253 exit(1);
254 }
255