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 2007 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(void) 104 { 105 ulong_t rfsid, fsid; 106 pid_t init_pid; 107 int ret; 108 109 log_framework(LOG_DEBUG, "special_fsminimal_post_online hook " 110 "executed\n"); 111 112 /* 113 * If /var is still read-only, and it is on a separate filesystem, then 114 * attempt to mount it read-write now. 115 */ 116 if ((ret = fs_is_read_only("/var", &fsid)) == 1) { 117 (void) fs_is_read_only("/", &rfsid); 118 119 if (rfsid != fsid) { 120 log_framework(LOG_WARNING, "/var filesystem " 121 "read-only after system/filesystem/minimal\n"); 122 if (fs_remount("/var")) 123 log_framework(LOG_WARNING, "/var " 124 "filesystem remount failed\n"); 125 } 126 } 127 128 if ((ret = fs_is_read_only("/var", &fsid)) != 1) { 129 if (ret != 0) 130 log_error(LOG_WARNING, gettext("couldn't check status " 131 "of /var filesystem: %s\n"), strerror(errno)); 132 133 /* 134 * Clear (dead) entries and record boot time. 135 */ 136 utmpx_clear_old(); 137 utmpx_write_boottime(); 138 139 /* 140 * Reinitialize the logs to point to LOG_PREFIX_NORMAL. 141 */ 142 log_init(); 143 144 /* 145 * Poke init so it will create /var/run/initpipe. 146 */ 147 if (zone_getattr(getzoneid(), ZONE_ATTR_INITPID, &init_pid, 148 sizeof (init_pid)) != sizeof (init_pid)) { 149 log_error(LOG_WARNING, "Could not get pid of init: " 150 "%s.\n", strerror(errno)); 151 } else { 152 if (kill(init_pid, SIGHUP) != 0) { 153 switch (errno) { 154 case EPERM: 155 case ESRCH: 156 log_error(LOG_WARNING, 157 "Could not signal init: %s.\n", 158 strerror(errno)); 159 break; 160 161 case EINVAL: 162 default: 163 bad_error("kill", errno); 164 } 165 } 166 } 167 } 168 169 if ((ret = fs_is_read_only("/etc/svc", &fsid)) != 1) { 170 if (ret != 0) 171 log_error(LOG_WARNING, gettext("couldn't check status " 172 "of /etc/svc filesystem: %s\n"), strerror(errno)); 173 174 /* 175 * Take pending snapshots and create a svc.startd instance. 176 */ 177 (void) startd_thread_create(restarter_post_fsminimal_thread, 178 NULL); 179 } 180 } 181 182 static void 183 special_single_post_online(void) 184 { 185 int r; 186 187 log_framework(LOG_DEBUG, "special_single_post_online hook executed\n"); 188 189 /* 190 * Un-set the special reconfig reboot property. 191 */ 192 r = libscf_set_reconfig(0); 193 switch (r) { 194 case 0: 195 case ENOENT: 196 break; 197 198 case EPERM: 199 case EACCES: 200 case EROFS: 201 log_error(LOG_WARNING, "Could not clear reconfiguration " 202 "property: %s.\n", strerror(r)); 203 break; 204 205 default: 206 bad_error("libscf_set_reconfig", r); 207 } 208 209 if (booting_to_single_user) 210 (void) startd_thread_create(single_user_thread, NULL); 211 } 212 213 static service_hook_assn_t special_svcs[] = { 214 { "svc:/system/filesystem/root:default", 215 special_null_transition, 216 special_fsroot_post_online, 217 special_null_transition }, 218 { "svc:/system/filesystem/minimal:default", 219 special_null_transition, 220 special_fsminimal_post_online, 221 special_null_transition }, 222 { "svc:/milestone/single-user:default", 223 special_null_transition, 224 special_single_post_online, 225 special_null_transition }, 226 }; 227 228 void 229 special_online_hooks_get(const char *fmri, instance_hook_t *pre_onp, 230 instance_hook_t *post_onp, instance_hook_t *post_offp) 231 { 232 int i; 233 234 for (i = 0; i < sizeof (special_svcs) / sizeof (service_hook_assn_t); 235 i++) 236 if (strcmp(fmri, special_svcs[i].sh_fmri) == 0) { 237 *pre_onp = special_svcs[i].sh_pre_online_hook; 238 *post_onp = special_svcs[i].sh_post_online_hook; 239 *post_offp = special_svcs[i].sh_post_offline_hook; 240 return; 241 } 242 243 *pre_onp = *post_onp = *post_offp = special_null_transition; 244 } 245