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