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