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