Home | History | Annotate | Download | only in startd
      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 2008 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 
     27 #include <assert.h>
     28 #include <stdlib.h>
     29 #include <string.h>
     30 #include <unistd.h>
     31 #include <errno.h>
     32 #include <sys/param.h>
     33 #include "startd.h"
     34 
     35 /*
     36  * The service deathrow mechanism addresses the problem of removing services
     37  * from a non accessible SMF repository. In this case, we can't simply use the
     38  * "SVCCFG_REPOSITORY=$ROOT/etc/svc/repository.db svccfg delete service_fmri"
     39  * command as the alternate repository format is not committed and could be
     40  * incompatible with the local SMF commands version.
     41  *
     42  * The idea is to manage a file (/etc/svc/deathrow) on the alternate root
     43  * directory that lists the FMRIs that need to disappear from the repository
     44  * when the system that uses this root directory boots up.
     45  * r.manifest and i.manifest update the file /etc/svc/deathrow in the alternate
     46  * root case.
     47  *
     48  * When svc.startd daemon launches, it first reads the /etc/svc/deathrow file
     49  * and for all FMRIs listed in this file, the service is not configured and
     50  * dependencies on it are forced satisfied (during svc.startd init time only).
     51  *
     52  * Than manifest-import service will actually, as first task, delete the
     53  * unconfigured services found in the /etc/svc/deathrow file and the
     54  * manifest hash entry from the repository.
     55  *
     56  */
     57 
     58 #define	SVC_DEATHROW_FILE	"/etc/svc/deathrow"
     59 
     60 /*
     61  * These data structures are unprotected because they
     62  * are modified by a single thread, at startup time.
     63  * After initialization, these data structures are
     64  * used only in read mode, thus requiring no protection.
     65  */
     66 
     67 /* list of deathrow fmris, created from the file SVC_DEATHROW_FILE */
     68 typedef struct deathrow {
     69     char *fmri;
     70     uu_list_node_t deathrow_link;
     71 } deathrow_t;
     72 
     73 static uu_list_pool_t *deathrow_pool;
     74 static uu_list_t *deathrow_list;
     75 
     76 static boolean_t deathrow_handling_status = B_FALSE;
     77 
     78 static deathrow_t *fmri_in_deathrow_internal(const char *);
     79 static void deathrow_add(const char *);
     80 
     81 static void
     82 deathrow_handling_start()
     83 {
     84 	assert(deathrow_handling_status == B_FALSE);
     85 	deathrow_handling_status = B_TRUE;
     86 }
     87 
     88 static void
     89 deathrow_handling_stop()
     90 {
     91 	assert(deathrow_handling_status == B_TRUE);
     92 	deathrow_handling_status = B_FALSE;
     93 }
     94 
     95 void
     96 deathrow_init()
     97 {
     98 	FILE *file;
     99 	char *line;
    100 	char *fmri;
    101 	char *manifest;
    102 	char *pkgname;
    103 	size_t line_size, sz;
    104 	unsigned int line_parsed = 0;
    105 
    106 	log_framework(LOG_DEBUG, "Deathrow init\n");
    107 
    108 	while ((file = fopen(SVC_DEATHROW_FILE, "r")) == NULL) {
    109 		if (errno == EINTR) {
    110 			continue;
    111 		}
    112 		if (errno != ENOENT) {
    113 			log_framework(LOG_ERR,
    114 			    "Deathrow not processed. "
    115 			    "Error opening file (%s): %s\n",
    116 			    SVC_DEATHROW_FILE, strerror(errno));
    117 		}
    118 		return;
    119 	}
    120 
    121 	deathrow_pool = uu_list_pool_create("deathrow",
    122 	    sizeof (deathrow_t), offsetof(deathrow_t, deathrow_link),
    123 	    NULL, UU_LIST_POOL_DEBUG);
    124 	if (deathrow_pool == NULL) {
    125 		uu_die("deathrow_init couldn't create deathrow_pool");
    126 	}
    127 
    128 	deathrow_list = uu_list_create(deathrow_pool,  deathrow_list, 0);
    129 	if (deathrow_list == NULL) {
    130 		uu_die("deathrow_init couldn't create deathrow_list");
    131 	}
    132 
    133 	/*
    134 	 * A deathrow file line looks like:
    135 	 * <fmri>< ><manifest path>< ><package name><\n>
    136 	 * (field separator is a space character)
    137 	 */
    138 	line_size = max_scf_fmri_size + 3 + MAXPATHLEN + MAXNAMELEN;
    139 	line = (char *)startd_alloc(line_size);
    140 	*line = '\0';
    141 
    142 	while (fgets(line, line_size, file) != NULL) {
    143 		line_parsed++;
    144 		fmri = NULL;
    145 		manifest = NULL;
    146 		pkgname = NULL;
    147 		sz = strlen(line);
    148 		if (sz > 0) {
    149 			/* remove linefeed */
    150 			if (line[sz - 1] == '\n') {
    151 				line[sz - 1] = '\0';
    152 			}
    153 			manifest = strchr(line, ' ');
    154 			if (manifest != NULL) {
    155 				fmri = line;
    156 				*manifest = '\0';
    157 				manifest++;
    158 				pkgname = strchr(manifest, ' ');
    159 				if (pkgname != NULL) {
    160 					*pkgname = '\0';
    161 					pkgname++;
    162 				}
    163 			}
    164 		}
    165 		if (fmri != NULL && strlen(fmri) > 0 &&
    166 		    strlen(fmri) < max_scf_fmri_size &&
    167 		    manifest != NULL && strlen(manifest) > 0 &&
    168 		    pkgname != NULL && strlen(pkgname) > 0) {
    169 			log_framework(LOG_DEBUG,
    170 			    "Deathrow parser <%s><%s><%s>\n",
    171 			    fmri, manifest, pkgname);
    172 			if (fmri_in_deathrow_internal(fmri) == NULL) {
    173 				/* fmri is not in list, add fmri */
    174 				deathrow_add(fmri);
    175 			}
    176 		} else {
    177 			log_framework(LOG_ERR,
    178 			    "Deathrow error processing file (%s). "
    179 			    "Skipping line %u.\n",
    180 			    SVC_DEATHROW_FILE, line_parsed);
    181 		}
    182 		*line = '\0';
    183 	}
    184 	startd_free(line, line_size);
    185 	(void) fclose(file);
    186 
    187 	if (uu_list_first(deathrow_list) != NULL) {
    188 		deathrow_handling_start();
    189 	}
    190 }
    191 
    192 void
    193 deathrow_fini()
    194 {
    195 	deathrow_t *d;
    196 	void *cookie = NULL;
    197 
    198 	if (deathrow_handling_status == B_FALSE) {
    199 		log_framework(LOG_DEBUG, "Deathrow fini\n");
    200 		return;
    201 	}
    202 	deathrow_handling_stop();
    203 
    204 	while ((d = uu_list_teardown(deathrow_list, &cookie)) != NULL) {
    205 		startd_free(d->fmri, strlen(d->fmri) + 1);
    206 		startd_free(d, sizeof (deathrow_t));
    207 	}
    208 
    209 	uu_list_destroy(deathrow_list);
    210 	uu_list_pool_destroy(deathrow_pool);
    211 	deathrow_pool = NULL;
    212 	deathrow_list = NULL;
    213 	log_framework(LOG_DEBUG, "Deathrow fini\n");
    214 }
    215 
    216 static void
    217 deathrow_add(const char *fmri)
    218 {
    219 	deathrow_t *d;
    220 
    221 	assert(fmri != NULL);
    222 
    223 	d = startd_alloc(sizeof (deathrow_t));
    224 	d->fmri = startd_alloc(strlen(fmri) + 1);
    225 	(void) strcpy(d->fmri, fmri);
    226 	uu_list_node_init(d, &d->deathrow_link, deathrow_pool);
    227 	(void) uu_list_insert_after(deathrow_list, NULL, d);
    228 
    229 	log_framework(LOG_DEBUG, "Deathrow added <%s>\n", d->fmri);
    230 }
    231 
    232 static deathrow_t *
    233 fmri_in_deathrow_internal(const char *fmri)
    234 {
    235 	deathrow_t *d;
    236 
    237 	assert(fmri != NULL);
    238 	assert(deathrow_pool != NULL);
    239 	assert(deathrow_list != NULL);
    240 
    241 	for ((d = uu_list_first(deathrow_list)); d != NULL;
    242 	    d = uu_list_next(deathrow_list, d)) {
    243 		if (strcmp(fmri, d->fmri) == 0) {
    244 			return (d);
    245 		}
    246 	}
    247 	return (NULL);
    248 }
    249 
    250 boolean_t
    251 is_fmri_in_deathrow(const char *fmri)
    252 {
    253 	if (deathrow_handling_status == B_FALSE) {
    254 		return (B_FALSE);
    255 	}
    256 	return ((fmri_in_deathrow_internal(fmri) != NULL) ? B_TRUE : B_FALSE);
    257 }
    258