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 (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 #include "mt.h" 27 #include <stdio.h> 28 #include <stdlib.h> 29 #include <string.h> 30 #include <sys/param.h> 31 #include <sys/types.h> 32 #include <sys/stat.h> 33 #include <time.h> 34 #include <wait.h> 35 #include <fcntl.h> 36 #include <thread.h> 37 #include <unistd.h> 38 #include <errno.h> 39 #include <ucontext.h> 40 #include <syslog.h> 41 #include <rpcsvc/daemon_utils.h> 42 43 static int open_daemon_lock(const char *, int); 44 45 /* 46 * Use an advisory lock to ensure that only one daemon process is 47 * active in the system at any point in time. If the lock is held 48 * by another process, do not block but return the pid owner of 49 * the lock to the caller immediately. The lock is cleared if the 50 * holding daemon process exits for any reason even if the lock 51 * file remains, so the daemon can be restarted if necessary. 52 */ 53 54 /* 55 * check if another process is holding lock on the lock file. 56 * 57 * return: 0 if file is not locked, else, 58 * 1 if file is locked by another process, else, 59 * -1 on any error. 60 */ 61 int 62 _check_daemon_lock(const char *name) 63 { 64 int fd, err; 65 struct flock lock; 66 67 if ((fd = open_daemon_lock(name, O_RDONLY)) == -1) { 68 if (errno == ENOENT) 69 return (0); 70 return (-1); 71 } 72 73 lock.l_type = F_WRLCK; 74 lock.l_whence = SEEK_SET; 75 lock.l_start = (off_t)0; 76 lock.l_len = (off_t)0; 77 78 err = fcntl(fd, F_GETLK, &lock); 79 (void) close(fd); 80 81 if (err == -1) 82 return (-1); 83 84 return ((lock.l_type == F_UNLCK) ? 0 : 1); 85 } 86 87 static int 88 open_daemon_lock(const char *name, int mode) 89 { 90 char lock_file[MAXPATHLEN], buf[MAXPATHLEN]; 91 int fd; 92 char *p; 93 94 /* 95 * Our args look like this: 96 * svc:/network/nfs/status:default 97 * We want to create a lock file named like this: 98 * /etc/svc/volatile/nfs-status.lock 99 * i.e., we want the last two path components in the name. 100 */ 101 (void) strncpy(buf, name, MAXPATHLEN); 102 103 /* First, strip off ":<instance>", if present. */ 104 p = strrchr(buf, ':'); 105 if (p != NULL) 106 *p = '\0'; 107 108 /* Next, find final '/' and replace it with a dash */ 109 p = strrchr(buf, '/'); 110 if (p == NULL) 111 p = buf; 112 else { 113 *p = '-'; 114 /* Now find the start of what we want our name to be */ 115 p = strrchr(buf, '/'); 116 if (p == NULL) 117 p = buf; 118 else 119 p++; 120 } 121 122 (void) snprintf(lock_file, MAXPATHLEN, "/etc/svc/volatile/%s.lock", p); 123 124 if ((fd = open(lock_file, mode, 0644)) == -1) 125 return (-1); 126 127 if (mode & O_CREAT) 128 (void) fchmod(fd, 0644); 129 130 return (fd); 131 } 132 /* 133 * lock the file, write caller's pid to the lock file 134 * return: 0 if caller can establish lock, else, 135 * pid of the current lock holder, else, 136 * -1 on any printable error. 137 */ 138 pid_t 139 _enter_daemon_lock(const char *name) 140 { 141 int fd; 142 pid_t pid; 143 char line[BUFSIZ]; 144 struct flock lock; 145 146 pid = getpid(); 147 (void) snprintf(line, sizeof (line), "%ld\n", pid); 148 149 if ((fd = open_daemon_lock(name, O_RDWR|O_CREAT)) == -1) 150 return ((pid_t)-1); 151 152 lock.l_type = F_WRLCK; 153 lock.l_whence = SEEK_SET; 154 lock.l_start = (off_t)0; 155 lock.l_len = (off_t)0; 156 157 if (fcntl(fd, F_SETLK, &lock) == -1) { 158 if (fcntl(fd, F_GETLK, &lock) == -1) { 159 (void) close(fd); 160 return ((pid_t)-1); 161 } 162 (void) close(fd); 163 return (lock.l_pid); 164 } 165 166 if (write(fd, line, strlen(line)) == -1) { 167 (void) close(fd); 168 return ((pid_t)-1); 169 } 170 171 return ((pid_t)0); 172 } 173 174 int 175 _create_daemon_lock(const char *name, uid_t uid, gid_t gid) 176 { 177 int fd = open_daemon_lock(name, O_CREAT); 178 int ret; 179 180 if (fd < 0) 181 return (-1); 182 183 ret = fchown(fd, uid, gid); 184 (void) close(fd); 185 186 return (ret); 187 } 188