Sync usage with man page.
[netbsd-mini2440.git] / usr.sbin / ypserv / mknetid / mknetid.c
blobe82e2ed15291836651e5bb4f0ea78f3254ecf2b5
1 /* $NetBSD: mknetid.c,v 1.16 2009/04/19 06:06:40 lukem Exp $ */
3 /*
4 * Copyright (c) 1996 Mats O Jansson <moj@stacken.kth.se>
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.
29 #include <sys/cdefs.h>
30 #ifndef lint
31 __RCSID("$NetBSD: mknetid.c,v 1.16 2009/04/19 06:06:40 lukem Exp $");
32 #endif
35 * Originally written by Mats O Jansson <moj@stacken.kth.se>
36 * Simplified a bit by Jason R. Thorpe <thorpej@NetBSD.org>
39 #include <sys/param.h>
40 #include <sys/queue.h>
41 #include <ctype.h>
42 #include <err.h>
43 #include <grp.h>
44 #include <limits.h>
45 #include <netdb.h>
46 #include <pwd.h>
47 #include <stdio.h>
48 #include <string.h>
49 #include <stdlib.h>
50 #include <unistd.h>
52 #include <rpcsvc/ypclnt.h>
54 #include "protos.h"
56 struct user {
57 char *usr_name; /* user name */
58 int usr_uid; /* user uid */
59 int usr_gid; /* user gid */
60 int gid_count; /* number of gids */
61 int gid[NGROUPS]; /* additional gids */
62 TAILQ_ENTRY(user) read; /* links in read order */
63 TAILQ_ENTRY(user) hash; /* links in hash order */
66 #define HASHMAX 55
68 void add_group(const char *, const char *);
69 void add_user(const char *, const char *, const char *);
70 int hashidx(char);
71 int isgsep(char);
72 int main(int, char *[]);
73 void print_hosts(const char *, const char *);
74 void print_netid(const char *);
75 void print_passwd_group(int, const char *);
76 void read_group(const char *);
77 void read_passwd(const char *);
78 void usage(void);
80 TAILQ_HEAD(user_list, user);
81 struct user_list root;
82 struct user_list hroot[HASHMAX];
84 int
85 main(int argc, char *argv[])
87 const char *HostFile = _PATH_HOSTS;
88 const char *PasswdFile = _PATH_PASSWD;
89 const char *GroupFile = _PATH_GROUP;
90 const char *NetidFile = "/etc/netid";
92 int qflag, ch;
93 char *domain;
95 TAILQ_INIT(&root);
96 for (ch = 0; ch < HASHMAX; ch++)
97 TAILQ_INIT((&hroot[ch]));
99 qflag = 0;
100 domain = NULL;
102 while ((ch = getopt(argc, argv, "d:g:h:m:p:q")) != -1) {
103 switch (ch) {
104 case 'd':
105 domain = optarg;
106 break;
108 case 'g':
109 GroupFile = optarg;
110 break;
112 case 'h':
113 HostFile = optarg;
114 break;
116 case 'm':
117 NetidFile = optarg;
118 break;
120 case 'p':
121 PasswdFile = optarg;
122 break;
124 case 'q':
125 qflag++;
126 break;
128 default:
129 usage();
132 if (argc != optind)
133 usage();
135 if (domain == NULL)
136 if (yp_get_default_domain(&domain))
137 errx(1, "Can't get YP domain name");
139 read_passwd(PasswdFile);
140 read_group(GroupFile);
142 print_passwd_group(qflag, domain);
143 print_hosts(HostFile, domain);
144 print_netid(NetidFile);
146 exit (0);
150 hashidx(char key)
152 if (key < 'A')
153 return(0);
155 if (key <= 'Z')
156 return(1 + key - 'A');
158 if (key < 'a')
159 return(27);
161 if (key <= 'z')
162 return(28 + key - 'a');
164 return(54);
167 void
168 add_user(const char *username, const char *uid, const char *gid)
170 struct user *u;
171 int idx;
173 idx = hashidx(username[0]);
175 u = (struct user *)malloc(sizeof(struct user));
176 if (u == NULL)
177 err(1, "can't allocate user");
178 memset(u, 0, sizeof(struct user));
180 u->usr_name = strdup(username);
181 if (u->usr_name == NULL)
182 err(1, "can't allocate user name");
184 u->usr_uid = atoi(uid);
185 u->usr_gid = atoi(gid);
186 u->gid_count = -1;
188 TAILQ_INSERT_TAIL(&root, u, read);
189 TAILQ_INSERT_TAIL((&hroot[idx]), u, hash);
192 void
193 add_group(const char *username, const char *gid)
195 struct user *u;
196 int g, idx;
198 g = atoi(gid);
199 idx = hashidx(username[0]);
201 for (u = hroot[idx].tqh_first;
202 u != NULL; u = u->hash.tqe_next) {
203 if (strcmp(username, u->usr_name) == 0) {
204 if (g != u->usr_gid) {
205 u->gid_count++;
206 if (u->gid_count < NGROUPS)
207 u->gid[u->gid_count] = g;
209 return;
214 void
215 read_passwd(const char *fname)
217 FILE *pfile;
218 size_t line_no;
219 int colon;
220 size_t len;
221 char *line, *p, *k, *u, *g;
223 if ((pfile = fopen(fname, "r")) == NULL)
224 err(1, "%s", fname);
226 line_no = 0;
227 for (;
228 (line = fparseln(pfile, &len, &line_no, NULL, FPARSELN_UNESCALL));
229 free(line)) {
230 if (len == 0) {
231 warnx("%s line %lu: empty line", fname,
232 (unsigned long)line_no);
233 continue;
236 p = line;
237 for (k = p, colon = 0; *k != '\0'; k++)
238 if (*k == ':')
239 colon++;
241 if (colon != 6) {
242 warnx("%s line %lu: incorrect number of fields",
243 fname, (unsigned long)line_no);
244 continue;
247 k = p;
248 p = strchr(p, ':');
249 *p++ = '\0';
251 /* If it's a YP entry, skip it. */
252 if (*k == '+' || *k == '-')
253 continue;
255 /* terminate password */
256 p = strchr(p, ':');
257 *p++ = '\0';
259 /* terminate uid */
260 u = p;
261 p = strchr(p, ':');
262 *p++ = '\0';
264 /* terminate gid */
265 g = p;
266 p = strchr(p, ':');
267 *p++ = '\0';
269 add_user(k, u, g);
271 (void)fclose(pfile);
275 isgsep(char ch)
278 switch (ch) {
279 case ',':
280 case ' ':
281 case '\t':
282 case '\0':
283 return (1);
286 return (0);
289 void
290 read_group(const char *fname)
292 FILE *gfile;
293 size_t line_no;
294 int colon;
295 size_t len;
296 char *line, *p, *k, *u, *g;
298 if ((gfile = fopen(fname, "r")) == NULL)
299 err(1, "%s", fname);
301 line_no = 0;
302 for (;
303 (line = fparseln(gfile, &len, &line_no, NULL, FPARSELN_UNESCALL));
304 free(line)) {
305 if (len == 0) {
306 warnx("%s line %lu: empty line", fname,
307 (unsigned long)line_no);
308 continue;
311 p = line;
312 for (k = p, colon = 0; *k != '\0'; k++)
313 if (*k == ':')
314 colon++;
316 if (colon != 3) {
317 warnx("%s line %lu: incorrect number of fields",
318 fname, (unsigned long)line_no);
319 continue;
322 /* terminate key */
323 k = p;
324 p = strchr(p, ':');
325 *p++ = '\0';
327 if (*k == '+' || *k == '-')
328 continue;
330 /* terminate password */
331 p = strchr(p, ':');
332 *p++ = '\0';
334 /* terminate gid */
335 g = p;
336 p = strchr(p, ':');
337 *p++ = '\0';
339 /* get the group list */
340 for (u = p; *u != '\0'; u = p) {
341 /* find separator */
342 for (; isgsep(*p) == 0; p++)
345 if (*p != '\0') {
346 *p = '\0';
347 if (u != p)
348 add_group(u, g);
349 p++;
350 } else if (u != p)
351 add_group(u, g);
354 (void)fclose(gfile);
357 void
358 print_passwd_group(int qflag, const char *domain)
360 struct user *u, *p;
361 int i;
363 for (u = root.tqh_first; u != NULL; u = u->read.tqe_next) {
364 for (p = root.tqh_first; p->usr_uid != u->usr_uid;
365 p = p->read.tqe_next)
366 /* empty */ ;
367 if (p != u) {
368 if (!qflag) {
369 warnx("unix.%d@%s %s", u->usr_uid, domain,
370 "multiply defined, ignoring duplicate");
372 } else {
373 printf("unix.%d@%s %d:%d", u->usr_uid, domain,
374 u->usr_uid, u->usr_gid);
375 if (u->gid_count >= 0)
376 for (i = 0; i <= u->gid_count; i++)
377 printf(",%d", u->gid[i]);
378 printf("\n");
383 void
384 print_hosts(const char *fname, const char *domain)
386 FILE *hfile;
387 size_t len;
388 char *line, *p, *k, *u;
390 if ((hfile = fopen(fname, "r")) == NULL)
391 err(1, "%s", fname);
393 for (;
394 (line = fparseln(hfile, &len, NULL, NULL, FPARSELN_UNESCALL));
395 free(line)) {
396 if (len == 0)
397 continue;
399 p = line;
400 /* Find the key, replace trailing whitespace will <NUL> */
401 for (k = p; *p && isspace((unsigned char)*p) == 0; p++)
403 while (*p && isspace((unsigned char)*p))
404 *p++ = '\0';
406 /* Get first hostname. */
407 for (u = p; *p && !isspace((unsigned char)*p); p++)
409 *p = '\0';
411 printf("unix.%s@%s 0:%s\n", u, domain, u);
413 (void) fclose(hfile);
416 void
417 print_netid(const char *fname)
419 FILE *mfile;
420 size_t len;
421 char *line, *p, *k, *u;
423 mfile = fopen(fname, "r");
424 if (mfile == NULL)
425 return;
427 for (;
428 (line = fparseln(mfile, &len, NULL, NULL, FPARSELN_UNESCALL));
429 free(line)) {
430 if (len == 0)
431 continue;
433 p = line;
434 /* Find the key, replace trailing whitespace will <NUL> */
435 for (k = p; *p && !isspace((unsigned char)*p); p++)
437 while (*p && isspace((unsigned char)*p))
438 *p++ = '\0';
440 /* Get netid entry. */
441 for (u = p; *p && !isspace((unsigned char)*p); p++)
443 *p = '\0';
445 printf("%s %s\n", k, u);
449 void
450 usage(void)
453 fprintf(stderr, "usage: %s %s\n", getprogname(),
454 "[-d domain] [-q] [-p passwdfile] [-g groupfile]");
455 fprintf(stderr, " %s %s", getprogname(),
456 "[-g groupfile] [-h hostfile] [-m netidfile]");
457 exit(1);