yppush.c revision 1.4 1 /* $NetBSD: yppush.c,v 1.4 1997/07/18 21:57:12 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/wait.h>
38
39 #include <ctype.h>
40 #include <errno.h>
41 #include <err.h>
42 #include <fcntl.h>
43 #include <netdb.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <signal.h>
48 #include <unistd.h>
49
50 #include <rpc/rpc.h>
51 #include <rpc/xdr.h>
52 #include <rpcsvc/yp_prot.h>
53 #include <rpcsvc/ypclnt.h>
54
55 #include "protos.h"
56 #include "yplib_host.h"
57 #include "ypdef.h"
58 #include "ypdb.h"
59 #include "yppush.h"
60
61 extern char *__progname; /* from crt0.o */
62
63 int main __P((int, char *[]));
64 int pushit __P((int, char *, int, char *, int, char *));
65 void push __P((int, char *));
66 void req_xfr __P((pid_t, u_int, SVCXPRT *, char *, CLIENT *));
67 void _svc_run __P((void));
68 void cleanup __P((void));
69 void usage __P((void));
70
71 int Verbose = 0;
72 u_int OrderNum;
73
74 char Domain[YPMAXDOMAIN];
75 char Map[YPMAXMAP];
76 char LocalHost[YPMAXPEER];
77
78 static DBM *yp_databas;
79
80 int
81 main(argc, argv)
82 int argc;
83 char *argv[];
84 {
85 struct ypall_callback ypcb;
86 char *master, *domain, *map, *hostname;
87 int c, r, i;
88 datum o;
89 char *ypmap = "ypservers";
90 CLIENT *client;
91 struct stat finfo;
92 char order_key[YP_LAST_LEN] = YP_LAST_KEY;
93 static char map_path[MAXPATHLEN];
94
95 if (atexit(cleanup))
96 err(1, "can't register cleanup function");
97
98 domain = NULL;
99 hostname = NULL;
100
101 while ((c = getopt(argc, argv, "d:h:v")) != -1) {
102 switch(c) {
103 case 'd':
104 domain = optarg;
105 break;
106
107 case 'h':
108 hostname = optarg;
109 break;
110
111 case 'v':
112 Verbose = 1;
113 break;
114
115 default:
116 usage();
117 /*NOTREACHED*/
118 }
119 }
120 argv += optind; argc -= optind;
121
122 if (argc != 1)
123 usage();
124
125 map = argv[0];
126
127 if (domain == NULL)
128 if ((c = yp_get_default_domain(&domain)))
129 errx(1, "can't get YP domain name. Reason: %s",
130 yperr_string(c));
131
132 memset(Domain, 0, sizeof(Domain));
133 snprintf(Domain, sizeof(Domain), "%s", domain);
134 memset(Map, 0, sizeof(Map));
135 snprintf(Map, sizeof(Map), "%s", map);
136
137 /* Set up the hostname to be used for the xfr */
138 localhostname(LocalHost, sizeof(LocalHost));
139
140 /* Check domain */
141 sprintf(map_path,"%s/%s",YP_DB_PATH,domain);
142 if (!((stat(map_path, &finfo) == 0) &&
143 ((finfo.st_mode & S_IFMT) == S_IFDIR))) {
144 fprintf(stderr,"yppush: Map does not exists.\n");
145 exit(1);
146 }
147
148 /* Check map */
149 memset(map_path, 0, sizeof(map_path));
150 snprintf(map_path, sizeof(map_path), "%s/%s/%s%s", YP_DB_PATH,
151 Domain, Map, YPDB_SUFFIX);
152 if (stat(map_path, &finfo) != 0)
153 errx(1, "map does not exist");
154
155 /* Open the database */
156 memset(map_path, 0, sizeof(map_path));
157 snprintf(map_path, sizeof(map_path), "%s/%s/%s", YP_DB_PATH,
158 Domain, Map);
159 yp_databas = ypdb_open(map_path, 0, O_RDONLY);
160 OrderNum=0xffffffff;
161 if (yp_databas == NULL)
162 errx(1, "%s%s: cannot open database", map_path, YPDB_SUFFIX);
163 else {
164 o.dptr = (char *) &order_key;
165 o.dsize = YP_LAST_LEN;
166 o = ypdb_fetch(yp_databas, o);
167 if (o.dptr == NULL)
168 errx(1, "%s: cannot determine order number", Map);
169 else {
170 OrderNum = 0;
171 for (i = 0; i < o.dsize - 1; i++)
172 if (!isdigit(o.dptr[i]))
173 OrderNum=0xffffffff;
174
175 if (OrderNum != 0)
176 errx(1, "%s: invalid order number `%s'",
177 Map, o.dptr);
178 else
179 OrderNum = atoi(o.dptr);
180 }
181 }
182
183 /* No longer need YP map. */
184 ypdb_close(yp_databas);
185 yp_databas = NULL;
186
187 r = yp_bind(Domain);
188 if (r != 0)
189 errx(1, "%s", yperr_string(r));
190
191 if (hostname != NULL)
192 push(strlen(hostname), hostname);
193 else {
194 r = yp_master(Domain, ypmap, &master);
195 if (r != 0)
196 errx(1, "%s (map = %s)", yperr_string(r), ypmap);
197
198 if (Verbose)
199 printf("Contacting master for ypservers (%s).\n",
200 master);
201
202 client = yp_bind_host(master, YPPROG, YPVERS, 0, 1);
203
204 ypcb.foreach = pushit;
205 ypcb.data = NULL;
206
207 r = yp_all_host(client, Domain, ypmap, &ypcb);
208 if (r != 0)
209 errx(1, "%s (map = %s)", yperr_string(r), ypmap);
210 }
211 exit (0);
212 }
213
214 void
215 usage()
216 {
217
218 fprintf(stderr, "usage: %s [-d domainname] [-h host] [-v] mapname\n",
219 __progname);
220 exit(1);
221 }
222
223 void
224 _svc_run()
225 {
226 fd_set readfds;
227 struct timeval timeout;
228
229 timeout.tv_sec = 60;
230 timeout.tv_usec = 0;
231
232 for(;;) {
233 readfds = svc_fdset;
234
235 switch (select(sysconf(_SC_OPEN_MAX), &readfds, NULL, NULL,
236 &timeout)) {
237
238 case -1:
239 if (errno == EINTR)
240 continue;
241
242 warnx("_svc_run: select failed");
243 return;
244
245 case 0:
246 errx(0, "Callback timed out.");
247
248 default:
249 svc_getreqset(&readfds);
250 }
251 }
252 }
253
254 void
255 req_xfr(pid, prog, transp, host, client)
256 pid_t pid;
257 u_int prog;
258 SVCXPRT *transp;
259 char *host;
260 CLIENT *client;
261 {
262 struct ypreq_xfr request;
263 struct timeval tv;
264
265 tv.tv_sec = 0;
266 tv.tv_usec = 0;
267
268 request.map_parms.domain = &Domain[0];
269 request.map_parms.map = &Map[0];
270 request.map_parms.owner = &LocalHost[0];
271 request.map_parms.ordernum = OrderNum;
272 request.transid = (u_int)pid;
273 request.proto = prog;
274 request.port = transp->xp_port;
275
276 if (Verbose)
277 printf("%d: %s(%d@%s) -> %s@%s\n", request.transid,
278 request.map_parms.map, request.map_parms.ordernum,
279 host, request.map_parms.owner, request.map_parms.domain);
280
281 switch (clnt_call(client, YPPROC_XFR, xdr_ypreq_xfr, &request,
282 xdr_void, NULL, tv)) {
283 case RPC_SUCCESS:
284 case RPC_TIMEDOUT:
285 break;
286
287 default:
288 clnt_perror(client, "yppush: Cannot call YPPROC_XFR");
289 kill(pid, SIGTERM);
290 }
291 }
292
293 void
294 push(inlen, indata)
295 int inlen;
296 char *indata;
297 {
298 char host[YPMAXPEER];
299 CLIENT *client;
300 SVCXPRT *transp;
301 int sock = RPC_ANYSOCK;
302 u_int prog;
303 bool_t sts;
304 pid_t pid;
305 int status;
306 struct rusage res;
307
308 memset(host, 0, sizeof(host));
309 snprintf(host, sizeof(host), "%*.*s", inlen, inlen, indata);
310
311 client = clnt_create(host, YPPROG, YPVERS, "tcp");
312 if (client == NULL) {
313 if (Verbose)
314 fprintf(stderr, "Target host: %s\n", host);
315 clnt_pcreateerror("yppush: cannot create client");
316 return;
317 }
318
319 transp = svcudp_create(sock);
320 if (transp == NULL) {
321 warnx("cannot create callback transport");
322 return;
323 }
324
325 for (prog = 0x40000000; prog < 0x5fffffff; prog++) {
326 if ((sts = svc_register(transp, prog, 1,
327 yppush_xfrrespprog_1, IPPROTO_UDP)))
328 break;
329 }
330
331 if (sts == FALSE) {
332 warnx("cannot register callback");
333 return;
334 }
335
336 switch ((pid = fork())) {
337 case -1:
338 err(1, "fork failed");
339
340 case 0:
341 _svc_run();
342 exit(0);
343
344 default:
345 close(transp->xp_sock);
346 req_xfr(pid, prog, transp, host, client);
347 wait4(pid, &status, 0, &res);
348 svc_unregister(prog, 1);
349 if (client != NULL)
350 clnt_destroy(client);
351 }
352 }
353
354 int
355 pushit(instatus, inkey, inkeylen, inval, invallen, indata)
356 int instatus;
357 char *inkey;
358 int inkeylen;
359 char *inval;
360 int invallen;
361 char *indata;
362 {
363
364 if (instatus != YP_TRUE)
365 return instatus;
366
367 push(inkeylen, inkey);
368 return 0;
369 }
370
371 void
372 cleanup()
373 {
374
375 /* Make sure the map file is closed. */
376 if (yp_databas != NULL)
377 ypdb_close(yp_databas);
378 }
379