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