Print this page
7569 statd support to run on a fixed port
Portions contributed by: Paul Dagnelie <pcd@delphix.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Sebastien Roy <sebastien.roy@delphix.com>
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/fs.d/nfs/statd/sm_svc.c
+++ new/usr/src/cmd/fs.d/nfs/statd/sm_svc.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 *
↓ open down ↓ |
12 lines elided |
↑ open up ↑ |
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 /*
23 - * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
24 23 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
24 + * Copyright (c) 2012, 2016 by Delphix. All rights reserved.
25 + * Copyright 2016 Nexenta Systems, Inc. All rights reserved.
25 26 */
26 27
27 28 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 29 /* All Rights Reserved */
29 30
30 31 /*
31 32 * University Copyright- Copyright (c) 1982, 1986, 1988
32 33 * The Regents of the University of California
33 34 * All Rights Reserved
34 35 *
35 36 * University Acknowledgment- Portions of this document are derived from
36 37 * software developed by the University of California, Berkeley, and its
37 38 * contributors.
38 39 */
39 40
40 -/*
41 - * Copyright (c) 2012 by Delphix. All rights reserved.
42 - */
43 -
44 41 #include <stdio.h>
45 42 #include <stdio_ext.h>
46 43 #include <stdlib.h>
47 44 #include <ftw.h>
48 45 #include <signal.h>
49 46 #include <string.h>
50 47 #include <syslog.h>
51 48 #include <netconfig.h>
49 +#include <netdir.h>
52 50 #include <unistd.h>
53 51 #include <netdb.h>
54 52 #include <rpc/rpc.h>
53 +#include <rpc/svc.h>
55 54 #include <netinet/in.h>
56 55 #include <sys/param.h>
57 56 #include <sys/resource.h>
58 57 #include <sys/file.h>
59 58 #include <sys/types.h>
60 59 #include <sys/stat.h>
61 60 #include <sys/sockio.h>
62 61 #include <dirent.h>
63 62 #include <errno.h>
64 63 #include <rpcsvc/sm_inter.h>
65 64 #include <rpcsvc/nsm_addr.h>
66 65 #include <thread.h>
67 66 #include <synch.h>
68 67 #include <net/if.h>
69 68 #include <limits.h>
70 69 #include <rpcsvc/daemon_utils.h>
71 70 #include <priv_utils.h>
71 +#include "smfcfg.h"
72 72 #include "sm_statd.h"
73 73
74 74
75 75 #define home0 "/var/statmon"
76 76 #define current0 "/var/statmon/sm"
77 77 #define backup0 "/var/statmon/sm.bak"
78 78 #define state0 "/var/statmon/state"
79 79
80 80 #define home1 "statmon"
81 81 #define current1 "statmon/sm/"
82 82 #define backup1 "statmon/sm.bak/"
83 83 #define state1 "statmon/state"
84 84
85 85 extern int daemonize_init(void);
86 86 extern void daemonize_fini(int fd);
87 87
88 88 /*
89 89 * User and group IDs to run as. These are hardwired, rather than looked
90 90 * up at runtime, because they are very unlikely to change and because they
91 91 * provide some protection against bogus changes to the passwd and group
↓ open down ↓ |
10 lines elided |
↑ open up ↑ |
92 92 * files.
93 93 */
94 94 uid_t daemon_uid = DAEMON_UID;
95 95 gid_t daemon_gid = DAEMON_GID;
96 96
97 97 char STATE[MAXPATHLEN], CURRENT[MAXPATHLEN], BACKUP[MAXPATHLEN];
98 98 static char statd_home[MAXPATHLEN];
99 99
100 100 int debug;
101 101 int regfiles_only = 0; /* 1 => use symlinks in statmon, 0 => don't */
102 +int statd_port = 0;
102 103 char hostname[MAXHOSTNAMELEN];
103 104
104 105 /*
105 106 * These variables will be used to store all the
106 107 * alias names for the host, as well as the -a
107 108 * command line hostnames.
108 109 */
109 110 int host_name_count;
110 111 char **host_name; /* store -a opts */
111 112 int addrix; /* # of -a entries */
112 113
113 114
114 115 /*
115 116 * The following 2 variables are meaningful
116 117 * only under a HA configuration.
117 118 * The path_name array is dynamically allocated in main() during
118 119 * command line argument processing for the -p options.
119 120 */
120 121 char **path_name = NULL; /* store -p opts */
121 122 int pathix = 0; /* # of -p entries */
122 123
123 124 /* Global variables. Refer to sm_statd.h for description */
124 125 mutex_t crash_lock;
125 126 int die;
126 127 int in_crash;
127 128 mutex_t sm_trylock;
128 129 rwlock_t thr_rwlock;
129 130 cond_t retrywait;
130 131 mutex_t name_addrlock;
131 132
132 133 mutex_t merges_lock;
133 134 cond_t merges_cond;
134 135 boolean_t in_merges;
135 136
136 137 /* forward references */
137 138 static void set_statmon_owner(void);
138 139 static void copy_client_names(void);
139 140 static void one_statmon_owner(const char *);
140 141 static int nftw_owner(const char *, const struct stat *, int, struct FTW *);
141 142
142 143 /*
143 144 * statd protocol
144 145 * commands:
145 146 * SM_STAT
146 147 * returns stat_fail to caller
147 148 * SM_MON
148 149 * adds an entry to the monitor_q and the record_q.
149 150 * This message is sent by the server lockd to the server
150 151 * statd, to indicate that a new client is to be monitored.
151 152 * It is also sent by the server lockd to the client statd
152 153 * to indicate that a new server is to be monitored.
153 154 * SM_UNMON
154 155 * removes an entry from the monitor_q and the record_q
155 156 * SM_UNMON_ALL
156 157 * removes all entries from a particular host from the
157 158 * monitor_q and the record_q. Our statd has this
158 159 * disabled.
159 160 * SM_SIMU_CRASH
160 161 * simulate a crash. Removes everything from the
161 162 * record_q and the recovery_q, then calls statd_init()
162 163 * to restart things. This message is sent by the server
163 164 * lockd to the server statd to have all clients notified
164 165 * that they should reclaim locks.
165 166 * SM_NOTIFY
166 167 * Sent by statd on server to statd on client during
167 168 * crash recovery. The client statd passes the info
168 169 * to its lockd so it can attempt to reclaim the locks
169 170 * held on the server.
170 171 *
171 172 * There are three main hash tables used to keep track of things.
172 173 * mon_table
173 174 * table that keeps track hosts statd must watch. If one of
174 175 * these hosts crashes, then any locks held by that host must
175 176 * be released.
176 177 * record_table
177 178 * used to keep track of all the hostname files stored in
178 179 * the directory /var/statmon/sm. These are client hosts who
179 180 * are holding or have held a lock at some point. Needed
180 181 * to determine if a file needs to be created for host in
181 182 * /var/statmon/sm.
182 183 * recov_q
183 184 * used to keep track hostnames during a recovery
184 185 *
185 186 * The entries are hashed based upon the name.
186 187 *
187 188 * There is a directory /var/statmon/sm which holds a file named
188 189 * for each host that is holding (or has held) a lock. This is
189 190 * used during initialization on startup, or after a simulated
190 191 * crash.
191 192 */
192 193
193 194 static void
194 195 sm_prog_1(struct svc_req *rqstp, SVCXPRT *transp)
195 196 {
196 197 union {
197 198 struct sm_name sm_stat_1_arg;
198 199 struct mon sm_mon_1_arg;
199 200 struct mon_id sm_unmon_1_arg;
200 201 struct my_id sm_unmon_all_1_arg;
201 202 struct stat_chge ntf_arg;
202 203 struct reg1args reg1_arg;
203 204 } argument;
204 205
205 206 union {
206 207 sm_stat_res stat_resp;
207 208 sm_stat mon_resp;
208 209 struct reg1res reg1_resp;
209 210 } result;
210 211
211 212 bool_t (*xdr_argument)(), (*xdr_result)();
212 213 char *(*local)();
213 214
214 215 /*
215 216 * Dispatch according to which protocol is being used:
216 217 * NSM_ADDR_PROGRAM is the private lockd address
217 218 * registration protocol.
218 219 * SM_PROG is the normal statd (NSM) protocol.
219 220 */
220 221 if (rqstp->rq_prog == NSM_ADDR_PROGRAM) {
221 222 switch (rqstp->rq_proc) {
222 223 case NULLPROC:
223 224 svc_sendreply(transp, xdr_void, (caddr_t)NULL);
224 225 return;
225 226
226 227 case NSMADDRPROC1_REG:
227 228 xdr_argument = xdr_reg1args;
228 229 xdr_result = xdr_reg1res;
229 230 local = (char *(*)()) nsmaddrproc1_reg;
230 231 break;
231 232
232 233 case NSMADDRPROC1_UNREG: /* Not impl. */
233 234 default:
234 235 svcerr_noproc(transp);
235 236 return;
236 237 }
237 238 } else {
238 239 /* Must be SM_PROG */
239 240 switch (rqstp->rq_proc) {
240 241 case NULLPROC:
241 242 svc_sendreply(transp, xdr_void, (caddr_t)NULL);
242 243 return;
243 244
244 245 case SM_STAT:
245 246 xdr_argument = xdr_sm_name;
246 247 xdr_result = xdr_sm_stat_res;
247 248 local = (char *(*)()) sm_stat_svc;
248 249 break;
249 250
250 251 case SM_MON:
251 252 xdr_argument = xdr_mon;
252 253 xdr_result = xdr_sm_stat_res;
253 254 local = (char *(*)()) sm_mon_svc;
254 255 break;
255 256
256 257 case SM_UNMON:
257 258 xdr_argument = xdr_mon_id;
258 259 xdr_result = xdr_sm_stat;
259 260 local = (char *(*)()) sm_unmon_svc;
260 261 break;
261 262
262 263 case SM_UNMON_ALL:
263 264 xdr_argument = xdr_my_id;
264 265 xdr_result = xdr_sm_stat;
265 266 local = (char *(*)()) sm_unmon_all_svc;
266 267 break;
267 268
268 269 case SM_SIMU_CRASH:
269 270 xdr_argument = xdr_void;
270 271 xdr_result = xdr_void;
271 272 local = (char *(*)()) sm_simu_crash_svc;
272 273 break;
273 274
274 275 case SM_NOTIFY:
275 276 xdr_argument = xdr_stat_chge;
276 277 xdr_result = xdr_void;
277 278 local = (char *(*)()) sm_notify_svc;
278 279 break;
279 280
280 281 default:
281 282 svcerr_noproc(transp);
282 283 return;
283 284 }
284 285 }
285 286
286 287 (void) memset(&argument, 0, sizeof (argument));
287 288 if (!svc_getargs(transp, xdr_argument, (caddr_t)&argument)) {
288 289 svcerr_decode(transp);
289 290 return;
290 291 }
291 292
292 293 (void) memset(&result, 0, sizeof (result));
293 294 (*local)(&argument, &result);
294 295 if (!svc_sendreply(transp, xdr_result, (caddr_t)&result)) {
295 296 svcerr_systemerr(transp);
296 297 }
297 298
298 299 if (!svc_freeargs(transp, xdr_argument, (caddr_t)&argument)) {
299 300 syslog(LOG_ERR, "statd: unable to free arguments\n");
300 301 }
301 302 }
302 303
303 304 /*
304 305 * Remove all files under directory path_dir.
305 306 */
306 307 static int
307 308 remove_dir(char *path_dir)
308 309 {
309 310 DIR *dp;
310 311 struct dirent *dirp;
311 312 char tmp_path[MAXPATHLEN];
312 313
313 314 if ((dp = opendir(path_dir)) == NULL) {
314 315 if (debug)
315 316 syslog(LOG_ERR,
316 317 "warning: open directory %s failed: %m\n",
317 318 path_dir);
318 319 return (1);
319 320 }
320 321
321 322 while ((dirp = readdir(dp)) != NULL) {
322 323 if (strcmp(dirp->d_name, ".") != 0 &&
323 324 strcmp(dirp->d_name, "..") != 0) {
324 325 if (strlen(path_dir) + strlen(dirp->d_name) +2 >
325 326 MAXPATHLEN) {
326 327
327 328 syslog(LOG_ERR, "statd: remove dir %s/%s "
328 329 "failed. Pathname too long.\n", path_dir,
329 330 dirp->d_name);
330 331
331 332 continue;
332 333 }
333 334 (void) strcpy(tmp_path, path_dir);
334 335 (void) strcat(tmp_path, "/");
335 336 (void) strcat(tmp_path, dirp->d_name);
336 337 delete_file(tmp_path);
337 338 }
338 339 }
339 340
340 341 (void) closedir(dp);
341 342 return (0);
342 343 }
343 344
344 345 /*
345 346 * Copy all files from directory `from_dir' to directory `to_dir'.
346 347 * Symlinks, if any, are preserved.
347 348 */
348 349 void
349 350 copydir_from_to(char *from_dir, char *to_dir)
350 351 {
351 352 int n;
352 353 DIR *dp;
353 354 struct dirent *dirp;
354 355 char rname[MAXNAMELEN + 1];
355 356 char path[MAXPATHLEN+MAXNAMELEN+2];
356 357
357 358 if ((dp = opendir(from_dir)) == NULL) {
358 359 if (debug)
359 360 syslog(LOG_ERR,
360 361 "warning: open directory %s failed: %m\n",
361 362 from_dir);
362 363 return;
363 364 }
364 365
365 366 while ((dirp = readdir(dp)) != NULL) {
366 367 if (strcmp(dirp->d_name, ".") == 0 ||
367 368 strcmp(dirp->d_name, "..") == 0) {
368 369 continue;
369 370 }
370 371
371 372 (void) strcpy(path, from_dir);
372 373 (void) strcat(path, "/");
373 374 (void) strcat(path, dirp->d_name);
374 375
375 376 if (is_symlink(path)) {
376 377 /*
377 378 * Follow the link to get the referenced file name
378 379 * and make a new link for that file in to_dir.
379 380 */
380 381 n = readlink(path, rname, MAXNAMELEN);
381 382 if (n <= 0) {
382 383 if (debug >= 2) {
383 384 (void) printf("copydir_from_to: can't "
384 385 "read link %s\n", path);
385 386 }
386 387 continue;
387 388 }
388 389 rname[n] = '\0';
389 390
390 391 (void) create_symlink(to_dir, rname, dirp->d_name);
391 392 } else {
392 393 /*
393 394 * Simply copy regular files to to_dir.
394 395 */
395 396 (void) strcpy(path, to_dir);
396 397 (void) strcat(path, "/");
397 398 (void) strcat(path, dirp->d_name);
398 399 (void) create_file(path);
399 400 }
400 401 }
401 402
402 403 (void) closedir(dp);
403 404 }
404 405
405 406 static int
406 407 init_hostname(void)
407 408 {
408 409 struct lifnum lifn;
409 410 int sock;
410 411
411 412 if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
412 413 syslog(LOG_ERR, "statd:init_hostname, socket: %m");
413 414 return (-1);
414 415 }
415 416
416 417 lifn.lifn_family = AF_UNSPEC;
417 418 lifn.lifn_flags = 0;
418 419
419 420 if (ioctl(sock, SIOCGLIFNUM, (char *)&lifn) < 0) {
420 421 syslog(LOG_ERR,
421 422 "statd:init_hostname, get number of interfaces, error: %m");
422 423 close(sock);
423 424 return (-1);
424 425 }
425 426
426 427 host_name_count = lifn.lifn_count;
427 428
428 429 host_name = malloc(host_name_count * sizeof (char *));
429 430 if (host_name == NULL) {
430 431 perror("statd -a can't get ip configuration\n");
431 432 close(sock);
432 433 return (-1);
433 434 }
434 435 close(sock);
435 436 return (0);
436 437 }
437 438
438 439 static void
439 440 thr_statd_merges(void)
440 441 {
441 442 /*
442 443 * Get other aliases from each interface.
443 444 */
444 445 merge_hosts();
445 446
446 447 /*
447 448 * Get all of the configured IP addresses.
448 449 */
449 450 merge_ips();
↓ open down ↓ |
338 lines elided |
↑ open up ↑ |
450 451
451 452 /*
452 453 * Notify the waiters.
453 454 */
454 455 (void) mutex_lock(&merges_lock);
455 456 in_merges = B_FALSE;
456 457 (void) cond_broadcast(&merges_cond);
457 458 (void) mutex_unlock(&merges_lock);
458 459 }
459 460
461 +/*
462 + * This function is called for each configured network type to
463 + * bind and register our RPC service programs.
464 + *
465 + * On TCP or UDP, we may want to bind SM_PROG on a specific port
466 + * (when statd_port is specified) in which case we'll use the
467 + * variant of svc_tp_create() that lets us pass a bind address.
468 + */
469 +static void
470 +sm_svc_tp_create(struct netconfig *nconf)
471 +{
472 + char port_str[8];
473 + struct nd_hostserv hs;
474 + struct nd_addrlist *al = NULL;
475 + SVCXPRT *xprt = NULL;
476 +
477 + /*
478 + * If statd_port is set and this is an inet transport,
479 + * bind this service on the specified port. The TLI way
480 + * to create such a bind address is netdir_getbyname()
481 + * with the special "host" HOST_SELF_BIND. This builds
482 + * an all-zeros IP address with the specified port.
483 + */
484 + if (statd_port != 0 &&
485 + (strcmp(nconf->nc_protofmly, NC_INET) == 0 ||
486 + strcmp(nconf->nc_protofmly, NC_INET6) == 0)) {
487 + int err;
488 +
489 + snprintf(port_str, sizeof (port_str), "%u",
490 + (unsigned short)statd_port);
491 +
492 + hs.h_host = HOST_SELF_BIND;
493 + hs.h_serv = port_str;
494 + err = netdir_getbyname((struct netconfig *)nconf, &hs, &al);
495 + if (err == 0 && al != NULL) {
496 + xprt = svc_tp_create_addr(sm_prog_1, SM_PROG, SM_VERS,
497 + nconf, al->n_addrs);
498 + netdir_free(al, ND_ADDRLIST);
499 + }
500 + if (xprt == NULL) {
501 + syslog(LOG_ERR, "statd: unable to create "
502 + "(SM_PROG, SM_VERS) on transport %s (port %d)",
503 + nconf->nc_netid, statd_port);
504 + }
505 + /* fall-back to default bind */
506 + }
507 + if (xprt == NULL) {
508 + /*
509 + * Had statd_port=0, or non-inet transport,
510 + * or the bind to a specific port failed.
511 + * Do a default bind.
512 + */
513 + xprt = svc_tp_create(sm_prog_1, SM_PROG, SM_VERS, nconf);
514 + }
515 + if (xprt == NULL) {
516 + syslog(LOG_ERR, "statd: unable to create "
517 + "(SM_PROG, SM_VERS) for transport %s",
518 + nconf->nc_netid);
519 + return;
520 + }
521 +
522 + /*
523 + * Also register the NSM_ADDR program on this
524 + * transport handle (same dispatch function).
525 + */
526 + if (!svc_reg(xprt, NSM_ADDR_PROGRAM, NSM_ADDR_V1, sm_prog_1, nconf)) {
527 + syslog(LOG_ERR, "statd: failed to register "
528 + "(NSM_ADDR_PROGRAM, NSM_ADDR_V1) for "
529 + "netconfig %s", nconf->nc_netid);
530 + }
531 +}
532 +
460 533 int
461 534 main(int argc, char *argv[])
462 535 {
463 536 int c;
464 537 int ppid;
465 538 extern char *optarg;
466 539 int choice = 0;
467 540 struct rlimit rl;
468 541 int mode;
469 542 int sz;
470 543 int pipe_fd = -1;
544 + int ret;
471 545 int connmaxrec = RPC_MAXDATASIZE;
546 + struct netconfig *nconf;
547 + NCONF_HANDLE *nc;
472 548
473 549 addrix = 0;
474 550 pathix = 0;
475 551
476 552 (void) gethostname(hostname, MAXHOSTNAMELEN);
477 553 if (init_hostname() < 0)
478 554 exit(1);
479 555
480 - while ((c = getopt(argc, argv, "Dd:a:G:p:rU:")) != EOF)
556 + ret = nfs_smf_get_iprop("statd_port", &statd_port,
557 + DEFAULT_INSTANCE, SCF_TYPE_INTEGER, STATD);
558 + if (ret != SA_OK) {
559 + syslog(LOG_ERR, "Reading of statd_port from SMF "
560 + "failed, using default value");
561 + }
562 +
563 + while ((c = getopt(argc, argv, "Dd:a:G:p:P:rU:")) != EOF)
481 564 switch (c) {
482 565 case 'd':
483 566 (void) sscanf(optarg, "%d", &debug);
484 567 break;
485 568 case 'D':
486 569 choice = 1;
487 570 break;
488 571 case 'a':
489 572 if (addrix < host_name_count) {
490 573 if (strcmp(hostname, optarg) != 0) {
491 574 sz = strlen(optarg);
492 575 if (sz < MAXHOSTNAMELEN) {
493 576 host_name[addrix] =
494 577 (char *)xmalloc(sz+1);
495 578 if (host_name[addrix] !=
496 579 NULL) {
497 580 (void) sscanf(optarg, "%s",
498 581 host_name[addrix]);
499 582 addrix++;
500 583 }
501 584 } else
502 585 (void) fprintf(stderr,
503 586 "statd: -a name of host is too long.\n");
504 587 }
505 588 } else
506 589 (void) fprintf(stderr,
507 590 "statd: -a exceeding maximum hostnames\n");
508 591 break;
509 592 case 'U':
510 593 (void) sscanf(optarg, "%d", &daemon_uid);
511 594 break;
512 595 case 'G':
513 596 (void) sscanf(optarg, "%d", &daemon_gid);
514 597 break;
515 598 case 'p':
516 599 if (strlen(optarg) < MAXPATHLEN) {
517 600 /* If the path_name array has not yet */
518 601 /* been malloc'ed, do that. The array */
519 602 /* should be big enough to hold all of the */
520 603 /* -p options we might have. An upper */
521 604 /* bound on the number of -p options is */
522 605 /* argc/2, because each -p option consumes */
523 606 /* two arguments. Here the upper bound */
524 607 /* is supposing that all the command line */
525 608 /* arguments are -p options, which would */
526 609 /* actually never be the case. */
527 610 if (path_name == NULL) {
528 611 size_t sz = (argc/2) * sizeof (char *);
529 612
530 613 path_name = (char **)malloc(sz);
531 614 if (path_name == NULL) {
↓ open down ↓ |
41 lines elided |
↑ open up ↑ |
532 615 (void) fprintf(stderr,
533 616 "statd: malloc failed\n");
534 617 exit(1);
535 618 }
536 619 (void) memset(path_name, 0, sz);
537 620 }
538 621 path_name[pathix] = optarg;
539 622 pathix++;
540 623 } else {
541 624 (void) fprintf(stderr,
542 - "statd: -p pathname is too long.\n");
625 + "statd: -p pathname is too long.\n");
543 626 }
544 627 break;
628 + case 'P':
629 + (void) sscanf(optarg, "%d", &statd_port);
630 + if (statd_port < 1 || statd_port > UINT16_MAX) {
631 + (void) fprintf(stderr,
632 + "statd: -P port invalid.\n");
633 + statd_port = 0;
634 + }
635 + break;
545 636 case 'r':
546 637 regfiles_only = 1;
547 638 break;
548 639 default:
549 640 (void) fprintf(stderr,
550 - "statd [-d level] [-D]\n");
641 + "statd [-d level] [-D]\n");
551 642 return (1);
552 643 }
553 644
554 645 if (choice == 0) {
555 646 (void) strcpy(statd_home, home0);
556 647 (void) strcpy(CURRENT, current0);
557 648 (void) strcpy(BACKUP, backup0);
558 649 (void) strcpy(STATE, state0);
559 650 } else {
560 651 (void) strcpy(statd_home, home1);
561 652 (void) strcpy(CURRENT, current1);
562 653 (void) strcpy(BACKUP, backup1);
563 654 (void) strcpy(STATE, state1);
564 655 }
565 656 if (debug)
566 657 (void) printf("debug is on, create entry: %s, %s, %s\n",
567 658 CURRENT, BACKUP, STATE);
568 659
569 660 if (getrlimit(RLIMIT_NOFILE, &rl))
570 661 (void) printf("statd: getrlimit failed. \n");
571 662
572 663 /* Set maxfdlimit current soft limit */
573 664 rl.rlim_cur = rl.rlim_max;
574 665 if (setrlimit(RLIMIT_NOFILE, &rl) != 0)
575 666 syslog(LOG_ERR, "statd: unable to set RLIMIT_NOFILE to %d\n",
576 667 rl.rlim_cur);
577 668
578 669 (void) enable_extended_FILE_stdio(-1, -1);
579 670
580 671 if (!debug) {
581 672 pipe_fd = daemonize_init();
582 673
583 674 openlog("statd", LOG_PID, LOG_DAEMON);
584 675 }
585 676
586 677 (void) _create_daemon_lock(STATD, daemon_uid, daemon_gid);
587 678 /*
588 679 * establish our lock on the lock file and write our pid to it.
589 680 * exit if some other process holds the lock, or if there's any
590 681 * error in writing/locking the file.
591 682 */
592 683 ppid = _enter_daemon_lock(STATD);
593 684 switch (ppid) {
594 685 case 0:
595 686 break;
596 687 case -1:
597 688 syslog(LOG_ERR, "error locking for %s: %s", STATD,
598 689 strerror(errno));
599 690 exit(2);
600 691 default:
601 692 /* daemon was already running */
602 693 exit(0);
603 694 }
604 695
605 696 mutex_init(&merges_lock, USYNC_THREAD, NULL);
606 697 cond_init(&merges_cond, USYNC_THREAD, NULL);
607 698 in_merges = B_TRUE;
608 699
609 700 /*
610 701 * Create thr_statd_merges() thread to populate the host_name list
611 702 * asynchronously.
612 703 */
613 704 if (thr_create(NULL, 0, (void *(*)(void *))thr_statd_merges, NULL,
614 705 THR_DETACHED, NULL) != 0) {
615 706 syslog(LOG_ERR, "statd: unable to create thread for "
616 707 "thr_statd_merges().");
617 708 exit(1);
618 709 }
619 710
620 711 /*
621 712 * Set to automatic mode such that threads are automatically
622 713 * created
623 714 */
624 715 mode = RPC_SVC_MT_AUTO;
625 716 if (!rpc_control(RPC_SVC_MTMODE_SET, &mode)) {
626 717 syslog(LOG_ERR,
627 718 "statd:unable to set automatic MT mode.");
628 719 exit(1);
↓ open down ↓ |
68 lines elided |
↑ open up ↑ |
629 720 }
630 721
631 722 /*
632 723 * Set non-blocking mode and maximum record size for
633 724 * connection oriented RPC transports.
634 725 */
635 726 if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &connmaxrec)) {
636 727 syslog(LOG_INFO, "unable to set maximum RPC record size");
637 728 }
638 729
639 - if (!svc_create(sm_prog_1, SM_PROG, SM_VERS, "netpath")) {
640 - syslog(LOG_ERR, "statd: unable to create (SM_PROG, SM_VERS) "
641 - "for netpath.");
642 - exit(1);
730 + /*
731 + * Enumerate network transports and create service listeners
732 + * as appropriate for each.
733 + */
734 + if ((nc = setnetconfig()) == NULL) {
735 + syslog(LOG_ERR, "setnetconfig failed: %m");
736 + return (-1);
643 737 }
738 + while ((nconf = getnetconfig(nc)) != NULL) {
644 739
645 - if (!svc_create(sm_prog_1, NSM_ADDR_PROGRAM, NSM_ADDR_V1, "netpath")) {
646 - syslog(LOG_ERR, "statd: unable to create (NSM_ADDR_PROGRAM, "
647 - "NSM_ADDR_V1) for netpath.");
740 + /*
741 + * Skip things like tpi_raw, invisible...
742 + */
743 + if ((nconf->nc_flag & NC_VISIBLE) == 0)
744 + continue;
745 + if (nconf->nc_semantics != NC_TPI_CLTS &&
746 + nconf->nc_semantics != NC_TPI_COTS &&
747 + nconf->nc_semantics != NC_TPI_COTS_ORD)
748 + continue;
749 +
750 + sm_svc_tp_create(nconf);
648 751 }
752 + (void) endnetconfig(nc);
649 753
650 754 /*
651 755 * Make sure /var/statmon and any alternate (-p) statmon
652 756 * directories exist and are owned by daemon. Then change our uid
653 757 * to daemon. The uid change is to prevent attacks against local
654 758 * daemons that trust any call from a local root process.
655 759 */
656 760
657 761 set_statmon_owner();
658 762
659 763 /*
660 764 *
661 765 * statd now runs as a daemon rather than root and can not
662 766 * dump core under / because of the permission. It is
663 767 * important that current working directory of statd be
664 768 * changed to writable directory /var/statmon so that it
665 769 * can dump the core upon the receipt of the signal.
666 770 * One still need to set allow_setid_core to non-zero in
667 771 * /etc/system to get the core dump.
668 772 *
669 773 */
670 774
671 775 if (chdir(statd_home) < 0) {
672 776 syslog(LOG_ERR, "can't chdir %s: %m", statd_home);
673 777 exit(1);
674 778 }
675 779
676 780 copy_client_names();
677 781
678 782 rwlock_init(&thr_rwlock, USYNC_THREAD, NULL);
679 783 mutex_init(&crash_lock, USYNC_THREAD, NULL);
680 784 mutex_init(&name_addrlock, USYNC_THREAD, NULL);
681 785 cond_init(&retrywait, USYNC_THREAD, NULL);
682 786 sm_inithash();
683 787 die = 0;
684 788 /*
685 789 * This variable is set to ensure that an sm_crash
686 790 * request will not be done at the same time
687 791 * when a statd_init is being done, since sm_crash
688 792 * can reset some variables that statd_init will be using.
689 793 */
690 794 in_crash = 1;
691 795 statd_init();
692 796
693 797 /*
694 798 * statd is up and running as far as we are concerned.
695 799 */
696 800 daemonize_fini(pipe_fd);
697 801
698 802 if (debug)
699 803 (void) printf("Starting svc_run\n");
700 804 svc_run();
701 805 syslog(LOG_ERR, "statd: svc_run returned\n");
702 806 /* NOTREACHED */
703 807 thr_exit((void *)1);
704 808 return (0);
705 809
706 810 }
707 811
708 812 /*
709 813 * Make sure the ownership of the statmon directories is correct, then
710 814 * change our uid to match. If the top-level directories (/var/statmon, -p
711 815 * arguments) don't exist, they are created first. The sm and sm.bak
712 816 * directories are not created here, but if they already exist, they are
713 817 * chowned to the correct uid, along with anything else in the
714 818 * directories.
715 819 */
716 820
717 821 static void
718 822 set_statmon_owner(void)
719 823 {
720 824 int i;
721 825 boolean_t can_do_mlp;
722 826
723 827 /*
724 828 * Recursively chown/chgrp /var/statmon and the alternate paths,
725 829 * creating them if necessary.
726 830 */
727 831 one_statmon_owner(statd_home);
728 832 for (i = 0; i < pathix; i++) {
729 833 char alt_path[MAXPATHLEN];
730 834
731 835 snprintf(alt_path, MAXPATHLEN, "%s/statmon", path_name[i]);
732 836 one_statmon_owner(alt_path);
733 837 }
734 838
735 839 can_do_mlp = priv_ineffect(PRIV_NET_BINDMLP);
736 840 if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET,
737 841 daemon_uid, daemon_gid, can_do_mlp ? PRIV_NET_BINDMLP : NULL,
738 842 NULL) == -1) {
739 843 syslog(LOG_ERR, "can't run unprivileged: %m");
740 844 exit(1);
741 845 }
742 846
743 847 __fini_daemon_priv(PRIV_PROC_EXEC, PRIV_PROC_SESSION,
744 848 PRIV_FILE_LINK_ANY, PRIV_PROC_INFO, NULL);
745 849 }
746 850
747 851 /*
748 852 * Copy client names from the alternate statmon directories into
749 853 * /var/statmon. The top-level (statmon) directories should already
750 854 * exist, though the sm and sm.bak directories might not.
751 855 */
752 856
753 857 static void
754 858 copy_client_names(void)
755 859 {
756 860 int i;
757 861 char buf[MAXPATHLEN+SM_MAXPATHLEN];
758 862
759 863 /*
760 864 * Copy all clients from alternate paths to /var/statmon/sm
761 865 * Remove the files in alternate directory when copying is done.
762 866 */
763 867 for (i = 0; i < pathix; i++) {
764 868 /*
765 869 * If the alternate directories do not exist, create it.
766 870 * If they do exist, just do the copy.
767 871 */
768 872 snprintf(buf, sizeof (buf), "%s/statmon/sm", path_name[i]);
769 873 if ((mkdir(buf, SM_DIRECTORY_MODE)) == -1) {
770 874 if (errno != EEXIST) {
771 875 syslog(LOG_ERR,
772 876 "can't mkdir %s: %m\n", buf);
773 877 continue;
774 878 }
775 879 copydir_from_to(buf, CURRENT);
776 880 (void) remove_dir(buf);
777 881 }
778 882
779 883 (void) snprintf(buf, sizeof (buf), "%s/statmon/sm.bak",
780 884 path_name[i]);
781 885 if ((mkdir(buf, SM_DIRECTORY_MODE)) == -1) {
782 886 if (errno != EEXIST) {
783 887 syslog(LOG_ERR,
784 888 "can't mkdir %s: %m\n", buf);
785 889 continue;
786 890 }
787 891 copydir_from_to(buf, BACKUP);
788 892 (void) remove_dir(buf);
789 893 }
790 894 }
791 895 }
792 896
793 897 /*
794 898 * Create the given directory if it doesn't already exist. Set the user
795 899 * and group to daemon for the directory and anything under it.
796 900 */
797 901
798 902 static void
799 903 one_statmon_owner(const char *dir)
800 904 {
801 905 if ((mkdir(dir, SM_DIRECTORY_MODE)) == -1) {
802 906 if (errno != EEXIST) {
803 907 syslog(LOG_ERR, "can't mkdir %s: %m",
804 908 dir);
805 909 return;
806 910 }
807 911 }
808 912
809 913 if (debug)
810 914 printf("Setting owner for %s\n", dir);
811 915
812 916 if (nftw(dir, nftw_owner, MAX_FDS, FTW_PHYS) != 0) {
813 917 syslog(LOG_WARNING, "error setting owner for %s: %m",
814 918 dir);
815 919 }
816 920 }
817 921
↓ open down ↓ |
159 lines elided |
↑ open up ↑ |
818 922 /*
819 923 * Set the user and group to daemon for the given file or directory. If
820 924 * it's a directory, also makes sure that it is mode 755.
821 925 * Generates a syslog message but does not return an error if there were
822 926 * problems.
823 927 */
824 928
825 929 /*ARGSUSED3*/
826 930 static int
827 931 nftw_owner(const char *path, const struct stat *statp, int info,
828 - struct FTW *ftw)
932 + struct FTW *ftw)
829 933 {
830 934 if (!(info == FTW_F || info == FTW_D))
831 935 return (0);
832 936
833 937 /*
834 938 * Some older systems might have mode 777 directories. Fix that.
835 939 */
836 940
837 941 if (info == FTW_D && (statp->st_mode & (S_IWGRP | S_IWOTH)) != 0) {
838 942 mode_t newmode = (statp->st_mode & ~(S_IWGRP | S_IWOTH)) &
839 943 S_IAMB;
840 944
841 945 if (debug)
842 946 printf("chmod %03o %s\n", newmode, path);
843 947 if (chmod(path, newmode) < 0) {
844 948 int error = errno;
845 949
846 950 syslog(LOG_WARNING, "can't chmod %s to %03o: %m",
847 951 path, newmode);
848 952 if (debug)
849 953 printf(" FAILED: %s\n", strerror(error));
850 954 }
851 955 }
852 956
853 957 /* If already owned by daemon, don't bother changing. */
854 958 if (statp->st_uid == daemon_uid &&
855 959 statp->st_gid == daemon_gid)
856 960 return (0);
857 961
858 962 if (debug)
859 963 printf("lchown %s daemon:daemon\n", path);
860 964 if (lchown(path, daemon_uid, daemon_gid) < 0) {
861 965 int error = errno;
862 966
863 967 syslog(LOG_WARNING, "can't chown %s to daemon: %m",
864 968 path);
865 969 if (debug)
866 970 printf(" FAILED: %s\n", strerror(error));
867 971 }
868 972
869 973 return (0);
870 974 }
↓ open down ↓ |
32 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX