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 2005 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 locale = st->st_locale; 77 78 (void) setlocale(LC_ALL, ""); 79 st->st_locale = setlocale(LC_MESSAGES, ""); 80 if (st->st_locale) { 81 st->st_locale = safe_strdup(st->st_locale); 82 xstr_sanitize(st->st_locale); 83 free(locale); 84 } else { 85 st->st_locale = locale; 86 } 87 88 (void) textdomain(TEXT_DOMAIN); 89 st->st_log_locale_known = 1; 90 } 91 92 if (once) 93 return; 94 95 /* 96 * ctime(3C) ends with '\n\0'. 97 */ 98 once++; 99 log_framework(LOG_INFO, "system start time was %s", 100 ctime(&st->st_start_time.tv_sec)); 101 } 102 103 static void 104 special_fsminimal_post_online() 105 { 106 ulong_t rfsid, vfsid; 107 pid_t init_pid; 108 109 log_framework(LOG_DEBUG, "special_fsminimal_post_online hook " 110 "executed\n"); 111 112 /* 113 * Are / and /var really writeable? 114 */ 115 switch (fs_is_read_only("/", &rfsid)) { 116 case 1: 117 return; /* still read-only: install / ro root */ 118 case 0: 119 break; 120 case -1: 121 default: 122 log_error(LOG_WARNING, gettext("couldn't check status of " 123 "root filesystem: %s\n"), strerror(errno)); 124 break; 125 } 126 127 switch (fs_is_read_only("/var", &vfsid)) { 128 case 1: 129 if (vfsid != rfsid) { 130 log_framework(LOG_WARNING, "/var filesystem " 131 "read-only after system/filesystem/minimal\n"); 132 if (fs_remount("/var")) 133 log_framework(LOG_WARNING, "/var " 134 "filesystem remount failed\n"); 135 } 136 break; 137 case 0: 138 break; 139 case -1: 140 default: 141 log_error(LOG_WARNING, gettext("couldn't check status of " 142 "/var filesystem: %s\n"), strerror(errno)); 143 break; 144 } 145 146 /* 147 * Clear (dead) entries and record boot time. 148 */ 149 utmpx_clear_old(); 150 utmpx_write_boottime(); 151 152 /* 153 * Reinitialize the logs to point to LOG_PREFIX_NORMAL. 154 */ 155 log_init(); 156 157 /* 158 * Poke init so it will create /etc/initpipe. 159 */ 160 if (zone_getattr(getzoneid(), ZONE_ATTR_INITPID, &init_pid, 161 sizeof (init_pid)) != sizeof (init_pid)) { 162 log_error(LOG_WARNING, "Could not get pid of init: %s.\n", 163 strerror(errno)); 164 } else { 165 if (kill(init_pid, SIGHUP) != 0) { 166 switch (errno) { 167 case EPERM: 168 case ESRCH: 169 log_error(LOG_WARNING, 170 "Could not signal init: %s.\n", 171 strerror(errno)); 172 break; 173 174 case EINVAL: 175 default: 176 bad_error("kill", errno); 177 } 178 } 179 } 180 181 /* 182 * Take pending snapshots and create a svc.startd instance. 183 */ 184 (void) startd_thread_create(restarter_post_fsminimal_thread, NULL); 185 } 186 187 static void 188 special_single_post_online() 189 { 190 int r; 191 192 log_framework(LOG_DEBUG, "special_single_post_online hook executed\n"); 193 194 /* 195 * Un-set the special reconfig reboot property. 196 */ 197 r = libscf_set_reconfig(0); 198 switch (r) { 199 case 0: 200 case ENOENT: 201 break; 202 203 case EPERM: 204 case EACCES: 205 case EROFS: 206 log_error(LOG_WARNING, "Could not clear reconfiguration " 207 "property: %s.\n", strerror(r)); 208 break; 209 210 default: 211 bad_error("libscf_set_reconfig", r); 212 } 213 214 if (booting_to_single_user) 215 (void) startd_thread_create(single_user_thread, NULL); 216 } 217 218 static service_hook_assn_t special_svcs[] = { 219 { "svc:/system/filesystem/root:default", 220 special_null_transition, 221 special_fsroot_post_online, 222 special_null_transition }, 223 { "svc:/system/filesystem/minimal:default", 224 special_null_transition, 225 special_fsminimal_post_online, 226 special_null_transition }, 227 { "svc:/milestone/single-user:default", 228 special_null_transition, 229 special_single_post_online, 230 special_null_transition }, 231 }; 232 233 void 234 special_online_hooks_get(const char *fmri, instance_hook_t *pre_onp, 235 instance_hook_t *post_onp, instance_hook_t *post_offp) 236 { 237 int i; 238 239 for (i = 0; i < sizeof (special_svcs) / sizeof (service_hook_assn_t); 240 i++) 241 if (strcmp(fmri, special_svcs[i].sh_fmri) == 0) { 242 *pre_onp = special_svcs[i].sh_pre_online_hook; 243 *post_onp = special_svcs[i].sh_post_online_hook; 244 *post_offp = special_svcs[i].sh_post_online_hook; 245 return; 246 } 247 248 *pre_onp = *post_onp = *post_offp = special_null_transition; 249 } 250