4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * probedev issues ioctls for all the metadevices
30 #include "md_monitord.h"
33 extern char queue_name
[];
34 boolean_e issue_ioctl
= True
;
37 #define DEBUG_LEVEL_FORK 9 /* will run in background at all */
38 /* levels less than DEBUG_LEVEL_FORK */
40 /* function prototypes */
41 static void usage(void);
42 static void catch_sig(int);
43 static pid_t
enter_daemon_lock(void);
44 static void exit_daemon_lock(void);
45 static void probe_all_devs(boolean_e
, md_error_t
*, boolean_e
);
47 #define DAEMON_LOCK_FILE "/etc/lvm/.mdmonitord.lock"
54 static int hold_daemon_lock
;
55 static const char *daemon_lock_file
= DAEMON_LOCK_FILE
;
56 static int daemon_lock_fd
;
58 static int debug_level
;
61 static struct itimerval itimer
;
62 static boolean_e probe_started
; /* flag to indicate main is probing */
66 (void) fprintf(stderr
, gettext(
67 "usage: mdmonitord [-d <debug_level>] [-t poll time]\n"
68 "higher debug levels get progressively more"
69 "detailed debug information.\n\n"
70 "mdmonitord will run in background if run"
71 "with a debug_level less than %d.\n"), DEBUG_LEVEL_FORK
);
76 /* common exit function which ensures releasing locks */
78 monitord_exit(int status
)
80 monitord_print(1, gettext("exit status = %d\n"), status
);
82 monitord_print(8, "hold_daemon_lock %d\n", hold_daemon_lock
);
83 if (hold_daemon_lock
) {
91 * When SIGHUP is received, reload modules?
96 boolean_e startup
= False
;
97 md_error_t status
= mdnullerror
;
98 boolean_e sig_verbose
= True
;
100 if (sig
== SIGALRM
) {
101 monitord_print(6, gettext("SIGALRM processing"));
102 if (probe_started
== True
) {
103 monitord_print(6, gettext(
104 " probe_started returning\n"));
107 monitord_print(6, gettext(
108 " starting probe from signal handler\n"));
109 probe_all_devs(startup
, &status
, sig_verbose
);
110 (void) setitimer(ITIMER_REAL
, &itimer
, NULL
);
117 * Use an advisory lock to ensure that only one daemon process is
118 * active at any point in time.
121 check_daemon_lock(void)
125 monitord_print(1, gettext("check_daemon_lock: lock file = %s\n"),
128 daemon_lock_fd
= open(daemon_lock_file
, O_CREAT
|O_RDWR
, 0644);
129 if (daemon_lock_fd
< 0) {
130 monitord_print(0, "open(%s) - %s\n", daemon_lock_file
,
135 lock
.l_type
= F_WRLCK
;
136 lock
.l_whence
= SEEK_SET
;
140 if (fcntl(daemon_lock_fd
, F_GETLK
, &lock
) == -1) {
141 monitord_print(0, "lock(%s) - %s", daemon_lock_file
,
146 return (lock
.l_type
== F_UNLCK
? 0 : lock
.l_pid
);
150 enter_daemon_lock(void)
154 monitord_print(1, gettext(
155 "enter_daemon_lock: lock file = %s\n"), daemon_lock_file
);
157 daemon_lock_fd
= open(daemon_lock_file
, O_CREAT
|O_RDWR
, 0644);
158 if (daemon_lock_fd
< 0) {
159 monitord_print(0, "open(%s) - %s\n",
160 daemon_lock_file
, strerror(errno
));
164 lock
.l_type
= F_WRLCK
;
165 lock
.l_whence
= SEEK_SET
;
169 if (fcntl(daemon_lock_fd
, F_SETLK
, &lock
) == -1) {
171 if (errno
== EAGAIN
|| errno
== EDEADLK
) {
173 if (fcntl(daemon_lock_fd
, F_GETLK
, &lock
) == -1) {
174 monitord_print(0, "lock(%s) - %s",
175 daemon_lock_file
, strerror(errno
));
182 hold_daemon_lock
= 1;
188 * Drop the advisory daemon lock, close lock file
191 exit_daemon_lock(void)
195 lock
.l_type
= F_UNLCK
;
196 lock
.l_whence
= SEEK_SET
;
200 if (fcntl(daemon_lock_fd
, F_SETLK
, &lock
) == -1) {
201 monitord_print(0, "unlock(%s) - %s",
202 daemon_lock_file
, strerror(errno
));
205 if (close(daemon_lock_fd
) == -1) {
206 monitord_print(0, "close(%s) failed - %s\n",
207 daemon_lock_file
, strerror(errno
));
210 (void) unlink(daemon_lock_file
);
215 * print error messages to the terminal or to syslog
219 monitord_print(int level
, char *message
, ...)
222 static int newline
= 1;
224 if (level
> debug_level
) {
228 va_start(ap
, message
);
231 (void) vsyslog(LOG_ERR
, message
, ap
);
233 (void) vfprintf(stderr
, message
, ap
);
238 (void) syslog(LOG_DEBUG
, "%s[%ld]: ",
240 (void) vsyslog(LOG_DEBUG
, message
, ap
);
243 (void) fprintf(stdout
, "%s[%ld]: ",
245 (void) vfprintf(stdout
, message
, ap
);
247 (void) vfprintf(stdout
, message
, ap
);
251 if (message
[strlen(message
)-1] == '\n') {
261 int2string(intmap_t
*map
, int value
)
263 const char *name
= (const char *)NULL
;
266 for (; map
->im_name
!= (const char *)NULL
; map
++) {
267 if (map
->im_int
== value
) {
272 if (name
== (const char *)NULL
) {
273 /* No match. Convert the string to an int. */
274 (void) sprintf(charstr
, "%d", value
);
276 (void) snprintf(charstr
, sizeof (charstr
), "%d %s",
279 return (strdup(charstr
));
283 probe_all_devs(boolean_e startup
, md_error_t
*statusp
, boolean_e verbose
)
285 set_t max_sets
, set_idx
;
287 probe_started
= True
;
288 (void) set_snarf(statusp
);
290 if ((max_sets
= get_max_sets(statusp
)) == 0) {
291 mde_perror(statusp
, gettext(
292 "Can't find max number of sets\n"));
297 * We delete the FF_Q to avoid recurse errors. Yes we will lose
298 * some but its the corner case.
301 if (startup
== False
&&
302 (meta_notify_deleteq(MD_FF_Q
, statusp
) != 0)) {
303 mde_perror(statusp
, gettext(
304 "delete queue failed\n"));
308 for (set_idx
= 0; set_idx
< max_sets
; set_idx
++) {
309 if ((sp
= metasetnosetname(set_idx
, statusp
)) == NULL
) {
310 if (mdiserror(statusp
, MDE_NO_SET
) == 0) {
312 * done break the loop
321 /* if we dont have ownership or cannot lock it continue. */
322 if ((meta_check_ownership(sp
, statusp
) == NULL
) &&
323 meta_lock(sp
, TRUE
, statusp
))
326 /* Skip if a MN set */
327 if (meta_is_mn_set(sp
, statusp
)) {
328 (void) meta_unlock(sp
, statusp
);
332 probe_mirror_devs(verbose
);
333 probe_raid_devs(verbose
);
334 probe_trans_devs(verbose
);
335 probe_hotspare_devs(verbose
);
336 (void) meta_unlock(sp
, statusp
);
338 if (meta_notify_createq(MD_FF_Q
, 0, statusp
)) {
339 mde_perror(statusp
, gettext(
340 "create queue failed"));
343 probe_started
= False
;
345 * need to do it here only at startup.
346 * The daemon will restart the alarm.
350 (void) setitimer(ITIMER_REAL
, &itimer
, NULL
);
354 wait_for_event(md_error_t
*statusp
)
359 event
.setno
= EV_ALLSETS
;
360 event
.obj
= EV_ALLOBJS
;
363 if (meta_notify_getev(MD_FF_Q
, EVFLG_WAIT
, &event
,
366 "meta_notify_getev: errno 0x%x\n", -errno
);
367 monitord_exit(-errno
);
369 } while ((event
.ev
!= EV_IOERR
&& event
.ev
!= EV_ERRED
&&
370 event
.ev
!= EV_LASTERRED
));
375 main(int argc
, char **argv
)
377 boolean_e startup
= True
;
378 boolean_e verbose
= False
;
381 md_error_t status
= mdnullerror
;
382 struct sigaction act
;
384 unsigned long timerval
= 0;
387 * Get the locale set up before calling any other routines
388 * with messages to ouput. Just in case we're not in a build
389 * environment, make sure that TEXT_DOMAIN gets set to
392 #if !defined(TEXT_DOMAIN)
393 #define TEXT_DOMAIN "SYS_TEST"
395 (void) setlocale(LC_ALL
, "");
396 (void) textdomain(TEXT_DOMAIN
);
398 if (sdssc_bind_library() == SDSSC_ERROR
) {
399 (void) printf(gettext(
400 "%s: Interface error with libsds_sc.so\n"), argv
[0]);
404 if (md_init(argc
, argv
, 0, 1, &status
) != 0 ||
405 meta_check_root(&status
) != 0) {
406 mde_perror(&status
, "");
410 (void) sigfillset(&mask
);
411 (void) thr_sigsetmask(SIG_BLOCK
, &mask
, NULL
);
417 if ((prog
= strrchr(argv
[0], '/')) == NULL
) {
424 * Reset optind/opterr so that the command line arguments can be
425 * parsed. This is in case anything has already called getopt,
426 * for example sdssc_cmd_proxy which is not currently used but
427 * may be in the future.
431 while ((c
= getopt(argc
, argv
, "ivd:t:")) != EOF
) {
440 debug_level
= atoi(optarg
);
443 timerval
= atol(optarg
);
452 monitord_print(8, gettext(
453 "operating in interrupt mode\n"));
455 itimer
.it_value
.tv_sec
= timerval
;
456 itimer
.it_interval
.tv_sec
= timerval
;
457 monitord_print(8, gettext(
458 "set value and interval %lu sec mode\n"), timerval
);
461 * set up our signal handler for SIGALRM. The
462 * rest are setup by md_init.
465 act
.sa_handler
= catch_sig
;
466 (void) sigemptyset(&act
.sa_mask
);
467 act
.sa_flags
= SA_RESTART
;
468 (void) sigaction(SIGALRM
, &act
, NULL
);
469 (void) sigaction(SIGHUP
, &act
, NULL
);
471 (void) sigemptyset(&mask
);
472 (void) sigaddset(&mask
, SIGALRM
);
473 (void) sigaddset(&mask
, SIGHUP
);
474 (void) thr_sigsetmask(SIG_UNBLOCK
, &mask
, NULL
);
476 /* demonize ourselves */
477 if (debug_level
< DEBUG_LEVEL_FORK
) {
480 if ((pid
= check_daemon_lock()) != 0) {
481 monitord_print(0, gettext(
482 "mdmonitord daemon pid %ld already running\n"),
491 /* only one daemon can run at a time */
492 if ((pid
= enter_daemon_lock()) != 0) {
493 monitord_print(0, gettext(
494 "mdmonitord daemon pid %ld already running\n"),
502 if (debug_level
<= 1) {
503 for (i
= 0; i
< 3; i
++) {
506 (void) open("/dev/null", 0);
513 openlog("mdmonitord", LOG_PID
, LOG_DAEMON
);
515 monitord_print(8, gettext(
516 "mdmonitord started, debug level = %d\n"), debug_level
);
519 /* loop forever waiting for events */
522 probe_all_devs(startup
, &status
, verbose
);
523 startup
= False
; /* since we have gone through once */
524 } while (wait_for_event(&status
));