]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - usr.sbin/services_mkdb/services_mkdb.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / usr.sbin / services_mkdb / services_mkdb.c
1 /*      $NetBSD: services_mkdb.c,v 1.14 2008/04/28 20:24:17 martin 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  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34
35 #include <sys/param.h>
36 #include <sys/stat.h>
37
38 #include <assert.h>
39 #include <db.h>
40 #include <err.h>
41 #include <fcntl.h>
42 #include <netdb.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <unistd.h>
47 #include <libutil.h>
48 #include <ctype.h>
49 #include <errno.h>
50 #include <stringlist.h>
51
52 #include "extern.h"
53
54 static char tname[MAXPATHLEN];
55
56 #define PMASK           0xffff
57 #define PROTOMAX        5
58
59 static void     add(DB *, StringList *, size_t, const char *, size_t *, int);
60 static StringList ***parseservices(const char *, StringList *);
61 static void     cleanup(void);
62 static void     store(DB *, DBT *, DBT *, int);
63 static void     killproto(DBT *);
64 static char    *getstring(const char *, size_t, char **, const char *);
65 static size_t   getprotoindex(StringList *, const char *);
66 static const char *getprotostr(StringList *, size_t);
67 static const char *mkaliases(StringList *, char *, size_t);
68 static void     usage(void);
69
70 HASHINFO hinfo = {
71         .bsize = 256,
72         .ffactor = 4,
73         .nelem = 32768,
74         .cachesize = 1024,
75         .hash = NULL,
76         .lorder = 0
77 };
78
79
80 int
81 main(int argc, char *argv[])
82 {
83         DB      *db;
84         int      ch;
85         const char *fname = _PATH_SERVICES;
86         const char *dbname = _PATH_SERVICES_DB;
87         int      warndup = 1;
88         int      unique = 0;
89         int      otherflag = 0;
90         int      byteorder = 0;
91         size_t   cnt = 0;
92         StringList *sl, ***svc;
93         size_t port, proto;
94
95         setprogname(argv[0]);
96
97         while ((ch = getopt(argc, argv, "blo:qu")) != -1)
98                 switch (ch) {
99                 case 'b':
100                 case 'l':
101                         if (byteorder != 0)
102                                 usage();
103                         byteorder = ch == 'b' ? 4321 : 1234;
104                         break;
105                 case 'q':
106                         otherflag = 1;
107                         warndup = 0;
108                         break;
109                 case 'o':
110                         otherflag = 1;
111                         dbname = optarg;
112                         break;
113                 case 'u':
114                         unique++;
115                         break;
116                 case '?':
117                 default:
118                         usage();
119                 }
120
121         argc -= optind;
122         argv += optind;
123
124         if (argc > 1 || (unique && otherflag))
125                 usage();
126         if (argc == 1)
127                 fname = argv[0];
128
129         /* Set byte order. */
130         hinfo.lorder = byteorder;
131
132         if (unique)
133                 uniq(fname);
134
135         svc = parseservices(fname, sl = sl_init());
136
137         if (atexit(cleanup))
138                 err(1, "Cannot install exit handler");
139
140         (void)snprintf(tname, sizeof(tname), "%s.tmp", dbname);
141         db = dbopen(tname, O_RDWR | O_CREAT | O_EXCL,
142             (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH), DB_HASH, &hinfo);
143         if (!db)
144                 err(1, "Error opening temporary database `%s'", tname);
145
146
147         for (port = 0; port < PMASK + 1; port++) {
148                 if (svc[port] == NULL)
149                         continue;
150
151                 for (proto = 0; proto < PROTOMAX; proto++) {
152                         StringList *s;
153                         if ((s = svc[port][proto]) == NULL)
154                                 continue;
155                         add(db, s, port, getprotostr(sl, proto), &cnt, warndup);
156                 }
157
158                 free(svc[port]);
159         }
160
161         free(svc);
162         sl_free(sl, 1);
163
164         if ((db->close)(db))
165                 err(1, "Error closing temporary database `%s'", tname);
166
167         if (rename(tname, dbname) == -1)
168                 err(1, "Cannot rename `%s' to `%s'", tname, dbname);
169
170         return 0;
171 }
172
173 static void
174 add(DB *db, StringList *sl, size_t port, const char *proto, size_t *cnt,
175     int warndup)
176 {
177         size_t i;
178         char     keyb[BUFSIZ], datab[BUFSIZ], abuf[BUFSIZ];
179         DBT      data, key;
180         key.data = keyb;
181         data.data = datab;
182
183 #ifdef DEBUG
184         (void)printf("add %s %zu %s [ ", sl->sl_str[0], port, proto);
185         for (i = 1; i < sl->sl_cur; i++)
186             (void)printf("%s ", sl->sl_str[i]);
187         (void)printf("]\n");
188 #endif
189
190         /* key `indirect key', data `full line' */
191         data.size = snprintf(datab, sizeof(datab), "%zu", (*cnt)++) + 1;
192         key.size = snprintf(keyb, sizeof(keyb), "%s %zu/%s %s",
193             sl->sl_str[0], port, proto, mkaliases(sl, abuf, sizeof(abuf))) + 1;
194         store(db, &data, &key, warndup);
195
196         /* key `\377port/proto', data = `indirect key' */
197         key.size = snprintf(keyb, sizeof(keyb), "\377%zu/%s",
198             port, proto) + 1;
199         store(db, &key, &data, warndup);
200
201         /* key `\377port', data = `indirect key' */
202         killproto(&key);
203         store(db, &key, &data, warndup);
204
205         /* add references for service and all aliases */
206         for (i = 0; i < sl->sl_cur; i++) {
207                 /* key `\376service/proto', data = `indirect key' */
208                 key.size = snprintf(keyb, sizeof(keyb), "\376%s/%s",
209                     sl->sl_str[i], proto) + 1;
210                 store(db, &key, &data, warndup);
211
212                 /* key `\376service', data = `indirect key' */
213                 killproto(&key);
214                 store(db, &key, &data, warndup);
215         }
216         sl_free(sl, 1);
217 }
218
219 static StringList ***
220 parseservices(const char *fname, StringList *sl)
221 {
222         size_t len, line, pindex;
223         FILE *fp;
224         StringList ***svc, *s;
225         char *p, *ep;
226
227         if ((fp = fopen(fname, "r")) == NULL)
228                 err(1, "Cannot open `%s'", fname);
229
230         line = 0;
231         if ((svc = calloc(PMASK + 1, sizeof(StringList **))) == NULL)
232                 err(1, "Cannot allocate %zu bytes", (size_t)(PMASK + 1));
233
234         /* XXX: change NULL to "\0\0#" when fparseln fixed */
235         for (; (p = fparseln(fp, &len, &line, NULL, 0)) != NULL; free(p)) {
236                 char    *name, *port, *proto, *aliases, *cp, *alias;
237                 unsigned long pnum;
238
239                 if (len == 0)
240                         continue;
241
242                 for (cp = p; *cp && isspace((unsigned char)*cp); cp++)
243                         continue;
244
245                 if (*cp == '\0' || *cp == '#')
246                         continue;
247
248                 if ((name = getstring(fname, line, &cp, "name")) == NULL)
249                         continue;
250
251                 if ((port = getstring(fname, line, &cp, "port")) == NULL)
252                         continue;
253
254                 if (cp) {
255                         for (aliases = cp; *cp && *cp != '#'; cp++)
256                                 continue;
257
258                         if (*cp)
259                                 *cp = '\0';
260                 } else
261                         aliases = NULL;
262
263                 proto = strchr(port, '/');
264                 if (proto == NULL || proto[1] == '\0') {
265                         warnx("%s, %zu: no protocol found", fname, line);
266                         continue;
267                 }
268                 *proto++ = '\0';
269
270                 errno = 0;
271                 pnum = strtoul(port, &ep, 0);
272                 if (*port == '\0' || *ep != '\0') {
273                         warnx("%s, %zu: invalid port `%s'", fname, line, port);
274                         continue;
275                 }
276                 if ((errno == ERANGE && pnum == ULONG_MAX) || pnum > PMASK) {
277                         warnx("%s, %zu: port too big `%s'", fname, line, port);
278                         continue;
279                 }
280
281                 if (svc[pnum] == NULL) {
282                         svc[pnum] = calloc(PROTOMAX, sizeof(StringList *));
283                         if (svc[pnum] == NULL)
284                                 err(1, "Cannot allocate %zu bytes",
285                                     (size_t)PROTOMAX);
286                 }
287
288                 pindex = getprotoindex(sl, proto);
289                 if (svc[pnum][pindex] == NULL)
290                         s = svc[pnum][pindex] = sl_init();
291                 else
292                         s = svc[pnum][pindex];
293
294                 /* build list of aliases */
295                 if (sl_find(s, name) == NULL) {
296                         char *p2;
297
298                         if ((p2 = strdup(name)) == NULL)
299                                 err(1, "Cannot copy string");
300                         (void)sl_add(s, p2);
301                 }
302
303                 if (aliases) {
304                         while ((alias = strsep(&aliases, " \t")) != NULL) {
305                                 if (alias[0] == '\0')
306                                         continue;
307                                 if (sl_find(s, alias) == NULL) {
308                                         char *p2;
309
310                                         if ((p2 = strdup(alias)) == NULL)
311                                                 err(1, "Cannot copy string");
312                                         (void)sl_add(s, p2);
313                                 }
314                         }
315                 }
316         }
317         (void)fclose(fp);
318         return svc;
319 }
320
321 /*
322  * cleanup(): Remove temporary files upon exit
323  */
324 static void
325 cleanup(void)
326 {
327         if (tname[0])
328                 (void)unlink(tname);
329 }
330
331 static char *
332 getstring(const char *fname, size_t line, char **cp, const char *tag)
333 {
334         char *str;
335
336         while ((str = strsep(cp, " \t")) != NULL && *str == '\0')
337                 continue;
338
339         if (str == NULL)
340                 warnx("%s, %zu: no %s found", fname, line, tag);
341
342         return str;
343 }
344
345 static void
346 killproto(DBT *key)
347 {
348         char *p, *d = key->data;
349
350         if ((p = strchr(d, '/')) == NULL)
351                 abort();
352         *p++ = '\0';
353         key->size = p - d;
354 }
355
356 static void
357 store(DB *db, DBT *key, DBT *data, int warndup)
358 {
359 #ifdef DEBUG
360         int k = key->size - 1;
361         int d = data->size - 1;
362         (void)printf("store [%*.*s] [%*.*s]\n",
363                 k, k, (char *)key->data + 1,
364                 d, d, (char *)data->data + 1);
365 #endif
366         switch ((db->put)(db, key, data, R_NOOVERWRITE)) {
367         case 0:
368                 break;
369         case 1:
370                 if (warndup)
371                         warnx("duplicate service `%s'",
372                             &((char *)key->data)[1]);
373                 break;
374         case -1:
375                 err(1, "put");
376                 break;
377         default:
378                 abort();
379                 break;
380         }
381 }
382
383 static size_t
384 getprotoindex(StringList *sl, const char *str)
385 {
386         size_t i;
387         char *p;
388
389         for (i= 0; i < sl->sl_cur; i++)
390                 if (strcmp(sl->sl_str[i], str) == 0)
391                         return i;
392
393         if (i == PROTOMAX)
394                 errx(1, "Ran out of protocols adding `%s';"
395                     " recompile with larger PROTOMAX", str);
396         if ((p = strdup(str)) == NULL)
397                 err(1, "Cannot copy string");
398         (void)sl_add(sl, p);
399         return i;
400 }
401
402 static const char *
403 getprotostr(StringList *sl, size_t i)
404 {
405         assert(i < sl->sl_cur);
406         return sl->sl_str[i];
407 }
408
409 static const char *
410 mkaliases(StringList *sl, char *buf, size_t len)
411 {
412         size_t nc, i, pos;
413
414         buf[0] = 0;
415         for (i = 1, pos = 0; i < sl->sl_cur; i++) {
416                 nc = strlcpy(buf + pos, sl->sl_str[i], len);
417                 if (nc >= len)
418                         goto out;
419                 pos += nc;
420                 len -= nc;
421                 nc = strlcpy(buf + pos, " ", len);
422                 if (nc >= len)
423                         goto out;
424                 pos += nc;
425                 len -= nc;
426         }
427         return buf;
428 out:
429         warn("aliases for `%s' truncated", sl->sl_str[0]);
430         return buf;
431 }
432
433 static void
434 usage(void)
435 {
436         (void)fprintf(stderr,
437             "Usage:\t%s [-b | -l] [-q] [-o <db>] [<servicefile>]\n"
438             "\t%s -u [<servicefile>]\n", getprogname(), getprogname());
439         exit(1);
440 }