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 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * specials.c - knowledge of special services 31 * 32 * svc.startd(1M) has duties that cannot be carried out without knowledge of the 33 * transition of various services, such as the milestones, to their online 34 * states. Hooks are called with the restarter instance's ri_lock held, so 35 * operations on all instances (or on the graph) should be performed 36 * asynchronously. 37 */ 38 39 #include <sys/statvfs.h> 40 #include <sys/types.h> 41 #include <assert.h> 42 #include <errno.h> 43 #include <libintl.h> 44 #include <limits.h> 45 #include <locale.h> 46 #include <pthread.h> 47 #include <signal.h> 48 #include <stdio.h> 49 #include <string.h> 50 #include <strings.h> 51 #include <time.h> 52 #include <zone.h> 53 54 #include "startd.h" 55 56 void 57 special_null_transition() 58 { 59 } 60 61 static void 62 special_fsroot_post_online() 63 { 64 static int once; 65 char *locale; 66 67 /* 68 * /usr, with timezone and locale data, is now available. 69 */ 70 if (!st->st_log_timezone_known) { 71 tzset(); 72 st->st_log_timezone_known = 1; 73 } 74 75 if (!st->st_log_locale_known) { 76 if (st->st_locale) 77 locale = st->st_locale; 78 79 (void) setlocale(LC_ALL, ""); 80 st->st_locale = setlocale(LC_MESSAGES, ""); 81 if (st->st_locale) { 82 st->st_locale = safe_strdup(st->st_locale); 83 xstr_sanitize(st->st_locale); 84 free(locale); 85 } else { 86 st->st_locale = locale; 87 } 88 89 (void) textdomain(TEXT_DOMAIN); 90 st->st_log_locale_known = 1; 91 } 92 93 if (once) 94 return; 95 96 /* 97 * ctime(3C) ends with '\n\0'. 98 */ 99 once++; 100 log_framework(LOG_INFO, "system start time was %s", 101 ctime(&st->st_start_time.tv_sec)); 102 } 103 104 static void 105 special_fsminimal_post_online() 106 { 107 ulong_t rfsid, vfsid; 108 pid_t init_pid; 109 110 log_framework(LOG_DEBUG, "special_fsminimal_post_online hook " 111 "executed\n"); 112 113 /* 114 * Are / and /var really writeable? 115 */ 116 switch (fs_is_read_only("/", &rfsid)) { 117 case 1: 118 return; /* still read-only: install / ro root */ 119 case 0: 120 break; 121 case -1: 122 default: 123 log_error(LOG_WARNING, gettext("couldn't check status of " 124 "root filesystem: %s\n"), strerror(errno)); 125 break; 126 } 127 128 switch (fs_is_read_only("/var", &vfsid)) { 129 case 1: 130 if (vfsid != rfsid) { 131 log_framework(LOG_WARNING, "/var filesystem " 132 "read-only after system/filesystem/minimal\n"); 133 if (fs_remount("/var")) 134 log_framework(LOG_WARNING, "/var " 135 "filesystem remount failed\n"); 136 } 137 break; 138 case 0: 139 break; 140 case -1: 141 default: 142 log_error(LOG_WARNING, gettext("couldn't check status of " 143 "/var filesystem: %s\n"), strerror(errno)); 144 break; 145 } 146 147 /* 148 * Clear (dead) entries and record boot time. 149 */ 150 utmpx_clear_old(); 151 utmpx_write_boottime(); 152 153 /* 154 * Reinitialize the logs to point to LOG_PREFIX_NORMAL. 155 */ 156 log_init(); 157 158 /* 159 * Poke init so it will create /etc/initpipe. 160 */ 161 if (zone_getattr(getzoneid(), ZONE_ATTR_INITPID, &init_pid, 162 sizeof (init_pid)) != sizeof (init_pid)) { 163 log_error(LOG_WARNING, "Could not get pid of init: %s.\n", 164 strerror(errno)); 165 } else { 166 if (kill(init_pid, SIGHUP) != 0) { 167 switch (errno) { 168 case EPERM: 169 case ESRCH: 170 log_error(LOG_WARNING, 171 "Could not signal init: %s.\n", 172 strerror(errno)); 173 break; 174 175 case EINVAL: 176 default: 177 bad_error("kill", errno); 178 } 179 } 180 } 181 182 /* 183 * Take pending snapshots and create a svc.startd instance. 184 */ 185 (void) startd_thread_create(restarter_post_fsminimal_thread, NULL); 186 } 187 188 static void 189 special_single_post_online() 190 { 191 int r; 192 193 log_framework(LOG_DEBUG, "special_single_post_online hook executed\n"); 194 195 /* 196 * Un-set the special reconfig reboot property. 197 */ 198 r = libscf_set_reconfig(0); 199 switch (r) { 200 case 0: 201 case ENOENT: 202 break; 203 204 case EPERM: 205 case EACCES: 206 case EROFS: 207 log_error(LOG_WARNING, "Could not clear reconfiguration " 208 "property: %s.\n", strerror(r)); 209 break; 210 211 default: 212 bad_error("libscf_set_reconfig", r); 213 } 214 215 if (booting_to_single_user) 216 (void) startd_thread_create(single_user_thread, NULL); 217 } 218 219 static service_hook_assn_t special_svcs[] = { 220 { "svc:/system/filesystem/root:default", 221 special_null_transition, 222 special_fsroot_post_online, 223 special_null_transition }, 224 { "svc:/system/filesystem/minimal:default", 225 special_null_transition, 226 special_fsminimal_post_online, 227 special_null_transition }, 228 { "svc:/milestone/single-user:default", 229 special_null_transition, 230 special_single_post_online, 231 special_null_transition }, 232 }; 233 234 void 235 special_online_hooks_get(const char *fmri, instance_hook_t *pre_onp, 236 instance_hook_t *post_onp, instance_hook_t *post_offp) 237 { 238 int i; 239 240 for (i = 0; i < sizeof (special_svcs) / sizeof (service_hook_assn_t); 241 i++) 242 if (strcmp(fmri, special_svcs[i].sh_fmri) == 0) { 243 *pre_onp = special_svcs[i].sh_pre_online_hook; 244 *post_onp = special_svcs[i].sh_post_online_hook; 245 *post_offp = special_svcs[i].sh_post_online_hook; 246 return; 247 } 248 249 *pre_onp = *post_onp = *post_offp = special_null_transition; 250 } 251