Print this page
195 Need replacement for nfs/lockd+klm
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/fs.d/nfs/statd/sm_statd.c
+++ new/usr/src/cmd/fs.d/nfs/statd/sm_statd.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 25
26 26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 27 /* All Rights Reserved */
28 28
↓ open down ↓ |
28 lines elided |
↑ open up ↑ |
29 29 /*
30 30 * University Copyright- Copyright (c) 1982, 1986, 1988
31 31 * The Regents of the University of California
32 32 * All Rights Reserved
33 33 *
34 34 * University Acknowledgment- Portions of this document are derived from
35 35 * software developed by the University of California, Berkeley, and its
36 36 * contributors.
37 37 */
38 38
39 +/*
40 + * Copyright (c) 2012 by Delphix. All rights reserved.
41 + */
42 +
39 43 #pragma ident "%Z%%M% %I% %E% SMI"
40 44
41 45 /*
42 46 * sm_statd.c consists of routines used for the intermediate
43 47 * statd implementation(3.2 rpc.statd);
44 48 * it creates an entry in "current" directory for each site that it monitors;
45 49 * after crash and recovery, it moves all entries in "current"
46 50 * to "backup" directory, and notifies the corresponding statd of its recovery.
47 51 */
48 52
49 53 #include <stdio.h>
50 54 #include <stdlib.h>
51 55 #include <unistd.h>
52 56 #include <string.h>
53 57 #include <syslog.h>
54 58 #include <netdb.h>
55 59 #include <sys/types.h>
56 60 #include <sys/stat.h>
57 61 #include <sys/file.h>
58 62 #include <sys/param.h>
59 63 #include <arpa/inet.h>
60 64 #include <dirent.h>
61 65 #include <rpc/rpc.h>
62 66 #include <rpcsvc/sm_inter.h>
63 67 #include <rpcsvc/nsm_addr.h>
64 68 #include <errno.h>
65 69 #include <memory.h>
66 70 #include <signal.h>
67 71 #include <synch.h>
68 72 #include <thread.h>
69 73 #include <limits.h>
70 74 #include <strings.h>
71 75 #include "sm_statd.h"
72 76
73 77
74 78 int LOCAL_STATE;
75 79
76 80 sm_hash_t mon_table[MAX_HASHSIZE];
77 81 static sm_hash_t record_table[MAX_HASHSIZE];
78 82 static sm_hash_t recov_q;
79 83
80 84 static name_entry *find_name(name_entry **namepp, char *name);
81 85 static name_entry *insert_name(name_entry **namepp, char *name,
82 86 int need_alloc);
83 87 static void delete_name(name_entry **namepp, char *name);
84 88 static void remove_name(char *name, int op, int startup);
85 89 static int statd_call_statd(char *name);
86 90 static void pr_name(char *name, int flag);
87 91 static void *thr_statd_init();
88 92 static void *sm_try();
89 93 static void *thr_call_statd(void *);
90 94 static void remove_single_name(char *name, char *dir1, char *dir2);
91 95 static int move_file(char *fromdir, char *file, char *todir);
92 96 static int count_symlinks(char *dir, char *name, int *count);
93 97 static char *family2string(sa_family_t family);
94 98
95 99 /*
96 100 * called when statd first comes up; it searches /etc/sm to gather
97 101 * all entries to notify its own failure
98 102 */
99 103 void
100 104 statd_init()
101 105 {
102 106 struct dirent *dirp;
103 107 DIR *dp;
104 108 FILE *fp, *fp_tmp;
105 109 int i, tmp_state;
106 110 char state_file[MAXPATHLEN+SM_MAXPATHLEN];
107 111
108 112 if (debug)
109 113 (void) printf("enter statd_init\n");
110 114
111 115 /*
112 116 * First try to open the file. If that fails, try to create it.
113 117 * If that fails, give up.
114 118 */
115 119 if ((fp = fopen(STATE, "r+")) == (FILE *)NULL)
116 120 if ((fp = fopen(STATE, "w+")) == (FILE *)NULL) {
117 121 syslog(LOG_ERR, "can't open %s: %m", STATE);
118 122 exit(1);
119 123 } else
120 124 (void) chmod(STATE, 0644);
121 125 if ((fscanf(fp, "%d", &LOCAL_STATE)) == EOF) {
122 126 if (debug >= 2)
123 127 (void) printf("empty file\n");
124 128 LOCAL_STATE = 0;
125 129 }
126 130
127 131 /*
128 132 * Scan alternate paths for largest "state" number
129 133 */
130 134 for (i = 0; i < pathix; i++) {
131 135 (void) sprintf(state_file, "%s/statmon/state", path_name[i]);
132 136 if ((fp_tmp = fopen(state_file, "r+")) == (FILE *)NULL) {
133 137 if ((fp_tmp = fopen(state_file, "w+"))
134 138 == (FILE *)NULL) {
135 139 if (debug)
136 140 syslog(LOG_ERR,
137 141 "can't open %s: %m",
138 142 state_file);
139 143 continue;
140 144 } else
141 145 (void) chmod(state_file, 0644);
142 146 }
143 147 if ((fscanf(fp_tmp, "%d", &tmp_state)) == EOF) {
144 148 if (debug)
145 149 syslog(LOG_ERR,
146 150 "statd: %s: file empty\n", state_file);
147 151 (void) fclose(fp_tmp);
148 152 continue;
149 153 }
150 154 if (tmp_state > LOCAL_STATE) {
151 155 LOCAL_STATE = tmp_state;
152 156 if (debug)
153 157 (void) printf("Update LOCAL STATE: %d\n",
154 158 tmp_state);
155 159 }
156 160 (void) fclose(fp_tmp);
157 161 }
158 162
159 163 LOCAL_STATE = ((LOCAL_STATE%2) == 0) ? LOCAL_STATE+1 : LOCAL_STATE+2;
160 164
161 165 /* IF local state overflows, reset to value 1 */
162 166 if (LOCAL_STATE < 0) {
163 167 LOCAL_STATE = 1;
164 168 }
165 169
166 170 /* Copy the LOCAL_STATE value back to all stat files */
167 171 if (fseek(fp, 0, 0) == -1) {
168 172 syslog(LOG_ERR, "statd: fseek failed\n");
169 173 exit(1);
170 174 }
171 175
172 176 (void) fprintf(fp, "%-10d", LOCAL_STATE);
173 177 (void) fflush(fp);
174 178 if (fsync(fileno(fp)) == -1) {
175 179 syslog(LOG_ERR, "statd: fsync failed\n");
176 180 exit(1);
177 181 }
178 182 (void) fclose(fp);
179 183
180 184 for (i = 0; i < pathix; i++) {
181 185 (void) sprintf(state_file, "%s/statmon/state", path_name[i]);
182 186 if ((fp_tmp = fopen(state_file, "r+")) == (FILE *)NULL) {
183 187 if ((fp_tmp = fopen(state_file, "w+"))
184 188 == (FILE *)NULL) {
185 189 syslog(LOG_ERR,
186 190 "can't open %s: %m", state_file);
187 191 continue;
188 192 } else
189 193 (void) chmod(state_file, 0644);
190 194 }
191 195 (void) fprintf(fp_tmp, "%-10d", LOCAL_STATE);
192 196 (void) fflush(fp_tmp);
193 197 if (fsync(fileno(fp_tmp)) == -1) {
194 198 syslog(LOG_ERR,
195 199 "statd: %s: fsync failed\n", state_file);
196 200 (void) fclose(fp_tmp);
197 201 exit(1);
198 202 }
199 203 (void) fclose(fp_tmp);
200 204 }
201 205
202 206 if (debug)
203 207 (void) printf("local state = %d\n", LOCAL_STATE);
204 208
205 209 if ((mkdir(CURRENT, SM_DIRECTORY_MODE)) == -1) {
206 210 if (errno != EEXIST) {
207 211 syslog(LOG_ERR, "statd: mkdir current, error %m\n");
208 212 exit(1);
209 213 }
210 214 }
211 215 if ((mkdir(BACKUP, SM_DIRECTORY_MODE)) == -1) {
212 216 if (errno != EEXIST) {
213 217 syslog(LOG_ERR, "statd: mkdir backup, error %m\n");
214 218 exit(1);
215 219 }
216 220 }
217 221
218 222 /* get all entries in CURRENT into BACKUP */
219 223 if ((dp = opendir(CURRENT)) == (DIR *)NULL) {
220 224 syslog(LOG_ERR, "statd: open current directory, error %m\n");
221 225 exit(1);
222 226 }
223 227
224 228 while ((dirp = readdir(dp)) != NULL) {
225 229 if (strcmp(dirp->d_name, ".") != 0 &&
226 230 strcmp(dirp->d_name, "..") != 0) {
227 231 /* rename all entries from CURRENT to BACKUP */
228 232 (void) move_file(CURRENT, dirp->d_name, BACKUP);
229 233 }
230 234 }
231 235
232 236 (void) closedir(dp);
233 237
234 238 /* Contact hosts' statd */
235 239 if (thr_create(NULL, NULL, thr_statd_init, NULL, THR_DETACHED, 0)) {
236 240 syslog(LOG_ERR,
237 241 "statd: unable to create thread for thr_statd_init\n");
238 242 exit(1);
239 243 }
240 244 }
241 245
242 246 /*
243 247 * Work thread which contacts hosts' statd.
244 248 */
245 249 void *
246 250 thr_statd_init()
247 251 {
248 252 struct dirent *dirp;
249 253 DIR *dp;
250 254 int num_threads;
251 255 int num_join;
252 256 int i;
253 257 char *name;
254 258 char buf[MAXPATHLEN+SM_MAXPATHLEN];
255 259
256 260 /* Go thru backup directory and contact hosts */
257 261 if ((dp = opendir(BACKUP)) == (DIR *)NULL) {
258 262 syslog(LOG_ERR, "statd: open backup directory, error %m\n");
259 263 exit(1);
260 264 }
261 265
262 266 /*
263 267 * Create "UNDETACHED" threads for each symlink and (unlinked)
264 268 * regular file in backup directory to initiate statd_call_statd.
265 269 * NOTE: These threads are the only undetached threads in this
266 270 * program and thus, the thread id is not needed to join the threads.
267 271 */
268 272 num_threads = 0;
269 273 while ((dirp = readdir(dp)) != NULL) {
270 274 /*
271 275 * If host file is not a symlink, don't bother to
272 276 * spawn a thread for it. If any link(s) refer to
273 277 * it, the host will be contacted using the link(s).
274 278 * If not, we'll deal with it during the legacy pass.
275 279 */
276 280 (void) sprintf(buf, "%s/%s", BACKUP, dirp->d_name);
277 281 if (is_symlink(buf) == 0) {
278 282 continue;
279 283 }
280 284
281 285 /*
282 286 * If the num_threads has exceeded, wait until
283 287 * a certain amount of threads have finished.
284 288 * Currently, 10% of threads created should be joined.
285 289 */
286 290 if (num_threads > MAX_THR) {
287 291 num_join = num_threads/PERCENT_MINJOIN;
288 292 for (i = 0; i < num_join; i++)
289 293 thr_join(0, 0, 0);
290 294 num_threads -= num_join;
291 295 }
292 296
293 297 /*
294 298 * If can't alloc name then print error msg and
295 299 * continue to next item on list.
296 300 */
297 301 name = strdup(dirp->d_name);
298 302 if (name == (char *)NULL) {
299 303 syslog(LOG_ERR,
300 304 "statd: unable to allocate space for name %s\n",
301 305 dirp->d_name);
302 306 continue;
303 307 }
304 308
305 309 /* Create a thread to do a statd_call_statd for name */
306 310 if (thr_create(NULL, NULL, thr_call_statd,
307 311 (void *) name, 0, 0)) {
308 312 syslog(LOG_ERR,
309 313 "statd: unable to create thr_call_statd() for name %s.\n",
310 314 dirp->d_name);
311 315 free(name);
312 316 continue;
313 317 }
314 318 num_threads++;
315 319 }
316 320
317 321 /*
318 322 * Join the other threads created above before processing the
319 323 * legacies. This allows all symlinks and the regular files
320 324 * to which they correspond to be processed and deleted.
321 325 */
322 326 for (i = 0; i < num_threads; i++) {
323 327 thr_join(0, 0, 0);
324 328 }
325 329
326 330 /*
327 331 * The second pass checks for `legacies': regular files which
328 332 * never had symlinks pointing to them at all, just like in the
329 333 * good old (pre-1184192 fix) days. Once a machine has cleaned
330 334 * up its legacies they should only reoccur due to catastrophes
331 335 * (e.g., severed symlinks).
332 336 */
333 337 rewinddir(dp);
334 338 num_threads = 0;
335 339 while ((dirp = readdir(dp)) != NULL) {
336 340 if (strcmp(dirp->d_name, ".") == 0 ||
337 341 strcmp(dirp->d_name, "..") == 0) {
338 342 continue;
339 343 }
340 344
341 345 (void) sprintf(buf, "%s/%s", BACKUP, dirp->d_name);
342 346 if (is_symlink(buf)) {
343 347 /*
344 348 * We probably couldn't reach this host and it's
345 349 * been put on the recovery queue for retry.
346 350 * Skip it and keep looking for regular files.
347 351 */
348 352 continue;
349 353 }
350 354
351 355 if (debug) {
352 356 (void) printf("thr_statd_init: legacy %s\n",
353 357 dirp->d_name);
354 358 }
355 359
356 360 /*
357 361 * If the number of threads exceeds the maximum, wait
358 362 * for some fraction of them to finish before
359 363 * continuing.
360 364 */
361 365 if (num_threads > MAX_THR) {
362 366 num_join = num_threads/PERCENT_MINJOIN;
363 367 for (i = 0; i < num_join; i++)
364 368 thr_join(0, 0, 0);
365 369 num_threads -= num_join;
366 370 }
367 371
368 372 /*
369 373 * If can't alloc name then print error msg and
370 374 * continue to next item on list.
371 375 */
372 376 name = strdup(dirp->d_name);
373 377 if (name == (char *)NULL) {
374 378 syslog(LOG_ERR,
375 379 "statd: unable to allocate space for name %s\n",
376 380 dirp->d_name);
377 381 continue;
378 382 }
379 383
380 384 /* Create a thread to do a statd_call_statd for name */
381 385 if (thr_create(NULL, NULL, thr_call_statd,
382 386 (void *) name, 0, 0)) {
383 387 syslog(LOG_ERR,
384 388 "statd: unable to create thr_call_statd() for name %s.\n",
385 389 dirp->d_name);
386 390 free(name);
387 391 continue;
388 392 }
389 393 num_threads++;
390 394 }
391 395
392 396 (void) closedir(dp);
393 397
394 398 /*
395 399 * Join the other threads created above before creating thread
396 400 * to process items in recovery table.
397 401 */
398 402 for (i = 0; i < num_threads; i++) {
399 403 thr_join(0, 0, 0);
400 404 }
401 405
402 406 /*
403 407 * Need to only copy /var/statmon/sm.bak to alternate paths, since
404 408 * the only hosts in /var/statmon/sm should be the ones currently
405 409 * being monitored and already should be in alternate paths as part
406 410 * of insert_mon().
407 411 */
408 412 for (i = 0; i < pathix; i++) {
409 413 (void) sprintf(buf, "%s/statmon/sm.bak", path_name[i]);
410 414 if ((mkdir(buf, SM_DIRECTORY_MODE)) == -1) {
411 415 if (errno != EEXIST)
412 416 syslog(LOG_ERR, "statd: mkdir %s error %m\n",
413 417 buf);
414 418 else
415 419 copydir_from_to(BACKUP, buf);
416 420 } else
417 421 copydir_from_to(BACKUP, buf);
418 422 }
419 423
420 424
421 425 /*
422 426 * Reset the die and in_crash variable and signal other threads
423 427 * that have issued an sm_crash and are waiting.
424 428 */
425 429 mutex_lock(&crash_lock);
426 430 die = 0;
427 431 in_crash = 0;
428 432 mutex_unlock(&crash_lock);
429 433 cond_broadcast(&crash_finish);
430 434
431 435 if (debug)
432 436 (void) printf("Creating thread for sm_try\n");
433 437
434 438 /* Continue to notify statd on hosts that were unreachable. */
435 439 if (thr_create(NULL, NULL, sm_try, NULL, THR_DETACHED, 0))
436 440 syslog(LOG_ERR,
437 441 "statd: unable to create thread for sm_try().\n");
438 442 thr_exit((void *) 0);
439 443 #ifdef lint
440 444 return (0);
441 445 #endif
442 446 }
443 447
444 448 /*
445 449 * Work thread to make call to statd_call_statd.
446 450 */
447 451 void *
448 452 thr_call_statd(void *namep)
449 453 {
450 454 char *name = (char *)namep;
451 455
452 456 /*
453 457 * If statd of name is unreachable, add name to recovery table
454 458 * otherwise if statd_call_statd was successful, remove from backup.
455 459 */
456 460 if (statd_call_statd(name) != 0) {
457 461 int n;
458 462 char *tail;
459 463 char path[MAXPATHLEN];
460 464 /*
461 465 * since we are constructing this pathname below we add
462 466 * another space for the terminating NULL so we don't
463 467 * overflow our buffer when we do the readlink
464 468 */
465 469 char rname[MAXNAMELEN + 1];
466 470
467 471 if (debug) {
468 472 (void) printf(
469 473 "statd call failed, inserting %s in recov_q\n", name);
470 474 }
471 475 mutex_lock(&recov_q.lock);
472 476 (void) insert_name(&recov_q.sm_recovhdp, name, 0);
473 477 mutex_unlock(&recov_q.lock);
474 478
475 479 /*
476 480 * If we queued a symlink name in the recovery queue,
477 481 * we now clean up the regular file to which it referred.
478 482 * This may leave a severed symlink if multiple links
479 483 * referred to one regular file; this is unaesthetic but
480 484 * it works. The big benefit is that it prevents us
481 485 * from recovering the same host twice (as symlink and
482 486 * as regular file) needlessly, usually on separate reboots.
483 487 */
484 488 (void) strcpy(path, BACKUP);
485 489 (void) strcat(path, "/");
486 490 (void) strcat(path, name);
487 491 if (is_symlink(path)) {
488 492 n = readlink(path, rname, MAXNAMELEN);
489 493 if (n <= 0) {
490 494 if (debug >= 2) {
491 495 (void) printf(
492 496 "thr_call_statd: can't read link %s\n",
493 497 path);
494 498 }
495 499 } else {
496 500 rname[n] = '\0';
497 501
498 502 tail = strrchr(path, '/') + 1;
499 503
500 504 if ((strlen(BACKUP) + strlen(rname) + 2) <=
501 505 MAXPATHLEN) {
502 506 (void) strcpy(tail, rname);
503 507 delete_file(path);
504 508 } else if (debug) {
505 509 printf("thr_call_statd: path over"
506 510 "maxpathlen!\n");
507 511 }
508 512 }
509 513
510 514 }
511 515
512 516 if (debug)
513 517 pr_name(name, 0);
514 518
515 519 } else {
516 520 /*
517 521 * If `name' is an IP address symlink to a name file,
518 522 * remove it now. If it is the last such symlink,
519 523 * remove the name file as well. Regular files with
520 524 * no symlinks to them are assumed to be legacies and
521 525 * are removed as well.
522 526 */
523 527 remove_name(name, 1, 1);
524 528 free(name);
525 529 }
526 530 thr_exit((void *) 0);
527 531 #ifdef lint
528 532 return (0);
529 533 #endif
530 534 }
531 535
532 536 /*
533 537 * Notifies the statd of host specified by name to indicate that
534 538 * state has changed for this server.
535 539 */
536 540 static int
537 541 statd_call_statd(name)
538 542 char *name;
539 543 {
540 544 enum clnt_stat clnt_stat;
541 545 struct timeval tottimeout;
542 546 CLIENT *clnt;
543 547 char *name_or_addr;
544 548 stat_chge ntf;
545 549 int i;
546 550 int rc;
547 551 int dummy1, dummy2, dummy3, dummy4;
548 552 char ascii_addr[MAXNAMELEN];
549 553 size_t unq_len;
550 554
551 555 ntf.mon_name = hostname;
552 556 ntf.state = LOCAL_STATE;
553 557 if (debug)
554 558 (void) printf("statd_call_statd at %s\n", name);
555 559
556 560 /*
557 561 * If it looks like an ASCII <address family>.<address> specifier,
558 562 * strip off the family - we just want the address when obtaining
559 563 * a client handle.
560 564 * If it's anything else, just pass it on to create_client().
561 565 */
562 566 unq_len = strcspn(name, ".");
563 567
564 568 if ((strncmp(name, SM_ADDR_IPV4, unq_len) == 0) ||
565 569 (strncmp(name, SM_ADDR_IPV6, unq_len) == 0)) {
566 570 name_or_addr = strchr(name, '.') + 1;
567 571 } else {
568 572 name_or_addr = name;
569 573 }
570 574
571 575 /*
572 576 * NOTE: We depend here upon the fact that the RPC client code
573 577 * allows us to use ASCII dotted quad `names', i.e. "192.9.200.1".
↓ open down ↓ |
525 lines elided |
↑ open up ↑ |
574 578 * This may change in a future release.
575 579 */
576 580 if (debug) {
577 581 (void) printf("statd_call_statd: calling create_client(%s)\n",
578 582 name_or_addr);
579 583 }
580 584
581 585 tottimeout.tv_sec = SM_RPC_TIMEOUT;
582 586 tottimeout.tv_usec = 0;
583 587
584 - if ((clnt = create_client(name_or_addr, SM_PROG, SM_VERS,
585 - &tottimeout)) == (CLIENT *) NULL) {
588 + if ((clnt = create_client(name_or_addr, SM_PROG, SM_VERS, NULL,
589 + &tottimeout)) == NULL) {
586 590 return (-1);
587 591 }
588 592
589 593 /* Perform notification to client */
590 594 rc = 0;
591 595 clnt_stat = clnt_call(clnt, SM_NOTIFY, xdr_stat_chge, (char *)&ntf,
592 596 xdr_void, NULL, tottimeout);
593 597 if (debug) {
594 598 (void) printf("clnt_stat=%s(%d)\n",
595 599 clnt_sperrno(clnt_stat), clnt_stat);
596 600 }
597 601 if (clnt_stat != (int)RPC_SUCCESS) {
598 602 syslog(LOG_WARNING,
599 603 "statd: cannot talk to statd at %s, %s(%d)\n",
600 604 name_or_addr, clnt_sperrno(clnt_stat), clnt_stat);
601 605 rc = -1;
602 606 }
603 607
604 608 /* For HA systems and multi-homed hosts */
605 609 ntf.state = LOCAL_STATE;
606 610 for (i = 0; i < addrix; i++) {
607 611 ntf.mon_name = host_name[i];
608 612 if (debug)
609 613 (void) printf("statd_call_statd at %s\n", name_or_addr);
610 614 clnt_stat = clnt_call(clnt, SM_NOTIFY, xdr_stat_chge,
611 615 (char *)&ntf, xdr_void, NULL,
612 616 tottimeout);
613 617 if (clnt_stat != (int)RPC_SUCCESS) {
614 618 syslog(LOG_WARNING,
615 619 "statd: cannot talk to statd at %s, %s(%d)\n",
616 620 name_or_addr, clnt_sperrno(clnt_stat), clnt_stat);
617 621 rc = -1;
618 622 }
619 623 }
620 624 clnt_destroy(clnt);
621 625 return (rc);
622 626 }
623 627
624 628 /*
625 629 * Continues to contact hosts in recovery table that were unreachable.
626 630 * NOTE: There should only be one sm_try thread executing and
627 631 * thus locks are not needed for recovery table. Die is only cleared
628 632 * after all the hosts has at least been contacted once. The reader/writer
629 633 * lock ensures to finish this code before an sm_crash is started. Die
630 634 * variable will signal it.
631 635 */
632 636 void *
633 637 sm_try()
634 638 {
635 639 name_entry *nl, *next;
636 640 timestruc_t wtime;
637 641 int delay = 0;
638 642
639 643 rw_rdlock(&thr_rwlock);
640 644 if (mutex_trylock(&sm_trylock))
641 645 goto out;
642 646 mutex_lock(&crash_lock);
643 647
644 648 while (!die) {
645 649 wtime.tv_sec = delay;
646 650 wtime.tv_nsec = 0;
647 651 /*
648 652 * Wait until signalled to wakeup or time expired.
649 653 * If signalled to be awoken, then a crash has occurred
650 654 * or otherwise time expired.
651 655 */
652 656 if (cond_reltimedwait(&retrywait, &crash_lock, &wtime) == 0) {
653 657 break;
654 658 }
655 659
656 660 /* Exit loop if queue is empty */
657 661 if ((next = recov_q.sm_recovhdp) == NULL)
658 662 break;
659 663
660 664 mutex_unlock(&crash_lock);
661 665
662 666 while (((nl = next) != (name_entry *)NULL) && (!die)) {
663 667 next = next->nxt;
664 668 if (statd_call_statd(nl->name) == 0) {
665 669 /* remove name from BACKUP */
666 670 remove_name(nl->name, 1, 0);
667 671 mutex_lock(&recov_q.lock);
668 672 /* remove entry from recovery_q */
669 673 delete_name(&recov_q.sm_recovhdp, nl->name);
670 674 mutex_unlock(&recov_q.lock);
671 675 } else {
672 676 /*
673 677 * Print message only once since unreachable
674 678 * host can be contacted forever.
675 679 */
676 680 if (delay == 0)
677 681 syslog(LOG_WARNING,
678 682 "statd: host %s is not responding\n",
679 683 nl->name);
680 684 }
681 685 }
682 686 /*
683 687 * Increment the amount of delay before restarting again.
684 688 * The amount of delay should not exceed the MAX_DELAYTIME.
685 689 */
686 690 if (delay <= MAX_DELAYTIME)
687 691 delay += INC_DELAYTIME;
688 692 mutex_lock(&crash_lock);
689 693 }
690 694
691 695 mutex_unlock(&crash_lock);
692 696 mutex_unlock(&sm_trylock);
693 697 out:
694 698 rw_unlock(&thr_rwlock);
695 699 if (debug)
696 700 (void) printf("EXITING sm_try\n");
697 701 thr_exit((void *) 0);
698 702 #ifdef lint
699 703 return (0);
700 704 #endif
701 705 }
702 706
703 707 /*
704 708 * Malloc's space and returns the ptr to malloc'ed space. NULL if unsuccessful.
705 709 */
706 710 char *
707 711 xmalloc(len)
708 712 unsigned len;
709 713 {
710 714 char *new;
711 715
712 716 if ((new = malloc(len)) == 0) {
713 717 syslog(LOG_ERR, "statd: malloc, error %m\n");
714 718 return ((char *)NULL);
715 719 } else {
716 720 (void) memset(new, 0, len);
717 721 return (new);
718 722 }
719 723 }
720 724
721 725 /*
722 726 * the following two routines are very similar to
723 727 * insert_mon and delete_mon in sm_proc.c, except the structture
724 728 * is different
725 729 */
726 730 static name_entry *
727 731 insert_name(namepp, name, need_alloc)
728 732 name_entry **namepp;
729 733 char *name;
730 734 int need_alloc;
731 735 {
732 736 name_entry *new;
733 737
734 738 new = (name_entry *)xmalloc(sizeof (name_entry));
735 739 if (new == (name_entry *) NULL)
736 740 return (NULL);
737 741
738 742 /* Allocate name when needed which is only when adding to record_t */
739 743 if (need_alloc) {
740 744 if ((new->name = strdup(name)) == (char *)NULL) {
741 745 syslog(LOG_ERR, "statd: strdup, error %m\n");
742 746 free(new);
743 747 return (NULL);
744 748 }
745 749 } else
746 750 new->name = name;
747 751
748 752 new->nxt = *namepp;
749 753 if (new->nxt != (name_entry *)NULL)
750 754 new->nxt->prev = new;
751 755
752 756 new->prev = (name_entry *) NULL;
753 757
754 758 *namepp = new;
755 759 if (debug) {
756 760 (void) printf("insert_name: inserted %s at %p\n",
757 761 name, (void *)namepp);
758 762 }
759 763
760 764 return (new);
761 765 }
762 766
763 767 /*
764 768 * Deletes name from specified list (namepp).
765 769 */
766 770 static void
767 771 delete_name(namepp, name)
768 772 name_entry **namepp;
769 773 char *name;
770 774 {
771 775 name_entry *nl;
772 776
773 777 nl = *namepp;
774 778 while (nl != (name_entry *)NULL) {
775 779 if (str_cmp_address_specifier(nl->name, name) == 0 ||
776 780 str_cmp_unqual_hostname(nl->name, name) == 0) {
777 781 if (nl->prev != (name_entry *)NULL)
778 782 nl->prev->nxt = nl->nxt;
779 783 else
780 784 *namepp = nl->nxt;
781 785 if (nl->nxt != (name_entry *)NULL)
782 786 nl->nxt->prev = nl->prev;
783 787 free(nl->name);
784 788 free(nl);
785 789 return;
786 790 }
787 791 nl = nl->nxt;
788 792 }
789 793 }
790 794
791 795 /*
792 796 * Finds name from specified list (namep).
793 797 */
794 798 static name_entry *
795 799 find_name(namep, name)
796 800 name_entry **namep;
797 801 char *name;
798 802 {
799 803 name_entry *nl;
800 804
801 805 nl = *namep;
802 806
803 807 while (nl != (name_entry *)NULL) {
804 808 if (str_cmp_unqual_hostname(nl->name, name) == 0) {
805 809 return (nl);
806 810 }
807 811 nl = nl->nxt;
808 812 }
809 813 return ((name_entry *)NULL);
810 814 }
811 815
812 816 /*
813 817 * Creates a file.
814 818 */
815 819
816 820 int
817 821 create_file(name)
818 822 char *name;
819 823 {
820 824 int fd;
821 825
822 826 /*
823 827 * The file might already exist. If it does, we ask for only write
824 828 * permission, since that's all the file was created with.
825 829 */
826 830 if ((fd = open(name, O_CREAT | O_WRONLY, S_IWUSR)) == -1) {
827 831 if (errno != EEXIST) {
828 832 syslog(LOG_ERR, "can't open %s: %m", name);
829 833 return (1);
830 834 }
831 835 }
832 836
833 837 if (debug >= 2)
834 838 (void) printf("%s is created\n", name);
835 839 if (close(fd)) {
836 840 syslog(LOG_ERR, "statd: close, error %m\n");
837 841 return (1);
838 842 }
839 843
840 844 return (0);
841 845 }
842 846
843 847 /*
844 848 * Deletes the file specified by name.
845 849 */
846 850 void
847 851 delete_file(name)
848 852 char *name;
849 853 {
850 854 if (debug >= 2)
851 855 (void) printf("Remove monitor entry %s\n", name);
852 856 if (unlink(name) == -1) {
853 857 if (errno != ENOENT)
854 858 syslog(LOG_ERR, "statd: unlink of %s, error %m", name);
855 859 }
856 860 }
857 861
858 862 /*
859 863 * Return 1 if file is a symlink, else 0.
860 864 */
861 865 int
862 866 is_symlink(file)
863 867 char *file;
864 868 {
865 869 int error;
866 870 struct stat lbuf;
867 871
868 872 do {
869 873 bzero((caddr_t)&lbuf, sizeof (lbuf));
870 874 error = lstat(file, &lbuf);
871 875 } while (error == EINTR);
872 876
873 877 if (error == 0) {
874 878 return ((lbuf.st_mode & S_IFMT) == S_IFLNK);
875 879 }
876 880
877 881 return (0);
878 882 }
879 883
880 884 /*
881 885 * Moves the file specified by `from' to `to' only if the
882 886 * new file is guaranteed to be created (which is presumably
883 887 * why we don't just do a rename(2)). If `from' is a
884 888 * symlink, the destination file will be a similar symlink
885 889 * in the directory of `to'.
886 890 *
887 891 * Returns 0 for success, 1 for failure.
888 892 */
889 893 static int
890 894 move_file(fromdir, file, todir)
891 895 char *fromdir;
892 896 char *file;
893 897 char *todir;
894 898 {
895 899 int n;
896 900 char rname[MAXNAMELEN + 1]; /* +1 for the terminating NULL */
897 901 char from[MAXPATHLEN];
898 902 char to[MAXPATHLEN];
899 903
900 904 (void) strcpy(from, fromdir);
901 905 (void) strcat(from, "/");
902 906 (void) strcat(from, file);
903 907 if (is_symlink(from)) {
904 908 /*
905 909 * Dig out the name of the regular file the link points to.
906 910 */
907 911 n = readlink(from, rname, MAXNAMELEN);
908 912 if (n <= 0) {
909 913 if (debug >= 2) {
910 914 (void) printf("move_file: can't read link %s\n",
911 915 from);
912 916 }
913 917 return (1);
914 918 }
915 919 rname[n] = '\0';
916 920
917 921 /*
918 922 * Create the link.
919 923 */
920 924 if (create_symlink(todir, rname, file) != 0) {
921 925 return (1);
922 926 }
923 927 } else {
924 928 /*
925 929 * Do what we've always done to move regular files.
926 930 */
927 931 (void) strcpy(to, todir);
928 932 (void) strcat(to, "/");
929 933 (void) strcat(to, file);
930 934 if (create_file(to) != 0) {
931 935 return (1);
932 936 }
933 937 }
934 938
935 939 /*
936 940 * Remove the old file if we've created the new one.
937 941 */
938 942 if (unlink(from) < 0) {
939 943 syslog(LOG_ERR, "move_file: unlink of %s, error %m", from);
940 944 return (1);
941 945 }
942 946
943 947 return (0);
944 948 }
945 949
946 950 /*
947 951 * Create a symbolic link named `lname' to regular file `rname'.
948 952 * Both files should be in directory `todir'.
949 953 */
950 954 int
951 955 create_symlink(todir, rname, lname)
952 956 char *todir;
953 957 char *rname;
954 958 char *lname;
955 959 {
956 960 int error;
957 961 char lpath[MAXPATHLEN];
958 962
959 963 /*
960 964 * Form the full pathname of the link.
961 965 */
962 966 (void) strcpy(lpath, todir);
963 967 (void) strcat(lpath, "/");
964 968 (void) strcat(lpath, lname);
965 969
966 970 /*
967 971 * Now make the new symlink ...
968 972 */
969 973 if (symlink(rname, lpath) < 0) {
970 974 error = errno;
971 975 if (error != 0 && error != EEXIST) {
972 976 if (debug >= 2) {
973 977 (void) printf(
974 978 "create_symlink: can't link %s/%s -> %s\n",
975 979 todir, lname, rname);
976 980 }
977 981 return (1);
978 982 }
979 983 }
980 984
981 985 if (debug) {
982 986 if (error == EEXIST) {
983 987 (void) printf("link %s/%s -> %s already exists\n",
984 988 todir, lname, rname);
985 989 } else {
986 990 (void) printf("created link %s/%s -> %s\n",
987 991 todir, lname, rname);
988 992 }
989 993 }
990 994
991 995 return (0);
992 996 }
993 997
994 998 /*
995 999 * remove the name from the specified directory
996 1000 * op = 0: CURRENT
997 1001 * op = 1: BACKUP
998 1002 */
999 1003 static void
1000 1004 remove_name(char *name, int op, int startup)
1001 1005 {
1002 1006 int i;
1003 1007 char *alt_dir;
1004 1008 char *queue;
1005 1009
1006 1010 if (op == 0) {
1007 1011 alt_dir = "statmon/sm";
1008 1012 queue = CURRENT;
1009 1013 } else {
1010 1014 alt_dir = "statmon/sm.bak";
1011 1015 queue = BACKUP;
1012 1016 }
1013 1017
1014 1018 remove_single_name(name, queue, NULL);
1015 1019 /*
1016 1020 * At startup, entries have not yet been copied to alternate
1017 1021 * directories and thus do not need to be removed.
1018 1022 */
1019 1023 if (startup == 0) {
1020 1024 for (i = 0; i < pathix; i++) {
1021 1025 remove_single_name(name, path_name[i], alt_dir);
1022 1026 }
1023 1027 }
1024 1028 }
1025 1029
1026 1030 /*
1027 1031 * Remove the name from the specified directory, which is dir1/dir2 or
1028 1032 * dir1, depending on whether dir2 is NULL.
1029 1033 */
1030 1034 static void
1031 1035 remove_single_name(char *name, char *dir1, char *dir2)
1032 1036 {
1033 1037 int n, error;
1034 1038 char path[MAXPATHLEN+MAXNAMELEN+SM_MAXPATHLEN]; /* why > MAXPATHLEN? */
1035 1039 char dirpath[MAXPATHLEN];
1036 1040 char rname[MAXNAMELEN + 1]; /* +1 for NULL term */
1037 1041
1038 1042 if (strlen(name) + strlen(dir1) + (dir2 != NULL ? strlen(dir2) : 0)
1039 1043 + 3 > MAXPATHLEN) {
1040 1044 if (dir2 != NULL)
1041 1045 syslog(LOG_ERR,
1042 1046 "statd: pathname too long: %s/%s/%s\n",
1043 1047 dir1, dir2, name);
1044 1048 else
1045 1049 syslog(LOG_ERR,
1046 1050 "statd: pathname too long: %s/%s\n",
1047 1051 dir1, name);
1048 1052
1049 1053 return;
1050 1054 }
1051 1055
1052 1056 (void) strcpy(path, dir1);
1053 1057 (void) strcat(path, "/");
1054 1058 if (dir2 != NULL) {
1055 1059 (void) strcat(path, dir2);
1056 1060 (void) strcat(path, "/");
1057 1061 }
1058 1062 (void) strcpy(dirpath, path); /* save here - we may need it shortly */
1059 1063 (void) strcat(path, name);
1060 1064
1061 1065 /*
1062 1066 * Despite the name of this routine :-@), `path' may be a symlink
1063 1067 * to a regular file. If it is, and if that file has no other
1064 1068 * links to it, we must remove it now as well.
1065 1069 */
1066 1070 if (is_symlink(path)) {
1067 1071 n = readlink(path, rname, MAXNAMELEN);
1068 1072 if (n > 0) {
1069 1073 rname[n] = '\0';
1070 1074
1071 1075 if (count_symlinks(dirpath, rname, &n) < 0) {
1072 1076 return;
1073 1077 }
1074 1078
1075 1079 if (n == 1) {
1076 1080 (void) strcat(dirpath, rname);
1077 1081 error = unlink(dirpath);
1078 1082 if (debug >= 2) {
1079 1083 if (error < 0) {
1080 1084 (void) printf(
1081 1085 "remove_name: can't unlink %s\n",
1082 1086 dirpath);
1083 1087 } else {
1084 1088 (void) printf(
1085 1089 "remove_name: unlinked %s\n",
1086 1090 dirpath);
1087 1091 }
1088 1092 }
1089 1093 }
1090 1094 } else {
1091 1095 /*
1092 1096 * Policy: if we can't read the symlink, leave it
1093 1097 * here for analysis by the system administrator.
1094 1098 */
1095 1099 syslog(LOG_ERR,
1096 1100 "statd: can't read link %s: %m\n", path);
1097 1101 }
1098 1102 }
1099 1103
1100 1104 /*
1101 1105 * If it's a regular file, we can assume all symlinks and the
1102 1106 * files to which they refer have been processed already - just
1103 1107 * fall through to here to remove it.
1104 1108 */
1105 1109 delete_file(path);
1106 1110 }
1107 1111
1108 1112 /*
1109 1113 * Count the number of symlinks in `dir' which point to `name' (also in dir).
1110 1114 * Passes back symlink count in `count'.
1111 1115 * Returns 0 for success, < 0 for failure.
1112 1116 */
1113 1117 static int
1114 1118 count_symlinks(char *dir, char *name, int *count)
1115 1119 {
1116 1120 int cnt = 0;
1117 1121 int n;
1118 1122 DIR *dp;
1119 1123 struct dirent *dirp;
1120 1124 char lpath[MAXPATHLEN];
1121 1125 char rname[MAXNAMELEN + 1]; /* +1 for term NULL */
1122 1126
1123 1127 if ((dp = opendir(dir)) == (DIR *)NULL) {
1124 1128 syslog(LOG_ERR, "count_symlinks: open %s dir, error %m\n",
1125 1129 dir);
1126 1130 return (-1);
1127 1131 }
1128 1132
1129 1133 while ((dirp = readdir(dp)) != NULL) {
1130 1134 if (strcmp(dirp->d_name, ".") == 0 ||
1131 1135 strcmp(dirp->d_name, "..") == 0) {
1132 1136 continue;
1133 1137 }
1134 1138
1135 1139 (void) sprintf(lpath, "%s%s", dir, dirp->d_name);
1136 1140 if (is_symlink(lpath)) {
1137 1141 /*
1138 1142 * Fetch the name of the file the symlink refers to.
1139 1143 */
1140 1144 n = readlink(lpath, rname, MAXNAMELEN);
1141 1145 if (n <= 0) {
1142 1146 if (debug >= 2) {
1143 1147 (void) printf(
1144 1148 "count_symlinks: can't read link %s\n",
1145 1149 lpath);
1146 1150 }
1147 1151 continue;
1148 1152 }
1149 1153 rname[n] = '\0';
1150 1154
1151 1155 /*
1152 1156 * If `rname' matches `name', bump the count. There
1153 1157 * may well be multiple symlinks to the same name, so
1154 1158 * we must continue to process the entire directory.
1155 1159 */
1156 1160 if (strcmp(rname, name) == 0) {
1157 1161 cnt++;
1158 1162 }
1159 1163 }
1160 1164 }
1161 1165
1162 1166 (void) closedir(dp);
1163 1167
1164 1168 if (debug) {
1165 1169 (void) printf("count_symlinks: found %d symlinks\n", cnt);
1166 1170 }
1167 1171 *count = cnt;
1168 1172 return (0);
1169 1173 }
1170 1174
1171 1175 /*
1172 1176 * Manage the cache of hostnames. An entry for each host that has recently
1173 1177 * locked a file is kept. There is an in-ram table (rec_table) and an empty
1174 1178 * file in the file system name space (/var/statmon/sm/<name>). This
1175 1179 * routine adds (deletes) the name to (from) the in-ram table and the entry
1176 1180 * to (from) the file system name space.
1177 1181 *
1178 1182 * If op == 1 then the name is added to the queue otherwise the name is
1179 1183 * deleted.
1180 1184 */
1181 1185 void
1182 1186 record_name(name, op)
1183 1187 char *name;
1184 1188 int op;
1185 1189 {
1186 1190 name_entry *nl;
1187 1191 int i;
1188 1192 char path[MAXPATHLEN+MAXNAMELEN+SM_MAXPATHLEN];
1189 1193 name_entry **record_q;
1190 1194 unsigned int hash;
1191 1195
1192 1196 /*
1193 1197 * These names are supposed to be just host names, not paths or
1194 1198 * other arbitrary files.
1195 1199 * manipulating the empty pathname unlinks CURRENT,
1196 1200 * manipulating files with '/' would allow you to create and unlink
1197 1201 * files all over the system; LOG_AUTH, it's a security thing.
1198 1202 * Don't remove the directories . and ..
1199 1203 */
1200 1204 if (name == NULL)
1201 1205 return;
1202 1206
1203 1207 if (name[0] == '\0' || strchr(name, '/') != NULL ||
1204 1208 strcmp(name, ".") == 0 || strcmp(name, "..") == 0) {
1205 1209 syslog(LOG_ERR|LOG_AUTH, "statd: attempt to %s \"%s/%s\"",
1206 1210 op == 1 ? "create" : "remove", CURRENT, name);
1207 1211 return;
1208 1212 }
1209 1213
1210 1214 SMHASH(name, hash);
1211 1215 if (debug) {
1212 1216 if (op == 1)
1213 1217 (void) printf("inserting %s at hash %d,\n",
1214 1218 name, hash);
1215 1219 else
1216 1220 (void) printf("deleting %s at hash %d\n", name, hash);
1217 1221 pr_name(name, 1);
1218 1222 }
1219 1223
1220 1224
1221 1225 if (op == 1) { /* insert */
1222 1226 mutex_lock(&record_table[hash].lock);
1223 1227 record_q = &record_table[hash].sm_rechdp;
1224 1228 if ((nl = find_name(record_q, name)) == (name_entry *)NULL) {
1225 1229
1226 1230 int path_len;
1227 1231
1228 1232 if ((nl = insert_name(record_q, name, 1)) !=
1229 1233 (name_entry *) NULL)
1230 1234 nl->count++;
1231 1235 mutex_unlock(&record_table[hash].lock);
1232 1236 /* make an entry in current directory */
1233 1237
1234 1238 path_len = strlen(CURRENT) + strlen(name) + 2;
1235 1239 if (path_len > MAXPATHLEN) {
1236 1240 syslog(LOG_ERR,
1237 1241 "statd: pathname too long: %s/%s\n",
1238 1242 CURRENT, name);
1239 1243 return;
1240 1244 }
1241 1245 (void) strcpy(path, CURRENT);
1242 1246 (void) strcat(path, "/");
1243 1247 (void) strcat(path, name);
1244 1248 (void) create_file(path);
1245 1249 if (debug) {
1246 1250 (void) printf("After insert_name\n");
1247 1251 pr_name(name, 1);
1248 1252 }
1249 1253 /* make an entry in alternate paths */
1250 1254 for (i = 0; i < pathix; i++) {
1251 1255 path_len = strlen(path_name[i]) +
1252 1256 strlen("/statmon/sm/") +
1253 1257 strlen(name) + 1;
1254 1258
1255 1259 if (path_len > MAXPATHLEN) {
1256 1260 syslog(LOG_ERR,
1257 1261 "statd: pathname too long: %s/statmon/sm/%s\n",
1258 1262 path_name[i], name);
1259 1263 continue;
1260 1264 }
1261 1265 (void) strcpy(path, path_name[i]);
1262 1266 (void) strcat(path, "/statmon/sm/");
1263 1267 (void) strcat(path, name);
1264 1268 (void) create_file(path);
1265 1269 }
1266 1270 return;
1267 1271 }
1268 1272 nl->count++;
1269 1273 mutex_unlock(&record_table[hash].lock);
1270 1274
1271 1275 } else { /* delete */
1272 1276 mutex_lock(&record_table[hash].lock);
1273 1277 record_q = &record_table[hash].sm_rechdp;
1274 1278 if ((nl = find_name(record_q, name)) == (name_entry *)NULL) {
1275 1279 mutex_unlock(&record_table[hash].lock);
1276 1280 return;
1277 1281 }
1278 1282 nl->count--;
1279 1283 if (nl->count == 0) {
1280 1284 delete_name(record_q, name);
1281 1285 mutex_unlock(&record_table[hash].lock);
1282 1286 /* remove this entry from current directory */
1283 1287 remove_name(name, 0, 0);
1284 1288 } else
1285 1289 mutex_unlock(&record_table[hash].lock);
1286 1290 if (debug) {
1287 1291 (void) printf("After delete_name \n");
1288 1292 pr_name(name, 1);
1289 1293 }
1290 1294 }
1291 1295 }
1292 1296
1293 1297 /*
1294 1298 * This routine adds a symlink in the form of an ASCII dotted quad
1295 1299 * IP address that is linked to the name already recorded in the
1296 1300 * filesystem name space by record_name(). Enough information is
1297 1301 * (hopefully) provided to support other address types in the future.
1298 1302 * The purpose of this is to cache enough information to contact
1299 1303 * hosts in other domains during server crash recovery (see bugid
1300 1304 * 1184192).
1301 1305 *
1302 1306 * The worst failure mode here is that the symlink is not made, and
1303 1307 * statd falls back to the old buggy behavior.
1304 1308 */
1305 1309 void
1306 1310 record_addr(char *name, sa_family_t family, struct netobj *ah)
1307 1311 {
1308 1312 int i;
1309 1313 int path_len;
1310 1314 char *famstr;
1311 1315 struct in_addr addr;
1312 1316 char *addr6;
1313 1317 char ascii_addr[MAXNAMELEN];
1314 1318 char path[MAXPATHLEN];
1315 1319
1316 1320 if (family == AF_INET) {
1317 1321 if (ah->n_len != sizeof (struct in_addr))
1318 1322 return;
1319 1323 addr = *(struct in_addr *)ah->n_bytes;
1320 1324 } else if (family == AF_INET6) {
1321 1325 if (ah->n_len != sizeof (struct in6_addr))
1322 1326 return;
1323 1327 addr6 = (char *)ah->n_bytes;
1324 1328 } else
1325 1329 return;
1326 1330
1327 1331 if (debug) {
1328 1332 if (family == AF_INET)
1329 1333 (void) printf("record_addr: addr= %x\n", addr.s_addr);
1330 1334 else if (family == AF_INET6)
1331 1335 (void) printf("record_addr: addr= %x\n", \
1332 1336 ((struct in6_addr *)addr6)->s6_addr);
1333 1337 }
1334 1338
1335 1339 if (family == AF_INET) {
1336 1340 if (addr.s_addr == INADDR_ANY ||
1337 1341 ((addr.s_addr && 0xff000000) == 0)) {
1338 1342 syslog(LOG_DEBUG,
1339 1343 "record_addr: illegal IP address %x\n",
1340 1344 addr.s_addr);
1341 1345 return;
1342 1346 }
1343 1347 }
1344 1348
1345 1349 /* convert address to ASCII */
1346 1350 famstr = family2string(family);
1347 1351 if (famstr == NULL) {
1348 1352 syslog(LOG_DEBUG,
1349 1353 "record_addr: unsupported address family %d\n",
1350 1354 family);
1351 1355 return;
1352 1356 }
1353 1357
1354 1358 switch (family) {
1355 1359 char abuf[INET6_ADDRSTRLEN];
1356 1360 case AF_INET:
1357 1361 (void) sprintf(ascii_addr, "%s.%s", famstr, inet_ntoa(addr));
1358 1362 break;
1359 1363
1360 1364 case AF_INET6:
1361 1365 (void) sprintf(ascii_addr, "%s.%s", famstr,\
1362 1366 inet_ntop(family, addr6, abuf, sizeof (abuf)));
1363 1367 break;
1364 1368
1365 1369 default:
1366 1370 if (debug) {
1367 1371 (void) printf(
1368 1372 "record_addr: family2string supports unknown family %d (%s)\n",
1369 1373 family,
1370 1374 famstr);
1371 1375 }
1372 1376 free(famstr);
1373 1377 return;
1374 1378 }
1375 1379
1376 1380 if (debug) {
1377 1381 (void) printf("record_addr: ascii_addr= %s\n", ascii_addr);
1378 1382 }
1379 1383 free(famstr);
1380 1384
1381 1385 /*
1382 1386 * Make the symlink in CURRENT. The `name' file should have
1383 1387 * been created previously by record_name().
1384 1388 */
1385 1389 (void) create_symlink(CURRENT, name, ascii_addr);
1386 1390
1387 1391 /*
1388 1392 * Similarly for alternate paths.
1389 1393 */
1390 1394 for (i = 0; i < pathix; i++) {
1391 1395 path_len = strlen(path_name[i]) +
1392 1396 strlen("/statmon/sm/") +
1393 1397 strlen(name) + 1;
1394 1398
1395 1399 if (path_len > MAXPATHLEN) {
1396 1400 syslog(LOG_ERR,
1397 1401 "statd: pathname too long: %s/statmon/sm/%s\n",
1398 1402 path_name[i], name);
1399 1403 continue;
1400 1404 }
1401 1405 (void) strcpy(path, path_name[i]);
1402 1406 (void) strcat(path, "/statmon/sm");
1403 1407 (void) create_symlink(path, name, ascii_addr);
1404 1408 }
1405 1409 }
1406 1410
1407 1411 /*
1408 1412 * SM_CRASH - simulate a crash of statd.
1409 1413 */
1410 1414 void
1411 1415 sm_crash()
1412 1416 {
1413 1417 name_entry *nl, *next;
1414 1418 mon_entry *nl_monp, *mon_next;
1415 1419 int k;
1416 1420 my_id *nl_idp;
1417 1421
1418 1422 for (k = 0; k < MAX_HASHSIZE; k++) {
1419 1423 mutex_lock(&mon_table[k].lock);
1420 1424 if ((mon_next = mon_table[k].sm_monhdp) ==
1421 1425 (mon_entry *) NULL) {
1422 1426 mutex_unlock(&mon_table[k].lock);
1423 1427 continue;
1424 1428 } else {
1425 1429 while ((nl_monp = mon_next) != (mon_entry *)NULL) {
1426 1430 mon_next = mon_next->nxt;
1427 1431 nl_idp = &nl_monp->id.mon_id.my_id;
1428 1432 free(nl_monp->id.mon_id.mon_name);
1429 1433 free(nl_idp->my_name);
1430 1434 free(nl_monp);
1431 1435 }
1432 1436 mon_table[k].sm_monhdp = (mon_entry *)NULL;
1433 1437 }
1434 1438 mutex_unlock(&mon_table[k].lock);
1435 1439 }
1436 1440
1437 1441 /* Clean up entries in record table */
1438 1442 for (k = 0; k < MAX_HASHSIZE; k++) {
1439 1443 mutex_lock(&record_table[k].lock);
1440 1444 if ((next = record_table[k].sm_rechdp) ==
1441 1445 (name_entry *) NULL) {
1442 1446 mutex_unlock(&record_table[k].lock);
1443 1447 continue;
1444 1448 } else {
1445 1449 while ((nl = next) != (name_entry *)NULL) {
1446 1450 next = next->nxt;
1447 1451 free(nl->name);
1448 1452 free(nl);
1449 1453 }
1450 1454 record_table[k].sm_rechdp = (name_entry *)NULL;
1451 1455 }
1452 1456 mutex_unlock(&record_table[k].lock);
1453 1457 }
1454 1458
1455 1459 /* Clean up entries in recovery table */
1456 1460 mutex_lock(&recov_q.lock);
1457 1461 if ((next = recov_q.sm_recovhdp) != (name_entry *)NULL) {
1458 1462 while ((nl = next) != (name_entry *)NULL) {
1459 1463 next = next->nxt;
1460 1464 free(nl->name);
1461 1465 free(nl);
1462 1466 }
1463 1467 recov_q.sm_recovhdp = (name_entry *)NULL;
1464 1468 }
1465 1469 mutex_unlock(&recov_q.lock);
1466 1470 statd_init();
1467 1471 }
1468 1472
1469 1473 /*
1470 1474 * Initialize the hash tables: mon_table, record_table, recov_q and
1471 1475 * locks.
1472 1476 */
1473 1477 void
1474 1478 sm_inithash()
1475 1479 {
1476 1480 int k;
1477 1481
1478 1482 if (debug)
1479 1483 (void) printf("Initializing hash tables\n");
1480 1484 for (k = 0; k < MAX_HASHSIZE; k++) {
1481 1485 mon_table[k].sm_monhdp = (mon_entry *)NULL;
1482 1486 record_table[k].sm_rechdp = (name_entry *)NULL;
1483 1487 mutex_init(&mon_table[k].lock, USYNC_THREAD, NULL);
1484 1488 mutex_init(&record_table[k].lock, USYNC_THREAD, NULL);
1485 1489 }
1486 1490 mutex_init(&recov_q.lock, USYNC_THREAD, NULL);
1487 1491 recov_q.sm_recovhdp = (name_entry *)NULL;
1488 1492
1489 1493 }
1490 1494
1491 1495 /*
1492 1496 * Maps a socket address family to a name string, or NULL if the family
1493 1497 * is not supported by statd.
1494 1498 * Caller is responsible for freeing storage used by result string, if any.
1495 1499 */
1496 1500 static char *
1497 1501 family2string(sa_family_t family)
1498 1502 {
1499 1503 char *rc;
1500 1504
1501 1505 switch (family) {
1502 1506 case AF_INET:
1503 1507 rc = strdup(SM_ADDR_IPV4);
1504 1508 break;
1505 1509
1506 1510 case AF_INET6:
1507 1511 rc = strdup(SM_ADDR_IPV6);
1508 1512 break;
1509 1513
1510 1514 default:
1511 1515 rc = NULL;
1512 1516 break;
1513 1517 }
1514 1518
1515 1519 return (rc);
1516 1520 }
1517 1521
1518 1522 /*
1519 1523 * Prints out list in record_table if flag is 1 otherwise
1520 1524 * prints out each list in recov_q specified by name.
1521 1525 */
1522 1526 static void
1523 1527 pr_name(name, flag)
1524 1528 char *name;
1525 1529 int flag;
1526 1530 {
1527 1531 name_entry *nl;
1528 1532 unsigned int hash;
1529 1533
1530 1534 if (!debug)
1531 1535 return;
1532 1536 if (flag) {
1533 1537 SMHASH(name, hash);
1534 1538 (void) printf("*****record_q: ");
1535 1539 mutex_lock(&record_table[hash].lock);
1536 1540 nl = record_table[hash].sm_rechdp;
1537 1541 while (nl != (name_entry *)NULL) {
1538 1542 (void) printf("(%x), ", (int)nl);
1539 1543 nl = nl->nxt;
1540 1544 }
1541 1545 mutex_unlock(&record_table[hash].lock);
1542 1546 } else {
1543 1547 (void) printf("*****recovery_q: ");
1544 1548 mutex_lock(&recov_q.lock);
1545 1549 nl = recov_q.sm_recovhdp;
1546 1550 while (nl != (name_entry *)NULL) {
1547 1551 (void) printf("(%x), ", (int)nl);
1548 1552 nl = nl->nxt;
1549 1553 }
1550 1554 mutex_unlock(&recov_q.lock);
1551 1555
1552 1556 }
1553 1557 (void) printf("\n");
1554 1558 }
↓ open down ↓ |
959 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX