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