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