No empty .Rs/.Re
[netbsd-mini2440.git] / usr.sbin / netgroup_mkdb / netgroup_mkdb.c
blob78417c534cd97183248abf89667622ed5b650178
1 /* $NetBSD: netgroup_mkdb.c,v 1.17 2009/04/18 05:09:15 lukem Exp $ */
3 /*
4 * Copyright (c) 1994 Christos Zoulas
5 * All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
17 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
28 #include <sys/cdefs.h>
29 #ifndef lint
30 __RCSID("$NetBSD: netgroup_mkdb.c,v 1.17 2009/04/18 05:09:15 lukem Exp $");
31 #endif
33 #include <sys/types.h>
34 #include <sys/param.h>
35 #include <sys/stat.h>
36 #include <stdlib.h>
37 #include <stddef.h>
38 #include <unistd.h>
39 #include <fcntl.h>
40 #include <db.h>
41 #include <err.h>
42 #include <errno.h>
43 #include <stdio.h>
44 #include <string.h>
45 #include <stringlist.h>
46 #define _NETGROUP_PRIVATE
47 #include <netgroup.h>
48 #include <assert.h>
50 #include "str.h"
51 #include "util.h"
53 #define DEBUG_NG
55 #define NEW(a) (a *) emalloc(sizeof(a))
57 struct nentry {
58 int n_type;
59 size_t n_size; /* Buffer size required for printing */
60 union {
61 char *_name;
62 struct netgroup *_group;
63 } _n;
64 #define n_name _n._name
65 #define n_group _n._group
66 struct nentry *n_next;
70 static void cleanup(void);
71 static DB *ng_insert(DB *, const char *);
72 static void ng_reventry(DB *, DB *, struct nentry *, char *,
73 size_t, StringList *);
74 static void ng_print(struct nentry *, struct string *);
75 static void ng_rprint(DB *, struct string *);
76 static DB *ng_reverse(DB *, size_t);
77 static DB *ng_load(const char *);
78 static void ng_write(DB *, DB *, int);
79 static void ng_rwrite(DB *, DB *, int);
80 static void usage(void) __dead;
82 #ifdef DEBUG_NG
83 static int debug = 0;
84 static void ng_dump(DB *);
85 static void ng_rdump(DB *);
86 #endif /* DEBUG_NG */
87 static int dups = 0;
90 static const char ng_empty[] = "";
91 #define NG_EMPTY(a) ((a) ? (a) : ng_empty)
93 static const char *dbname = _PATH_NETGROUP_DB;
95 int
96 main(int argc, char **argv)
98 DB *db, *ndb, *hdb, *udb;
99 int ch;
100 char buf[MAXPATHLEN];
101 const char *fname = _PATH_NETGROUP;
104 while ((ch = getopt(argc, argv, "dDo:")) != -1)
105 switch (ch) {
106 #ifdef DEBUG_NG
107 case 'd':
108 debug++;
109 break;
110 #endif
111 case 'o':
112 dbname = optarg;
113 break;
115 case 'D':
116 dups++;
117 break;
119 case '?':
120 default:
121 usage();
124 argc -= optind;
125 argv += optind;
127 if (argc == 1)
128 fname = *argv;
129 else if (argc > 1)
130 usage();
132 if (atexit(cleanup))
133 err(1, "Cannot install exit handler");
135 /* Read and parse the netgroup file */
136 ndb = ng_load(fname);
137 #ifdef DEBUG_NG
138 if (debug) {
139 (void)fprintf(stderr, "#### Database\n");
140 ng_dump(ndb);
142 #endif
144 /* Reverse the database by host */
145 hdb = ng_reverse(ndb, offsetof(struct netgroup, ng_host));
146 #ifdef DEBUG_NG
147 if (debug) {
148 (void)fprintf(stderr, "#### Reverse by host\n");
149 ng_rdump(hdb);
151 #endif
153 /* Reverse the database by user */
154 udb = ng_reverse(ndb, offsetof(struct netgroup, ng_user));
155 #ifdef DEBUG_NG
156 if (debug) {
157 (void)fprintf(stderr, "#### Reverse by user\n");
158 ng_rdump(udb);
160 #endif
162 (void)snprintf(buf, sizeof(buf), "%s.tmp", dbname);
164 db = dbopen(buf, O_RDWR | O_CREAT | O_EXCL,
165 (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH), DB_HASH, NULL);
166 if (!db)
167 err(1, "%s", buf);
169 ng_write(db, ndb, _NG_KEYBYNAME);
170 ng_rwrite(db, udb, _NG_KEYBYUSER);
171 ng_rwrite(db, hdb, _NG_KEYBYHOST);
173 if ((db->close)(db))
174 err(1, "Error closing database");
176 if (rename(buf, dbname) == -1)
177 err(1, "Cannot rename `%s' to `%s'", buf, dbname);
179 return 0;
184 * cleanup(): Remove temporary files upon exit
186 static void
187 cleanup(void)
189 char buf[MAXPATHLEN];
190 (void)snprintf(buf, sizeof(buf), "%s.tmp", dbname);
191 (void)unlink(buf);
197 * ng_load(): Load the netgroup database from a file
199 static DB *
200 ng_load(const char *fname)
202 FILE *fp;
203 DB *db;
204 char *buf;
205 size_t size;
206 struct nentry *tail, *head, *e;
207 char *p, *name;
208 struct netgroup *ng;
209 DBT data, key;
211 /* Open the netgroup file */
212 if ((fp = fopen(fname, "r")) == NULL)
213 err(1, "%s", fname);
215 db = dbopen(NULL, O_RDWR | O_CREAT | O_EXCL, 0, DB_HASH, NULL);
217 if (db == NULL)
218 err(1, "dbopen");
220 while ((buf = fparseln(fp, &size, NULL, NULL, 0)) != NULL) {
221 tail = head = NULL;
222 p = buf;
224 while (p != NULL) {
225 switch (_ng_parse(&p, &name, &ng)) {
226 case _NG_NONE:
227 /* done with this one */
228 p = NULL;
229 free(buf);
230 if (head == NULL)
231 break;
233 key.data = (u_char *)head->n_name;
234 key.size = strlen(head->n_name) + 1;
235 data.data = (u_char *)&head;
236 data.size = sizeof(head);
237 switch ((db->put)(db, &key, &data,
238 R_NOOVERWRITE)) {
239 case 0:
240 break;
242 case 1:
243 warnx("Duplicate entry netgroup `%s'",
244 head->n_name);
245 break;
247 case -1:
248 err(1, "put");
249 break;
251 default:
252 abort();
253 break;
255 break;
257 case _NG_NAME:
258 e = NEW(struct nentry);
259 e->n_type = _NG_NAME;
260 e->n_name = name;
261 e->n_next = NULL;
262 e->n_size = size;
263 if (tail == NULL)
264 head = tail = e;
265 else {
266 tail->n_next = e;
267 tail = e;
269 break;
271 case _NG_GROUP:
272 if (tail == NULL) {
273 char fmt[BUFSIZ];
274 _ng_print(fmt, sizeof(fmt), ng);
275 errx(1, "no netgroup key for %s", fmt);
277 else {
278 e = NEW(struct nentry);
279 e->n_type = _NG_GROUP;
280 e->n_group = ng;
281 e->n_next = NULL;
282 e->n_size = size;
283 tail->n_next = e;
284 tail = e;
286 break;
288 case _NG_ERROR:
289 errx(1, "Fatal error at `%s'", p);
290 break;
292 default:
293 abort();
294 break;
298 (void)fclose(fp);
299 return db;
304 * ng_insert(): Insert named key into the database, and return its associated
305 * string database
307 static DB *
308 ng_insert(DB *db, const char *name)
310 DB *xdb = NULL;
311 DBT key, data;
313 key.data = __UNCONST(name);
314 key.size = strlen(name) + 1;
316 switch ((db->get)(db, &key, &data, 0)) {
317 case 0:
318 (void)memcpy(&xdb, data.data, sizeof(xdb));
319 break;
321 case 1:
322 xdb = dbopen(NULL, O_RDWR | O_CREAT | O_EXCL, 0, DB_HASH, NULL);
323 if (xdb == NULL)
324 err(1, "dbopen");
326 data.data = (u_char *)&xdb;
327 data.size = sizeof(xdb);
328 switch ((db->put)(db, &key, &data, R_NOOVERWRITE)) {
329 case 0:
330 break;
332 case -1:
333 err(1, "db put `%s'", name);
334 break;
336 case 1:
337 default:
338 abort();
340 break;
342 case -1:
343 err(1, "db get `%s'", name);
344 break;
346 default:
347 abort();
348 break;
351 return xdb;
356 * ng_reventry(): Recursively add all the netgroups to the group entry.
358 static void
359 ng_reventry(DB *db, DB *udb, struct nentry *fe, char *name, size_t s,
360 StringList *ss)
362 DBT key, data;
363 struct nentry *e;
364 struct netgroup *ng;
365 char *p;
366 DB *xdb;
368 if (sl_find(ss, fe->n_name) != NULL) {
369 _ng_cycle(name, ss);
370 return;
372 sl_add(ss, fe->n_name);
374 for (e = fe->n_next; e != NULL; e = e->n_next)
375 switch (e->n_type) {
376 case _NG_GROUP:
377 if (!dups)
378 sl_delete(ss, fe->n_name, 0);
379 ng = e->n_group;
380 p = _ng_makekey(*((char **)(((char *) ng) + s)),
381 ng->ng_domain, e->n_size);
382 xdb = ng_insert(udb, p);
383 key.data = (u_char *)name;
384 key.size = strlen(name) + 1;
385 data.data = NULL;
386 data.size = 0;
387 switch ((xdb->put)(xdb, &key, &data, R_NOOVERWRITE)) {
388 case 0:
389 case 1:
390 break;
392 case -1:
393 err(1, "db put `%s'", name);
394 return;
396 default:
397 abort();
398 break;
400 free(p);
401 break;
403 case _NG_NAME:
404 key.data = (u_char *) e->n_name;
405 key.size = strlen(e->n_name) + 1;
406 switch ((db->get)(db, &key, &data, 0)) {
407 struct nentry *rfe;
408 case 0:
409 (void)memcpy(&rfe, data.data, sizeof(rfe));
410 ng_reventry(db, udb, rfe, name, s, ss);
411 break;
413 case 1:
414 break;
416 case -1:
417 err(1, "db get `%s'", e->n_name);
418 return;
420 default:
421 abort();
422 return;
424 break;
426 default:
427 abort();
428 break;
434 * ng_reverse(): Reverse the database
436 static DB *
437 ng_reverse(DB *db, size_t s)
439 int pos;
440 StringList *sl;
441 DBT key, data;
442 struct nentry *fe;
443 DB *udb = dbopen(NULL, O_RDWR | O_CREAT | O_EXCL, 0,
444 DB_HASH, NULL);
446 if (udb == NULL)
447 err(1, "dbopen");
449 for (pos = R_FIRST;; pos = R_NEXT)
450 switch ((db->seq)(db, &key, &data, pos)) {
451 case 0:
452 sl = sl_init();
453 (void)memcpy(&fe, data.data, sizeof(fe));
454 ng_reventry(db, udb, fe, (char *) key.data, s, sl);
455 sl_free(sl, 0);
456 break;
458 case 1:
459 return udb;
461 case -1:
462 err(1, "seq");
463 return udb;
466 return udb;
471 * ng_print(): Pretty print a netgroup entry
473 static void
474 ng_print(struct nentry *e, struct string *str)
476 char *ptr;
478 if (e->n_next == NULL) {
479 str_append(str, "", ' ');
480 return;
483 ptr = emalloc(e->n_size);
485 for (e = e->n_next; e != NULL; e = e->n_next) {
486 switch (e->n_type) {
487 case _NG_NAME:
488 (void)snprintf(ptr, e->n_size, "%s", e->n_name);
489 break;
491 case _NG_GROUP:
492 (void)snprintf(ptr, e->n_size, "(%s,%s,%s)",
493 NG_EMPTY(e->n_group->ng_host),
494 NG_EMPTY(e->n_group->ng_user),
495 NG_EMPTY(e->n_group->ng_domain));
496 break;
498 default:
499 errx(1, "Internal error: Bad netgroup type");
500 break;
502 str_append(str, ptr, ' ');
504 free(ptr);
509 * ng_rprint(): Pretty print all reverse netgroup mappings in the given entry
511 static void
512 ng_rprint(DB *db, struct string *str)
514 int pos;
515 DBT key, data;
517 for (pos = R_FIRST;; pos = R_NEXT)
518 switch ((db->seq)(db, &key, &data, pos)) {
519 case 0:
520 str_append(str, (char *)key.data, ',');
521 break;
523 case 1:
524 return;
526 default:
527 err(1, "seq");
528 break;
533 #ifdef DEBUG_NG
535 * ng_dump(): Pretty print all netgroups in the given database
537 static void
538 ng_dump(DB *db)
540 int pos;
541 DBT key, data;
542 struct nentry *e;
543 struct string buf;
545 for (pos = R_FIRST;; pos = R_NEXT)
546 switch ((db->seq)(db, &key, &data, pos)) {
547 case 0:
548 (void)memcpy(&e, data.data, sizeof(e));
549 str_init(&buf);
550 assert(e->n_type == _NG_NAME);
552 ng_print(e, &buf);
553 (void)fprintf(stderr, "%s\t%s\n", e->n_name,
554 buf.s_str ? buf.s_str : "");
555 str_free(&buf);
556 break;
558 case 1:
559 return;
561 default:
562 err(1, "seq");
563 return;
569 * ng_rdump(): Pretty print all reverse mappings in the given database
571 static void
572 ng_rdump(DB *db)
574 int pos;
575 DBT key, data;
576 DB *xdb;
577 struct string buf;
579 for (pos = R_FIRST;; pos = R_NEXT)
580 switch ((db->seq)(db, &key, &data, pos)) {
581 case 0:
582 (void)memcpy(&xdb, data.data, sizeof(xdb));
583 str_init(&buf);
584 ng_rprint(xdb, &buf);
585 (void)fprintf(stderr, "%s\t%s\n",
586 (char *)key.data, buf.s_str ? buf.s_str : "");
587 str_free(&buf);
588 break;
590 case 1:
591 return;
593 default:
594 err(1, "seq");
595 return;
598 #endif /* DEBUG_NG */
602 * ng_write(): Dump the database into a file.
604 static void
605 ng_write(DB *odb, DB *idb, int k)
607 int pos;
608 DBT key, data;
609 struct nentry *e;
610 struct string skey, sdata;
612 for (pos = R_FIRST;; pos = R_NEXT)
613 switch ((idb->seq)(idb, &key, &data, pos)) {
614 case 0:
615 memcpy(&e, data.data, sizeof(e));
616 str_init(&skey);
617 str_init(&sdata);
618 assert(e->n_type == _NG_NAME);
620 str_prepend(&skey, e->n_name, k);
621 ng_print(e, &sdata);
622 key.data = (u_char *) skey.s_str;
623 key.size = skey.s_len + 1;
624 data.data = (u_char *) sdata.s_str;
625 data.size = sdata.s_len + 1;
627 switch ((odb->put)(odb, &key, &data, R_NOOVERWRITE)) {
628 case 0:
629 break;
631 case -1:
632 err(1, "put");
633 break;
635 case 1:
636 default:
637 abort();
638 break;
641 str_free(&skey);
642 str_free(&sdata);
643 break;
645 case 1:
646 return;
648 default:
649 err(1, "seq");
650 return;
656 * ng_rwrite(): Write the database
658 static void
659 ng_rwrite(DB *odb, DB *idb, int k)
661 int pos;
662 DBT key, data;
663 DB *xdb;
664 struct string skey, sdata;
666 for (pos = R_FIRST;; pos = R_NEXT)
667 switch ((idb->seq)(idb, &key, &data, pos)) {
668 case 0:
669 memcpy(&xdb, data.data, sizeof(xdb));
670 str_init(&skey);
671 str_init(&sdata);
673 str_prepend(&skey, (char *) key.data, k);
674 ng_rprint(xdb, &sdata);
675 key.data = (u_char *) skey.s_str;
676 key.size = skey.s_len + 1;
677 data.data = (u_char *) sdata.s_str;
678 data.size = sdata.s_len + 1;
680 switch ((odb->put)(odb, &key, &data, R_NOOVERWRITE)) {
681 case 0:
682 break;
684 case -1:
685 err(1, "put");
686 break;
688 case 1:
689 default:
690 abort();
691 break;
694 str_free(&skey);
695 str_free(&sdata);
696 break;
698 case 1:
699 return;
701 default:
702 err(1, "seq");
703 return;
709 * usage(): Print usage message and exit
711 static void
712 usage(void)
715 (void)fprintf(stderr, "Usage: %s [-D] [-o db] [<file>]\n",
716 getprogname());
717 exit(1);