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