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