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 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <sys/param.h> 27 #include <sys/stat.h> 28 #include <sys/types.h> 29 #include <sys/sysevent/eventdefs.h> 30 #include <sys/sysevent/dr.h> 31 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <unistd.h> 35 #include <signal.h> 36 #include <syslog.h> 37 #include <string.h> 38 #include <fcntl.h> 39 #include <errno.h> 40 #include <time.h> 41 #include <config_admin.h> 42 #include <libsysevent.h> 43 44 45 /* Signal handler type */ 46 typedef void (SigHandler)(int); 47 /* oplhpd process id file descriptor */ 48 static int pid_fd; 49 50 /* Program Name */ 51 char *oplhpd_prog_name = ""; 52 53 /* Macros */ 54 #define OPLHPD_DEV_DIR "/devices" /* device base dir */ 55 #define OPLHPD_PID_FILE "/var/run/oplhpd.pid" /* lock file path */ 56 #define OPLHPD_PROG_NAME oplhpd_prog_name 57 58 /* Event handler to get information */ 59 static sysevent_handle_t *oplhpd_hdl; 60 61 62 /* 63 * Function Prototypes 64 */ 65 void quit_daemon(int signo); 66 SigHandler *set_sig_handler(int sig, SigHandler *handler); 67 void init_daemon(void); 68 void oplhpd_init(void); 69 void oplhpd_fini(void); 70 static void oplhpd_event(sysevent_t *ev); 71 72 extern void notify_scf_of_hotplug(sysevent_t *ev); 73 74 75 /* 76 * Terminate and Quit Daemon Process. 77 * signo = 0 ... normal quit 78 * > 0 ... signaled quit 79 * < 0 ... failure quit 80 */ 81 void 82 quit_daemon(int signo) 83 { 84 int status = 0; 85 id_t pgid; 86 87 syslog(LOG_DEBUG, "*** quit daemon [pid:%d, signal#:%d].\n", 88 getpid(), signo); 89 90 (void) set_sig_handler(SIGTERM, SIG_IGN); 91 pgid = getpgrp(); 92 (void) kill(-pgid, SIGTERM); 93 94 (void) close(pid_fd); 95 (void) unlink(OPLHPD_PID_FILE); /* clean up lock file */ 96 97 if (signo < 0) { 98 status = signo; 99 } 100 _exit(status); 101 } 102 103 /* 104 * Setting the signal handler utility 105 */ 106 SigHandler * 107 set_sig_handler(int sig, SigHandler *handler) 108 { 109 struct sigaction act, oact; 110 111 act.sa_handler = handler; 112 act.sa_flags = 0; 113 if (sig == SIGCHLD && handler == SIG_IGN) { 114 act.sa_flags |= SA_NOCLDWAIT; 115 } 116 (void) sigemptyset(&act.sa_mask); 117 (void) sigemptyset(&oact.sa_mask); 118 if (sigaction(sig, &act, &oact) < 0) { 119 return (SIG_ERR); 120 } 121 122 return (oact.sa_handler); 123 } 124 125 /* 126 * Setup oplhpd daemon 127 */ 128 void 129 init_daemon() 130 { 131 int i; 132 int ret; 133 int fd; 134 pid_t pid; 135 char pid_str[32]; 136 137 if (geteuid() != 0) { 138 syslog(LOG_ERR, "must be root to execute %s\n", 139 OPLHPD_PROG_NAME); 140 exit(1); 141 } 142 143 /* 144 * Daemonize 145 */ 146 if ((pid = fork()) < 0) { 147 perror("fork failed"); 148 exit(1); 149 } 150 if (pid > 0) { 151 /* Parent, exit. */ 152 exit(0); 153 } 154 (void) setsid(); 155 (void) chdir("/"); 156 (void) umask(0); 157 (void) closefrom(0); 158 (void) open("/dev/null", O_RDONLY); 159 (void) open("/dev/null", O_WRONLY); 160 (void) dup(1); 161 162 (void) openlog(OPLHPD_PROG_NAME, LOG_PID, LOG_DAEMON); 163 164 /* 165 * Create the lock file for singletonize 166 */ 167 if ((pid_fd = open(OPLHPD_PID_FILE, O_RDWR | O_CREAT, 0644)) < 0) { 168 syslog(LOG_ERR, "could not create pid file: %s", 169 strerror(errno)); 170 exit(1); 171 } 172 if (lockf(pid_fd, F_TLOCK, 0L) < 0) { 173 if (errno == EACCES || errno == EAGAIN) { 174 syslog(LOG_ERR, "another oplhpd is already running"); 175 } else { 176 syslog(LOG_ERR, "could not lock pid file"); 177 } 178 exit(1); 179 } 180 181 (void) ftruncate(pid_fd, 0); 182 i = sprintf(pid_str, "%d\n", getpid()); 183 while ((ret = write(pid_fd, pid_str, i)) != i) { 184 if (errno == EINTR) { 185 continue; 186 } 187 if (ret < 0) { 188 syslog(LOG_ERR, "pid file write fail: %s", 189 strerror(errno)); 190 exit(1); 191 } 192 } 193 194 /* 195 * Set signal handlers 196 */ 197 (void) set_sig_handler(SIGTERM, (SigHandler *)quit_daemon); 198 (void) set_sig_handler(SIGQUIT, (SigHandler *)quit_daemon); 199 (void) set_sig_handler(SIGINT, (SigHandler *)quit_daemon); 200 (void) set_sig_handler(SIGCHLD, SIG_IGN); 201 } 202 203 static void 204 oplhpd_event(sysevent_t *ev) 205 { 206 /* 207 * Inform the SCF of the change in the state of the pci hot plug 208 * cassette. 209 */ 210 notify_scf_of_hotplug(ev); 211 212 } 213 214 /* 215 * Initialization for hotplug event. 216 * - Bind event handler. 217 * - Subscribe the handler to the hotplug event. 218 */ 219 void 220 oplhpd_init() 221 { 222 const char *subclass = ESC_DR_AP_STATE_CHANGE; 223 224 syslog(LOG_DEBUG, "oplhpd_init"); 225 226 oplhpd_hdl = sysevent_bind_handle(oplhpd_event); 227 if (oplhpd_hdl == NULL) { 228 syslog(LOG_ERR, "event handler bind fail"); 229 quit_daemon(-1); 230 } 231 232 if (sysevent_subscribe_event(oplhpd_hdl, EC_DR, &subclass, 1) != 0) { 233 syslog(LOG_ERR, "event handler subscribe fail"); 234 sysevent_unbind_handle(oplhpd_hdl); 235 quit_daemon(-1); 236 } 237 238 for (;;) { 239 (void) pause(); 240 } 241 } 242 243 void 244 oplhpd_fini() 245 { 246 if (oplhpd_hdl != NULL) { 247 sysevent_unsubscribe_event(oplhpd_hdl, EC_DR); 248 sysevent_unbind_handle(oplhpd_hdl); 249 } 250 } 251 252 int 253 main(int argc, char *argv[]) 254 { 255 int opt; 256 257 /* Get Program Name */ 258 if ((oplhpd_prog_name = strrchr(argv[0], '/')) == NULL) { 259 oplhpd_prog_name = argv[0]; 260 } else { 261 oplhpd_prog_name++; 262 } 263 264 /* Check the daemon running lock and Initialize the signal */ 265 init_daemon(); 266 267 /* Subscribe to the hotplug event */ 268 oplhpd_init(); 269 270 /* Unsubscribe the hotplug event */ 271 oplhpd_fini(); 272 273 return (0); 274 } 275