1 /* 2 * CDDL HEADER START 3 * 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. 7 * 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. 12 * 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] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <door.h> 28 #include <locale.h> 29 #include <meta.h> 30 #include <strings.h> 31 #include <syslog.h> 32 33 static pid_t enter_daemon_lock(void); 34 static void exit_daemon_lock(void); 35 #define DAEMON_LOCK_FILE "/var/run/.mddoors.lock" 36 37 static int hold_daemon_lock; 38 static const char *daemon_lock_file = DAEMON_LOCK_FILE; 39 static int daemon_lock_fd; 40 41 void 42 daemon_cleanup() 43 { 44 if (hold_daemon_lock) { 45 meta_mirror_resync_block_all(); 46 exit_daemon_lock(); 47 } 48 } 49 50 /* 51 * Use an advisory lock to ensure that only one daemon process is 52 * active at any point in time. 53 */ 54 static pid_t 55 enter_daemon_lock(void) 56 { 57 struct flock lock; 58 59 daemon_lock_fd = open(daemon_lock_file, O_CREAT|O_RDWR, 0644); 60 61 if (daemon_lock_fd < 0) { 62 exit(-1); 63 } 64 65 lock.l_type = F_WRLCK; 66 lock.l_whence = SEEK_SET; 67 lock.l_start = 0; 68 lock.l_len = 0; 69 70 if (fcntl(daemon_lock_fd, F_SETLK, &lock) == -1) { 71 72 if (errno == EAGAIN || errno == EDEADLK) { 73 74 if (fcntl(daemon_lock_fd, F_GETLK, &lock) == -1) { 75 exit(1); 76 } 77 return (lock.l_pid); 78 } 79 } 80 hold_daemon_lock = 1; 81 return (getpid()); 82 } 83 84 85 /* 86 * Drop the advisory daemon lock, close lock file 87 */ 88 static void 89 exit_daemon_lock(void) 90 { 91 struct flock lock; 92 93 lock.l_type = F_UNLCK; 94 lock.l_whence = SEEK_SET; 95 lock.l_start = 0; 96 lock.l_len = 0; 97 98 if (fcntl(daemon_lock_fd, F_SETLK, &lock) == -1) { 99 syslog(LOG_DAEMON | LOG_DEBUG, gettext("unlock(%s) - %s"), 100 daemon_lock_file, strerror(errno)); 101 return; 102 } 103 104 if (close(daemon_lock_fd) == -1) { 105 syslog(LOG_DAEMON | LOG_DEBUG, 106 gettext("close(%s) failed - %s\n"), 107 daemon_lock_file, strerror(errno)); 108 return; 109 } 110 unlink(daemon_lock_file); 111 } 112 113 /* 114 * Purpose of this routine is to accept a message from the local kernel and 115 * send this message using rpc to the master node. 116 * when an ok comes from the master we call door_return() 117 */ 118 119 /* ARGSUSED */ 120 static void 121 door2rpc(void *cookie, /* required by the doors infrastructure */ 122 char *argp, 123 size_t arg_size, /* required by the doors infrastructure */ 124 door_desc_t *dp, /* required by the doors infrastructure */ 125 uint_t n_desc) /* required by the doors infrastructure */ 126 { 127 int err; 128 int size; 129 md_error_t ep = mdnullerror; 130 md_mn_result_t *result = NULL; 131 md_mn_kresult_t kresult; 132 133 md_mn_kmsg_t *kmsg = (md_mn_kmsg_t *)(void *)argp; 134 err = mdmn_send_message(kmsg->kmsg_setno, kmsg->kmsg_type, 135 kmsg->kmsg_flags, kmsg->kmsg_recipient, (char *)&(kmsg->kmsg_data), 136 kmsg->kmsg_size, &result, &ep); 137 138 if (result == NULL) { 139 kresult.kmmr_comm_state = MDMNE_RPC_FAIL; 140 } else { 141 kresult.kmmr_comm_state = result->mmr_comm_state; 142 if (err == 0) { 143 kresult.kmmr_msgtype = result->mmr_msgtype; 144 kresult.kmmr_flags = result->mmr_flags; 145 kresult.kmmr_exitval = result->mmr_exitval; 146 kresult.kmmr_failing_node = result->mmr_failing_node; 147 size = result->mmr_out_size; 148 if (size > 0) { 149 /* This is the max data we can transfer, here */ 150 if (size > MDMN_MAX_KRES_DATA) { 151 size = MDMN_MAX_KRES_DATA; 152 } 153 bcopy(result->mmr_out, &(kresult.kmmr_res_data), 154 size); 155 kresult.kmmr_res_size = size; 156 } else { 157 kresult.kmmr_res_size = 0; 158 } 159 } 160 free_result(result); 161 } 162 163 door_return((char *)&kresult, sizeof (md_mn_kresult_t), NULL, 0); 164 } 165 166 167 /* ARGSUSED */ 168 int 169 main(void) 170 { 171 172 int i; 173 int mdmn_door_handle; 174 pid_t pid; 175 int size; 176 md_error_t ep = mdnullerror; 177 struct rlimit rl; 178 179 /* 180 * Get the locale set up before calling any other routines 181 * with messages to ouput. Just in case we're not in a build 182 * environment, make sure that TEXT_DOMAIN gets set to 183 * something. 184 */ 185 #if !defined(TEXT_DOMAIN) 186 #define TEXT_DOMAIN "SYS_TEST" 187 #endif 188 (void) setlocale(LC_ALL, ""); 189 (void) textdomain(TEXT_DOMAIN); 190 191 openlog("mddoors", LOG_PID, LOG_DAEMON); 192 193 /* here beginneth the daemonizing code */ 194 pid = fork(); 195 if (pid < 0) { 196 syslog(LOG_DAEMON | LOG_ERR, gettext("Cannot fork")); 197 exit(1); 198 } 199 200 if (pid) { 201 exit(0); 202 } 203 204 /* 205 * Only one daemon can run at a time. 206 * If another instance is already running, this is not an error. 207 */ 208 if ((pid = enter_daemon_lock()) != getpid()) { 209 exit(0); 210 } 211 212 rl.rlim_max = 0; 213 getrlimit(RLIMIT_NOFILE, &rl); 214 if ((size = rl.rlim_max) == 0) { 215 syslog(LOG_DAEMON | LOG_ERR, gettext("Cannot getrlimit")); 216 exit(1); 217 } 218 219 for (i = 0; i < size; i++) { 220 if (i == daemon_lock_fd) 221 continue; 222 (void) close(i); 223 } 224 225 226 i = open("/dev/null", 2); 227 (void) dup2(i, 1); 228 (void) dup2(i, 2); 229 setsid(); 230 231 /* here endeth the daemonizing code */ 232 233 /* Block out the usual signals so we don't get killed unintentionally */ 234 (void) signal(SIGHUP, SIG_IGN); 235 (void) signal(SIGINT, SIG_IGN); 236 (void) signal(SIGQUIT, SIG_IGN); 237 (void) signal(SIGTERM, SIG_IGN); 238 239 atexit(daemon_cleanup); 240 241 /* Resume any previously blocked resync */ 242 meta_mirror_resync_unblock_all(); 243 244 /* 245 * At this point we are single threaded. 246 * We give mdmn_send_message() a chance to initialize safely. 247 */ 248 (void) mdmn_send_message(0, 0, 0, 0, 0, 0, 0, 0); 249 250 /* setup the door handle */ 251 mdmn_door_handle = door_create(door2rpc, NULL, 252 DOOR_REFUSE_DESC | DOOR_NO_CANCEL); 253 if (mdmn_door_handle == -1) { 254 perror(gettext("door_create failed")); 255 syslog(LOG_DAEMON | LOG_ERR, gettext("door_create failed")); 256 exit(1); 257 } 258 259 if (metaioctl(MD_MN_SET_DOORH, &mdmn_door_handle, &ep, 260 "mddoors") != 0) { 261 syslog(LOG_DAEMON | LOG_DEBUG, gettext( 262 "Couldn't set door handle")); 263 exit(1); 264 } 265 266 (void) pause(); 267 syslog(LOG_DAEMON | LOG_ERR, gettext( 268 "Unexpected exit from pause()")); 269 return (1); 270 } 271