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