yppush.c revision 1.3 1 /* $NetBSD: yppush.c,v 1.3 1996/08/09 20:24:34 thorpej Exp $ */
2
3 /*
4 * Copyright (c) 1995 Mats O Jansson <moj (at) stacken.kth.se>
5 * All rights reserved.
6 *
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.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Mats O Jansson
18 * 4. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
22 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
25 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <sys/resource.h>
37 #include <sys/signal.h>
38
39 #include <errno.h>
40 #include <err.h>
41 #include <fcntl.h>
42 #include <netdb.h>
43 #include <stdio.h>
44 #include <string.h>
45 #include <unistd.h>
46
47 #include <rpc/rpc.h>
48 #include <rpc/xdr.h>
49 #include <rpcsvc/yp_prot.h>
50 #include <rpcsvc/ypclnt.h>
51
52 #include "yplib_host.h"
53 #include "ypdef.h"
54 #include "ypdb.h"
55 #include "yppush.h"
56
57 extern char *__progname; /* from crt0.o */
58 extern char *optarg;
59 extern int optind;
60
61 int pushit __P((int, char *, int, char *, int, char *));
62 void push __P((int, char *));
63 void req_xfr __P((pid_t, u_int, SVCXPRT *, char *, CLIENT *));
64 void _svc_run __P((void));
65 void cleanup __P((void));
66 void usage __P((void));
67
68 int Verbose = 0;
69 u_int OrderNum;
70
71 char Domain[YPMAXDOMAIN];
72 char Map[YPMAXMAP];
73 char LocalHost[YPMAXPEER];
74
75 static DBM *yp_databas;
76
77 int
78 main(argc, argv)
79 int argc;
80 char **argv;
81 {
82 struct ypall_callback ypcb;
83 char *master, *domain, *map, *hostname;
84 int c, r, i;
85 datum o;
86 char *ypmap = "ypservers";
87 CLIENT *client;
88 struct stat finfo;
89 char order_key[YP_LAST_LEN] = YP_LAST_KEY;
90 static char map_path[MAXPATHLEN];
91
92 if (atexit(cleanup))
93 err(1, "can't register cleanup function");
94
95 domain = NULL;
96 hostname = NULL;
97
98 while ((c = getopt(argc, argv, "d:h:v")) != -1) {
99 switch(c) {
100 case 'd':
101 domain = optarg;
102 break;
103
104 case 'h':
105 hostname = optarg;
106 break;
107
108 case 'v':
109 Verbose = 1;
110 break;
111
112 default:
113 usage();
114 /*NOTREACHED*/
115 }
116 }
117 argv += optind; argc -= optind;
118
119 if (argc != 1)
120 usage();
121
122 map = argv[0];
123
124 if (domain == NULL)
125 if ((c = yp_get_default_domain(&domain)))
126 errx(1, "can't get YP domain name. Reason: %s",
127 yperr_string(c));
128
129 memset(Domain, 0, sizeof(Domain));
130 snprintf(Domain, sizeof(Domain), "%s", domain);
131 memset(Map, 0, sizeof(Map));
132 snprintf(Map, sizeof(Map), "%s", map);
133
134 /* Set up the hostname to be used for the xfr */
135 localhostname(LocalHost, sizeof(LocalHost));
136
137 /* Check domain */
138 sprintf(map_path,"%s/%s",YP_DB_PATH,domain);
139 if (!((stat(map_path, &finfo) == 0) &&
140 ((finfo.st_mode & S_IFMT) == S_IFDIR))) {
141 fprintf(stderr,"yppush: Map does not exists.\n");
142 exit(1);
143 }
144
145 /* Check map */
146 memset(map_path, 0, sizeof(map_path));
147 snprintf(map_path, sizeof(map_path), "%s/%s/%s%s", YP_DB_PATH,
148 Domain, Map, YPDB_SUFFIX);
149 if (stat(map_path, &finfo) != 0)
150 errx(1, "map does not exist");
151
152 /* Open the database */
153 memset(map_path, 0, sizeof(map_path));
154 snprintf(map_path, sizeof(map_path), "%s/%s/%s", YP_DB_PATH,
155 Domain, Map);
156 yp_databas = ypdb_open(map_path, 0, O_RDONLY);
157 OrderNum=0xffffffff;
158 if (yp_databas == NULL)
159 errx(1, "%s%s: cannot open database", map_path, YPDB_SUFFIX);
160 else {
161 o.dptr = (char *) &order_key;
162 o.dsize = YP_LAST_LEN;
163 o = ypdb_fetch(yp_databas, o);
164 if (o.dptr == NULL)
165 errx(1, "%s: cannot determine order number", Map);
166 else {
167 OrderNum = 0;
168 for (i = 0; i < o.dsize - 1; i++)
169 if (!isdigit(o.dptr[i]))
170 OrderNum=0xffffffff;
171
172 if (OrderNum != 0)
173 errx(1, "%s: invalid order number `%s'",
174 Map, o.dptr);
175 else
176 OrderNum = atoi(o.dptr);
177 }
178 }
179
180 /* No longer need YP map. */
181 ypdb_close(yp_databas);
182 yp_databas = NULL;
183
184 r = yp_bind(Domain);
185 if (r != 0)
186 errx(1, "%s", yperr_string(r));
187
188 if (hostname != NULL)
189 push(strlen(hostname), hostname);
190 else {
191 r = yp_master(Domain, ypmap, &master);
192 if (r != 0)
193 errx(1, "%s (map = %s)", yperr_string(r), ypmap);
194
195 if (Verbose)
196 printf("Contacting master for ypservers (%s).\n",
197 master);
198
199 client = yp_bind_host(master, YPPROG, YPVERS, 0, 1);
200
201 ypcb.foreach = (int(*)())pushit;
202 ypcb.data = NULL;
203
204 r = yp_all_host(client, Domain, ypmap, &ypcb);
205 if (r != 0)
206 errx(1, "%s (map = %s)", yperr_string(r), ypmap);
207 }
208 exit (0);
209 }
210
211 void
212 usage()
213 {
214
215 fprintf(stderr, "usage: %s [-d domainname] [-h host] [-v] mapname\n",
216 __progname);
217 exit(1);
218 }
219
220 void
221 _svc_run()
222 {
223 fd_set readfds;
224 struct timeval timeout;
225
226 timeout.tv_sec = 60;
227 timeout.tv_usec = 0;
228
229 for(;;) {
230 readfds = svc_fdset;
231
232 switch (select(_rpc_dtablesize(), &readfds, NULL, NULL,
233 &timeout)) {
234
235 case -1:
236 if (errno == EINTR)
237 continue;
238
239 warnx("_svc_run: select failed");
240 return;
241
242 case 0:
243 errx(0, "Callback timed out.");
244
245 default:
246 svc_getreqset(&readfds);
247 }
248 }
249 }
250
251 void
252 req_xfr(pid, prog, transp, host, client)
253 pid_t pid;
254 u_int prog;
255 SVCXPRT *transp;
256 char *host;
257 CLIENT *client;
258 {
259 struct ypreq_xfr request;
260 struct timeval tv;
261
262 tv.tv_sec = 0;
263 tv.tv_usec = 0;
264
265 request.map_parms.domain = &Domain[0];
266 request.map_parms.map = &Map[0];
267 request.map_parms.owner = &LocalHost[0];
268 request.map_parms.ordernum = OrderNum;
269 request.transid = (u_int)pid;
270 request.proto = prog;
271 request.port = transp->xp_port;
272
273 if (Verbose)
274 printf("%d: %s(%d@%s) -> %s@%s\n", request.transid,
275 request.map_parms.map, request.map_parms.ordernum,
276 host, request.map_parms.owner, request.map_parms.domain);
277
278 switch (clnt_call(client, YPPROC_XFR, xdr_ypreq_xfr, &request,
279 xdr_void, NULL, tv)) {
280 case RPC_SUCCESS:
281 case RPC_TIMEDOUT:
282 break;
283
284 default:
285 clnt_perror(client, "yppush: Cannot call YPPROC_XFR");
286 kill(pid, SIGTERM);
287 }
288 }
289
290 void
291 push(inlen, indata)
292 int inlen;
293 char *indata;
294 {
295 char host[YPMAXPEER];
296 CLIENT *client;
297 SVCXPRT *transp;
298 int sock = RPC_ANYSOCK;
299 u_int prog;
300 bool_t sts;
301 pid_t pid;
302 int status;
303 struct rusage res;
304
305 memset(host, 0, sizeof(host));
306 snprintf(host, sizeof(host), "%*.*s", inlen, inlen, indata);
307
308 client = clnt_create(host, YPPROG, YPVERS, "tcp");
309 if (client == NULL) {
310 if (Verbose)
311 fprintf(stderr, "Target host: %s\n", host);
312 clnt_pcreateerror("yppush: cannot create client");
313 return;
314 }
315
316 transp = svcudp_create(sock);
317 if (transp == NULL) {
318 warnx("cannot create callback transport");
319 return;
320 }
321
322 for (prog = 0x40000000; prog < 0x5fffffff; prog++) {
323 if (sts = svc_register(transp, prog, 1,
324 yppush_xfrrespprog_1, IPPROTO_UDP))
325 break;
326 }
327
328 if (sts == FALSE) {
329 warnx("cannot register callback");
330 return;
331 }
332
333 switch ((pid = fork())) {
334 case -1:
335 err(1, "fork failed");
336
337 case 0:
338 _svc_run();
339 exit(0);
340
341 default:
342 close(transp->xp_sock);
343 req_xfr(pid, prog, transp, host, client);
344 wait4(pid, &status, 0, &res);
345 svc_unregister(prog, 1);
346 if (client != NULL)
347 clnt_destroy(client);
348 }
349 }
350
351 int
352 pushit(instatus, inkey, inkeylen, inval, invallen, indata)
353 int instatus;
354 char *inkey;
355 int inkeylen;
356 char *inval;
357 int invallen;
358 char *indata;
359 {
360
361 if (instatus != YP_TRUE)
362 return instatus;
363
364 push(inkeylen, inkey);
365 return 0;
366 }
367
368 void
369 cleanup()
370 {
371
372 /* Make sure the map file is closed. */
373 if (yp_databas != NULL)
374 ypdb_close(yp_databas);
375 }
376