xref: /illumos-gate/usr/src/lib/libnsl/common/daemon_utils.c (revision 30f5cf21f0e4186919b67ac48223d09ca110f8fe)
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 /*
24  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
25  * Use is subject to license terms.
26  */
27 
28 #pragma ident	"%Z%%M%	%I%	%E% SMI"
29 
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <sys/param.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <time.h>
37 #include <wait.h>
38 #include <fcntl.h>
39 #include <thread.h>
40 #include <unistd.h>
41 #include <errno.h>
42 #include <ucontext.h>
43 #include <syslog.h>
44 #include <rpcsvc/daemon_utils.h>
45 #include <libscf.h>
46 
47 static int open_daemon_lock(const char *, int);
48 static int is_auto_enabled(char *);
49 
50 /*
51  * Check an array of services and enable any that don't have the
52  * "application/auto_enable" property set to "false", which is
53  * the interface to turn off this behaviour (see PSARC 2004/739).
54  */
55 void
56 _check_services(char **svcs)
57 {
58 	char *s;
59 
60 	for (; *svcs; svcs++) {
61 		if (is_auto_enabled(*svcs) == 0)
62 			continue;
63 		if ((s = smf_get_state(*svcs)) != NULL) {
64 			if (strcmp(SCF_STATE_STRING_DISABLED, s) == 0)
65 				(void) smf_enable_instance(*svcs, 0);
66 			free(s);
67 		}
68 	}
69 }
70 
71 /*
72  * Use an advisory lock to ensure that only one daemon process is
73  * active in the system at any point in time. If the lock is held
74  * by another process, do not block but return the pid owner of
75  * the lock to the caller immediately. The lock is cleared if the
76  * holding daemon process exits for any reason even if the lock
77  * file remains, so the daemon can be restarted if necessary.
78  */
79 
80 /*
81  * check if another process is holding lock on the lock file.
82  *
83  * return: 0 if file is not locked, else,
84  *	   1 if file is locked by another process, else,
85  *	   -1 on any error.
86  */
87 int
88 _check_daemon_lock(const char *name)
89 {
90 	int		fd, err;
91 	struct flock	lock;
92 
93 	if ((fd = open_daemon_lock(name, O_RDONLY)) == -1) {
94 		if (errno == ENOENT)
95 			return (0);
96 		return (-1);
97 	}
98 
99 	lock.l_type = F_WRLCK;
100 	lock.l_whence = SEEK_SET;
101 	lock.l_start = (off_t)0;
102 	lock.l_len = (off_t)0;
103 
104 	err = fcntl(fd, F_GETLK, &lock);
105 	(void) close(fd);
106 
107 	if (err == -1)
108 		return (-1);
109 
110 	return ((lock.l_type == F_UNLCK) ? 0 : 1);
111 }
112 
113 static int
114 open_daemon_lock(const char *name, int mode)
115 {
116 	char		lock_file[MAXPATHLEN], buf[MAXPATHLEN];
117 	int		fd;
118 	char		*p;
119 
120 	/*
121 	 * Our args look like this:
122 	 *   svc:/network/nfs/status:default
123 	 * We want to create a lock file named like this:
124 	 *   /etc/svc/volatile/nfs-status.lock
125 	 * i.e., we want the last two path components in the name.
126 	 */
127 	(void) strncpy(buf, name, MAXPATHLEN);
128 
129 	/* First, strip off ":<instance>", if present. */
130 	p = strrchr(buf, ':');
131 	if (p != NULL)
132 		*p = '\0';
133 
134 	/* Next, find final '/' and replace it with a dash */
135 	p = strrchr(buf, '/');
136 	if (p == NULL)
137 		p = buf;
138 	else {
139 		*p = '-';
140 		/* Now find the start of what we want our name to be */
141 		p = strrchr(buf, '/');
142 		if (p == NULL)
143 			p = buf;
144 		else
145 			p++;
146 	}
147 
148 	(void) snprintf(lock_file, MAXPATHLEN, "/etc/svc/volatile/%s.lock", p);
149 
150 	if ((fd = open(lock_file, mode, 0644)) == -1)
151 		return (-1);
152 
153 	if (mode & O_CREAT)
154 		(void) fchmod(fd, 0644);
155 
156 	return (fd);
157 }
158 /*
159  * lock the file, write caller's pid to the lock file
160  * return: 0 if caller can establish lock, else,
161  *	   pid of the current lock holder, else,
162  *	   -1 on any printable error.
163  */
164 pid_t
165 _enter_daemon_lock(const char *name)
166 {
167 	int		fd;
168 	pid_t		pid;
169 	char		line[BUFSIZ];
170 	struct flock	lock;
171 
172 	pid = getpid();
173 	(void) snprintf(line, sizeof (line), "%ld\n", pid);
174 
175 	if ((fd = open_daemon_lock(name, O_RDWR|O_CREAT)) == -1)
176 		return ((pid_t)-1);
177 
178 	lock.l_type = F_WRLCK;
179 	lock.l_whence = SEEK_SET;
180 	lock.l_start = (off_t)0;
181 	lock.l_len = (off_t)0;
182 
183 	if (fcntl(fd, F_SETLK, &lock) == -1) {
184 		if (fcntl(fd, F_GETLK, &lock) == -1) {
185 			(void) close(fd);
186 			return ((pid_t)-1);
187 		}
188 		(void) close(fd);
189 		return (lock.l_pid);
190 	}
191 
192 	if (write(fd, line, strlen(line)) == -1) {
193 		(void) close(fd);
194 		return ((pid_t)-1);
195 	}
196 
197 	return ((pid_t)0);
198 }
199 
200 int
201 _create_daemon_lock(const char *name, uid_t uid, gid_t gid)
202 {
203 	int fd = open_daemon_lock(name, O_CREAT);
204 	int ret;
205 
206 	if (fd < 0)
207 		return (-1);
208 
209 	ret = fchown(fd, uid, gid);
210 	(void) close(fd);
211 
212 	return (ret);
213 }
214 
215 /*
216  * Check the "application/auto_enable" property for the passed FMRI.
217  * scf_simple_prop_get() should find the property on an instance
218  * or on the service FMRI.  The routine returns:
219  * -1: inconclusive (likely no such property or FMRI)
220  *  0: auto_enable is false
221  *  1: auto_enable is true
222  */
223 int
224 is_auto_enabled(char *fmri)
225 {
226 	scf_simple_prop_t *prop;
227 	int retval = -1;
228 	uint8_t *ret;
229 
230 	prop = scf_simple_prop_get(NULL, fmri, "application", "auto_enable");
231 	if (!prop)
232 		return (retval);
233 	ret = scf_simple_prop_next_boolean(prop);
234 	retval = (*ret != 0);
235 	scf_simple_prop_free(prop);
236 	return (retval);
237 }
238