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