1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate /* 30*0Sstevel@tonic-gate * lsvcrun - run an rc?.d script, modifying appropriate data in the 31*0Sstevel@tonic-gate * repository to reflect legacy behavior. 32*0Sstevel@tonic-gate * 33*0Sstevel@tonic-gate * We try to keep track of what we can for the legacy scripts via 34*0Sstevel@tonic-gate * property groups under the smf/legacy_run service. Each property 35*0Sstevel@tonic-gate * group identifies a service, named in the form 'rc2_d_S10foo'. 36*0Sstevel@tonic-gate * 37*0Sstevel@tonic-gate * Each group has the following properties: name, the script name 38*0Sstevel@tonic-gate * displayed by svcs(1m); state_timestamp; contract, contract ID; 39*0Sstevel@tonic-gate * inode, the inode of the script; and suffix, the suffix of the 40*0Sstevel@tonic-gate * script name, e.g. 'foo'. 41*0Sstevel@tonic-gate * 42*0Sstevel@tonic-gate * When we run a K script, we try to identify and remove the 43*0Sstevel@tonic-gate * property group by means of examining the inode and script 44*0Sstevel@tonic-gate * suffix. The inode check means more than one script with the 45*0Sstevel@tonic-gate * same suffix will still work as intended in the common case. 46*0Sstevel@tonic-gate * 47*0Sstevel@tonic-gate * If we cannot find a property group, or one already exists 48*0Sstevel@tonic-gate * when we try to add one, then we print a suitable warning. These 49*0Sstevel@tonic-gate * are warnings because there was no strict requirement that K 50*0Sstevel@tonic-gate * and S scripts be matched up. 51*0Sstevel@tonic-gate * 52*0Sstevel@tonic-gate * In the face of these assumptions being proved wrong, we always 53*0Sstevel@tonic-gate * make sure to execute the script anyway in an attempt to keep 54*0Sstevel@tonic-gate * things working as they used to. If we can't execute the script, 55*0Sstevel@tonic-gate * we try to leave the repository in the state it was before. 56*0Sstevel@tonic-gate */ 57*0Sstevel@tonic-gate 58*0Sstevel@tonic-gate #include <sys/ctfs.h> 59*0Sstevel@tonic-gate #include <sys/types.h> 60*0Sstevel@tonic-gate #include <sys/wait.h> 61*0Sstevel@tonic-gate #include <sys/stat.h> 62*0Sstevel@tonic-gate #include <assert.h> 63*0Sstevel@tonic-gate #include <ctype.h> 64*0Sstevel@tonic-gate #include <errno.h> 65*0Sstevel@tonic-gate #include <fcntl.h> 66*0Sstevel@tonic-gate #include <fnmatch.h> 67*0Sstevel@tonic-gate #include <libcontract.h> 68*0Sstevel@tonic-gate #include <libcontract_priv.h> 69*0Sstevel@tonic-gate #include <libintl.h> 70*0Sstevel@tonic-gate #include <libscf.h> 71*0Sstevel@tonic-gate #include <libscf_priv.h> 72*0Sstevel@tonic-gate #include <libuutil.h> 73*0Sstevel@tonic-gate #include <signal.h> 74*0Sstevel@tonic-gate #include <stdio.h> 75*0Sstevel@tonic-gate #include <stdlib.h> 76*0Sstevel@tonic-gate #include <string.h> 77*0Sstevel@tonic-gate #include <strings.h> 78*0Sstevel@tonic-gate #include <time.h> 79*0Sstevel@tonic-gate #include <unistd.h> 80*0Sstevel@tonic-gate #include <limits.h> 81*0Sstevel@tonic-gate 82*0Sstevel@tonic-gate 83*0Sstevel@tonic-gate /* Environment variables to pass on. See clean_environment(). */ 84*0Sstevel@tonic-gate static char *evars_to_pass[] = { "LANG", "LC_ALL", "LC_COLLATE", "LC_CTYPE", 85*0Sstevel@tonic-gate "LC_MESSAGES", "LC_MONETARY", "LC_NUMERIC", "LC_TIME", "PATH", "TZ" 86*0Sstevel@tonic-gate }; 87*0Sstevel@tonic-gate 88*0Sstevel@tonic-gate #define EVARS_TO_PASS_NUM \ 89*0Sstevel@tonic-gate (sizeof (evars_to_pass) / sizeof (*evars_to_pass)) 90*0Sstevel@tonic-gate 91*0Sstevel@tonic-gate 92*0Sstevel@tonic-gate static void 93*0Sstevel@tonic-gate usage() 94*0Sstevel@tonic-gate { 95*0Sstevel@tonic-gate (void) fprintf(stderr, 96*0Sstevel@tonic-gate gettext("Usage: %s [-s] script {start | stop}\n"), uu_getpname()); 97*0Sstevel@tonic-gate exit(UU_EXIT_USAGE); 98*0Sstevel@tonic-gate } 99*0Sstevel@tonic-gate 100*0Sstevel@tonic-gate /* 101*0Sstevel@tonic-gate * Pick out the script name and convert it for use as an SMF property 102*0Sstevel@tonic-gate * group name. 103*0Sstevel@tonic-gate */ 104*0Sstevel@tonic-gate static char * 105*0Sstevel@tonic-gate start_pg_name(const char *path) 106*0Sstevel@tonic-gate { 107*0Sstevel@tonic-gate char *out, *cp; 108*0Sstevel@tonic-gate 109*0Sstevel@tonic-gate if (fnmatch("/etc/rc[0-6S].d/S*", path, FNM_PATHNAME) != 0) { 110*0Sstevel@tonic-gate uu_warn(gettext("couldn't parse name %s.\n"), path); 111*0Sstevel@tonic-gate return (NULL); 112*0Sstevel@tonic-gate } 113*0Sstevel@tonic-gate 114*0Sstevel@tonic-gate out = strdup(path + sizeof ("/etc/") - 1); 115*0Sstevel@tonic-gate 116*0Sstevel@tonic-gate if (out == NULL) { 117*0Sstevel@tonic-gate uu_warn(gettext("strdup() failed (%s).\n"), strerror(errno)); 118*0Sstevel@tonic-gate return (NULL); 119*0Sstevel@tonic-gate } 120*0Sstevel@tonic-gate 121*0Sstevel@tonic-gate /* Convert illegal characters to _. */ 122*0Sstevel@tonic-gate for (cp = out; *cp != '\0'; ++cp) { 123*0Sstevel@tonic-gate /* locale problem? */ 124*0Sstevel@tonic-gate if (!isalnum(*cp) && *cp != '-') 125*0Sstevel@tonic-gate *cp = '_'; 126*0Sstevel@tonic-gate } 127*0Sstevel@tonic-gate 128*0Sstevel@tonic-gate return (out); 129*0Sstevel@tonic-gate } 130*0Sstevel@tonic-gate 131*0Sstevel@tonic-gate static char * 132*0Sstevel@tonic-gate script_suffix(const char *path) 133*0Sstevel@tonic-gate { 134*0Sstevel@tonic-gate const char *cp; 135*0Sstevel@tonic-gate char *out; 136*0Sstevel@tonic-gate 137*0Sstevel@tonic-gate if (fnmatch("/etc/rc[0-6S].d/[SK]*", path, FNM_PATHNAME) != 0) { 138*0Sstevel@tonic-gate uu_warn(gettext("couldn't parse name %s.\n"), path); 139*0Sstevel@tonic-gate return (NULL); 140*0Sstevel@tonic-gate } 141*0Sstevel@tonic-gate 142*0Sstevel@tonic-gate cp = path + sizeof ("/etc/rc0.d/S") - 1; 143*0Sstevel@tonic-gate 144*0Sstevel@tonic-gate while (isdigit(*cp)) 145*0Sstevel@tonic-gate cp++; 146*0Sstevel@tonic-gate 147*0Sstevel@tonic-gate if (*cp == '\0') { 148*0Sstevel@tonic-gate uu_warn(gettext("couldn't parse name %s.\n"), path); 149*0Sstevel@tonic-gate return (NULL); 150*0Sstevel@tonic-gate } 151*0Sstevel@tonic-gate 152*0Sstevel@tonic-gate out = strdup(cp); 153*0Sstevel@tonic-gate if (out == NULL) 154*0Sstevel@tonic-gate uu_warn(gettext("strdup() failed (%s).\n"), strerror(errno)); 155*0Sstevel@tonic-gate 156*0Sstevel@tonic-gate return (out); 157*0Sstevel@tonic-gate } 158*0Sstevel@tonic-gate 159*0Sstevel@tonic-gate /* 160*0Sstevel@tonic-gate * Convert a path to an acceptable SMF (service) name. 161*0Sstevel@tonic-gate */ 162*0Sstevel@tonic-gate static char * 163*0Sstevel@tonic-gate path_to_svc_name(const char *path) 164*0Sstevel@tonic-gate { 165*0Sstevel@tonic-gate char *out, *cp; 166*0Sstevel@tonic-gate 167*0Sstevel@tonic-gate out = strdup(path); 168*0Sstevel@tonic-gate if (out == NULL) { 169*0Sstevel@tonic-gate uu_warn(gettext("strdup() failed (%s).\n"), strerror(errno)); 170*0Sstevel@tonic-gate return (NULL); 171*0Sstevel@tonic-gate } 172*0Sstevel@tonic-gate 173*0Sstevel@tonic-gate /* Convert illegal characters to _. */ 174*0Sstevel@tonic-gate for (cp = out; *cp != '\0'; ++cp) { 175*0Sstevel@tonic-gate /* locale problem? */ 176*0Sstevel@tonic-gate if (!isalnum(*cp) && *cp != '-' && *cp != '/') 177*0Sstevel@tonic-gate *cp = '_'; 178*0Sstevel@tonic-gate } 179*0Sstevel@tonic-gate 180*0Sstevel@tonic-gate /* If the first character is _, use a instead. */ 181*0Sstevel@tonic-gate if (*out == '_') 182*0Sstevel@tonic-gate *out = 'a'; 183*0Sstevel@tonic-gate 184*0Sstevel@tonic-gate return (out); 185*0Sstevel@tonic-gate } 186*0Sstevel@tonic-gate 187*0Sstevel@tonic-gate static void 188*0Sstevel@tonic-gate scferr(const char *func) 189*0Sstevel@tonic-gate { 190*0Sstevel@tonic-gate uu_warn(gettext("%s failed (%s). Repository will not be modified.\n"), 191*0Sstevel@tonic-gate func, scf_strerror(scf_error())); 192*0Sstevel@tonic-gate } 193*0Sstevel@tonic-gate 194*0Sstevel@tonic-gate static scf_propertygroup_t * 195*0Sstevel@tonic-gate get_start_pg(const char *script, scf_handle_t *h, scf_service_t *svc, 196*0Sstevel@tonic-gate boolean_t *ok) 197*0Sstevel@tonic-gate { 198*0Sstevel@tonic-gate char *pg_name = NULL; 199*0Sstevel@tonic-gate scf_propertygroup_t *pg = NULL; 200*0Sstevel@tonic-gate scf_property_t *prop = NULL; 201*0Sstevel@tonic-gate 202*0Sstevel@tonic-gate if ((pg_name = start_pg_name(script)) == NULL) 203*0Sstevel@tonic-gate return (NULL); 204*0Sstevel@tonic-gate 205*0Sstevel@tonic-gate if ((pg = scf_pg_create(h)) == NULL) { 206*0Sstevel@tonic-gate scferr("scf_pg_create()"); 207*0Sstevel@tonic-gate goto out; 208*0Sstevel@tonic-gate } 209*0Sstevel@tonic-gate 210*0Sstevel@tonic-gate add: 211*0Sstevel@tonic-gate if (scf_service_add_pg(svc, pg_name, SCF_GROUP_FRAMEWORK, 212*0Sstevel@tonic-gate SCF_PG_FLAG_NONPERSISTENT, pg) == 0) { 213*0Sstevel@tonic-gate *ok = 1; 214*0Sstevel@tonic-gate free(pg_name); 215*0Sstevel@tonic-gate return (pg); 216*0Sstevel@tonic-gate } 217*0Sstevel@tonic-gate 218*0Sstevel@tonic-gate switch (scf_error()) { 219*0Sstevel@tonic-gate case SCF_ERROR_INVALID_ARGUMENT: 220*0Sstevel@tonic-gate assert(0); 221*0Sstevel@tonic-gate abort(); 222*0Sstevel@tonic-gate /* NOTREACHED */ 223*0Sstevel@tonic-gate 224*0Sstevel@tonic-gate case SCF_ERROR_EXISTS: 225*0Sstevel@tonic-gate break; 226*0Sstevel@tonic-gate 227*0Sstevel@tonic-gate case SCF_ERROR_PERMISSION_DENIED: 228*0Sstevel@tonic-gate uu_die(gettext( 229*0Sstevel@tonic-gate "Insufficient privilege to add repository properties; " 230*0Sstevel@tonic-gate "not launching \"%s\".\n"), script); 231*0Sstevel@tonic-gate /* NOTREACHED */ 232*0Sstevel@tonic-gate 233*0Sstevel@tonic-gate default: 234*0Sstevel@tonic-gate scferr("scf_service_add_pg()"); 235*0Sstevel@tonic-gate scf_pg_destroy(pg); 236*0Sstevel@tonic-gate pg = NULL; 237*0Sstevel@tonic-gate goto out; 238*0Sstevel@tonic-gate } 239*0Sstevel@tonic-gate 240*0Sstevel@tonic-gate if (scf_service_get_pg(svc, pg_name, pg) != 0) { 241*0Sstevel@tonic-gate switch (scf_error()) { 242*0Sstevel@tonic-gate case SCF_ERROR_INVALID_ARGUMENT: 243*0Sstevel@tonic-gate assert(0); 244*0Sstevel@tonic-gate abort(); 245*0Sstevel@tonic-gate /* NOTREACHED */ 246*0Sstevel@tonic-gate 247*0Sstevel@tonic-gate case SCF_ERROR_NOT_FOUND: 248*0Sstevel@tonic-gate goto add; 249*0Sstevel@tonic-gate 250*0Sstevel@tonic-gate default: 251*0Sstevel@tonic-gate scferr("scf_service_get_pg()"); 252*0Sstevel@tonic-gate scf_pg_destroy(pg); 253*0Sstevel@tonic-gate pg = NULL; 254*0Sstevel@tonic-gate goto out; 255*0Sstevel@tonic-gate } 256*0Sstevel@tonic-gate } 257*0Sstevel@tonic-gate 258*0Sstevel@tonic-gate if ((prop = scf_property_create(h)) == NULL) { 259*0Sstevel@tonic-gate scferr("scf_property_create()"); 260*0Sstevel@tonic-gate scf_pg_destroy(pg); 261*0Sstevel@tonic-gate pg = NULL; 262*0Sstevel@tonic-gate goto out; 263*0Sstevel@tonic-gate } 264*0Sstevel@tonic-gate 265*0Sstevel@tonic-gate /* 266*0Sstevel@tonic-gate * See if the pg has the name property. If it has, that 267*0Sstevel@tonic-gate * implies we successfully ran the same script before. We 268*0Sstevel@tonic-gate * should re-run it anyway, but not modify the existing pg; 269*0Sstevel@tonic-gate * this might lose contract-control but there's not much we 270*0Sstevel@tonic-gate * can do. 271*0Sstevel@tonic-gate * 272*0Sstevel@tonic-gate * If there's no name property, then we probably couldn't 273*0Sstevel@tonic-gate * remove the pg fully after a script failed to run. 274*0Sstevel@tonic-gate */ 275*0Sstevel@tonic-gate 276*0Sstevel@tonic-gate if (scf_pg_get_property(pg, SCF_LEGACY_PROPERTY_NAME, prop) == 0) { 277*0Sstevel@tonic-gate uu_warn(gettext("Service matching \"%s\" " 278*0Sstevel@tonic-gate "seems to be running.\n"), script); 279*0Sstevel@tonic-gate scf_pg_destroy(pg); 280*0Sstevel@tonic-gate pg = NULL; 281*0Sstevel@tonic-gate } else if (scf_error() != SCF_ERROR_NOT_FOUND) { 282*0Sstevel@tonic-gate scferr("scf_pg_get_property()"); 283*0Sstevel@tonic-gate scf_pg_destroy(pg); 284*0Sstevel@tonic-gate pg = NULL; 285*0Sstevel@tonic-gate } else { 286*0Sstevel@tonic-gate uu_warn(gettext("Service \"%s\" has an invalid property " 287*0Sstevel@tonic-gate "group.\n"), script); 288*0Sstevel@tonic-gate } 289*0Sstevel@tonic-gate 290*0Sstevel@tonic-gate out: 291*0Sstevel@tonic-gate free(pg_name); 292*0Sstevel@tonic-gate scf_property_destroy(prop); 293*0Sstevel@tonic-gate return (pg); 294*0Sstevel@tonic-gate } 295*0Sstevel@tonic-gate 296*0Sstevel@tonic-gate static scf_propertygroup_t * 297*0Sstevel@tonic-gate pg_match(scf_handle_t *h, scf_service_t *svc, ino_t ino, const char *suffix) 298*0Sstevel@tonic-gate { 299*0Sstevel@tonic-gate char buf[PATH_MAX]; 300*0Sstevel@tonic-gate scf_iter_t *iter = NULL; 301*0Sstevel@tonic-gate scf_propertygroup_t *pg = NULL; 302*0Sstevel@tonic-gate scf_property_t *prop = NULL; 303*0Sstevel@tonic-gate scf_value_t *val = NULL; 304*0Sstevel@tonic-gate 305*0Sstevel@tonic-gate if ((pg = scf_pg_create(h)) == NULL) { 306*0Sstevel@tonic-gate scferr("scf_pg_create()"); 307*0Sstevel@tonic-gate goto err; 308*0Sstevel@tonic-gate } 309*0Sstevel@tonic-gate 310*0Sstevel@tonic-gate if ((iter = scf_iter_create(h)) == NULL) { 311*0Sstevel@tonic-gate scferr("scf_iter_create()"); 312*0Sstevel@tonic-gate goto err; 313*0Sstevel@tonic-gate } 314*0Sstevel@tonic-gate 315*0Sstevel@tonic-gate if ((prop = scf_property_create(h)) == NULL) { 316*0Sstevel@tonic-gate scferr("scf_property_create()"); 317*0Sstevel@tonic-gate goto err; 318*0Sstevel@tonic-gate } 319*0Sstevel@tonic-gate 320*0Sstevel@tonic-gate if ((val = scf_value_create(h)) == NULL) { 321*0Sstevel@tonic-gate scferr("scf_value_create()"); 322*0Sstevel@tonic-gate goto err; 323*0Sstevel@tonic-gate } 324*0Sstevel@tonic-gate 325*0Sstevel@tonic-gate if (scf_iter_service_pgs_typed(iter, svc, SCF_GROUP_FRAMEWORK) != 326*0Sstevel@tonic-gate 0) { 327*0Sstevel@tonic-gate scferr("scf_iter_service_pgs_typed()"); 328*0Sstevel@tonic-gate goto err; 329*0Sstevel@tonic-gate } 330*0Sstevel@tonic-gate 331*0Sstevel@tonic-gate while (scf_iter_next_pg(iter, pg) > 0) { 332*0Sstevel@tonic-gate int match = 1; 333*0Sstevel@tonic-gate 334*0Sstevel@tonic-gate if (suffix != NULL) { 335*0Sstevel@tonic-gate ssize_t len; 336*0Sstevel@tonic-gate 337*0Sstevel@tonic-gate if (scf_pg_get_property(pg, SCF_LEGACY_PROPERTY_SUFFIX, 338*0Sstevel@tonic-gate prop) != 0) 339*0Sstevel@tonic-gate continue; 340*0Sstevel@tonic-gate 341*0Sstevel@tonic-gate if (scf_property_get_value(prop, val) != 0) 342*0Sstevel@tonic-gate continue; 343*0Sstevel@tonic-gate 344*0Sstevel@tonic-gate len = scf_value_get_astring(val, buf, sizeof (buf)); 345*0Sstevel@tonic-gate if (len < 0) { 346*0Sstevel@tonic-gate scferr("scf_value_get_astring()"); 347*0Sstevel@tonic-gate goto err; 348*0Sstevel@tonic-gate } 349*0Sstevel@tonic-gate if (len >= sizeof (buf)) 350*0Sstevel@tonic-gate continue; 351*0Sstevel@tonic-gate 352*0Sstevel@tonic-gate match = (strcmp(buf, suffix) == 0); 353*0Sstevel@tonic-gate } 354*0Sstevel@tonic-gate 355*0Sstevel@tonic-gate if (ino != 0) { 356*0Sstevel@tonic-gate uint64_t pval; 357*0Sstevel@tonic-gate 358*0Sstevel@tonic-gate if (scf_pg_get_property(pg, SCF_LEGACY_PROPERTY_INODE, 359*0Sstevel@tonic-gate prop) != 0) 360*0Sstevel@tonic-gate continue; 361*0Sstevel@tonic-gate 362*0Sstevel@tonic-gate if (scf_property_get_value(prop, val) != 0) 363*0Sstevel@tonic-gate continue; 364*0Sstevel@tonic-gate 365*0Sstevel@tonic-gate if (scf_value_get_count(val, &pval) != 0) 366*0Sstevel@tonic-gate continue; 367*0Sstevel@tonic-gate 368*0Sstevel@tonic-gate match = (ino == pval) && match; 369*0Sstevel@tonic-gate } 370*0Sstevel@tonic-gate 371*0Sstevel@tonic-gate if (match) 372*0Sstevel@tonic-gate goto out; 373*0Sstevel@tonic-gate } 374*0Sstevel@tonic-gate 375*0Sstevel@tonic-gate err: 376*0Sstevel@tonic-gate scf_pg_destroy(pg); 377*0Sstevel@tonic-gate pg = NULL; 378*0Sstevel@tonic-gate 379*0Sstevel@tonic-gate out: 380*0Sstevel@tonic-gate scf_value_destroy(val); 381*0Sstevel@tonic-gate scf_iter_destroy(iter); 382*0Sstevel@tonic-gate scf_property_destroy(prop); 383*0Sstevel@tonic-gate return (pg); 384*0Sstevel@tonic-gate } 385*0Sstevel@tonic-gate 386*0Sstevel@tonic-gate /* 387*0Sstevel@tonic-gate * Try and find the property group matching the service this script 388*0Sstevel@tonic-gate * stops. First we look for a matching inode plus a matching suffix. 389*0Sstevel@tonic-gate * This commonly succeeds, but if not, we just search for inode. 390*0Sstevel@tonic-gate * Finally, we try for just the script suffix. 391*0Sstevel@tonic-gate */ 392*0Sstevel@tonic-gate static scf_propertygroup_t * 393*0Sstevel@tonic-gate get_stop_pg(const char *script, scf_handle_t *h, scf_service_t *svc, 394*0Sstevel@tonic-gate boolean_t *ok) 395*0Sstevel@tonic-gate { 396*0Sstevel@tonic-gate struct stat st; 397*0Sstevel@tonic-gate char *suffix; 398*0Sstevel@tonic-gate scf_propertygroup_t *pg; 399*0Sstevel@tonic-gate 400*0Sstevel@tonic-gate if (stat(script, &st) != 0) { 401*0Sstevel@tonic-gate uu_warn(gettext("Couldn't stat %s (%s).\n"), script, 402*0Sstevel@tonic-gate strerror(errno)); 403*0Sstevel@tonic-gate return (NULL); 404*0Sstevel@tonic-gate } 405*0Sstevel@tonic-gate 406*0Sstevel@tonic-gate if ((suffix = script_suffix(script)) == NULL) { 407*0Sstevel@tonic-gate pg = pg_match(h, svc, st.st_ino, NULL); 408*0Sstevel@tonic-gate if (pg != NULL) 409*0Sstevel@tonic-gate goto out; 410*0Sstevel@tonic-gate return (NULL); 411*0Sstevel@tonic-gate } 412*0Sstevel@tonic-gate 413*0Sstevel@tonic-gate if ((pg = pg_match(h, svc, st.st_ino, suffix)) != NULL) 414*0Sstevel@tonic-gate goto out; 415*0Sstevel@tonic-gate 416*0Sstevel@tonic-gate if ((pg = pg_match(h, svc, st.st_ino, NULL)) != NULL) 417*0Sstevel@tonic-gate goto out; 418*0Sstevel@tonic-gate 419*0Sstevel@tonic-gate if ((pg = pg_match(h, svc, 0, suffix)) == NULL) { 420*0Sstevel@tonic-gate uu_warn(gettext("Service matching \"%s\" " 421*0Sstevel@tonic-gate "doesn't seem to be running.\n"), script); 422*0Sstevel@tonic-gate free(suffix); 423*0Sstevel@tonic-gate return (NULL); 424*0Sstevel@tonic-gate } 425*0Sstevel@tonic-gate 426*0Sstevel@tonic-gate out: 427*0Sstevel@tonic-gate *ok = 1; 428*0Sstevel@tonic-gate free(suffix); 429*0Sstevel@tonic-gate return (pg); 430*0Sstevel@tonic-gate } 431*0Sstevel@tonic-gate 432*0Sstevel@tonic-gate static scf_propertygroup_t * 433*0Sstevel@tonic-gate get_script_pg(const char *script, boolean_t start_flag, boolean_t *ok) 434*0Sstevel@tonic-gate { 435*0Sstevel@tonic-gate scf_handle_t *h = NULL; 436*0Sstevel@tonic-gate scf_scope_t *scope = NULL; 437*0Sstevel@tonic-gate scf_service_t *svc = NULL; 438*0Sstevel@tonic-gate scf_propertygroup_t *pg = NULL; 439*0Sstevel@tonic-gate 440*0Sstevel@tonic-gate *ok = 0; 441*0Sstevel@tonic-gate 442*0Sstevel@tonic-gate h = scf_handle_create(SCF_VERSION); 443*0Sstevel@tonic-gate if (h == NULL) { 444*0Sstevel@tonic-gate scferr("scf_handle_create()"); 445*0Sstevel@tonic-gate goto out; 446*0Sstevel@tonic-gate } 447*0Sstevel@tonic-gate 448*0Sstevel@tonic-gate if (scf_handle_bind(h) != 0) { 449*0Sstevel@tonic-gate if (scf_error() != SCF_ERROR_NO_SERVER) { 450*0Sstevel@tonic-gate scferr("scf_handle_bind()"); 451*0Sstevel@tonic-gate } else { 452*0Sstevel@tonic-gate uu_warn(gettext( 453*0Sstevel@tonic-gate "Could not connect to svc.configd.\n")); 454*0Sstevel@tonic-gate } 455*0Sstevel@tonic-gate goto out; 456*0Sstevel@tonic-gate } 457*0Sstevel@tonic-gate 458*0Sstevel@tonic-gate if ((scope = scf_scope_create(h)) == NULL) { 459*0Sstevel@tonic-gate scferr("scf_scope_create()"); 460*0Sstevel@tonic-gate goto out; 461*0Sstevel@tonic-gate } 462*0Sstevel@tonic-gate 463*0Sstevel@tonic-gate if ((svc = scf_service_create(h)) == NULL) { 464*0Sstevel@tonic-gate scferr("scf_service_create()"); 465*0Sstevel@tonic-gate goto out; 466*0Sstevel@tonic-gate } 467*0Sstevel@tonic-gate 468*0Sstevel@tonic-gate if (scf_handle_get_scope(h, SCF_SCOPE_LOCAL, scope) != 0) { 469*0Sstevel@tonic-gate scferr("scf_handle_get_local_scope()"); 470*0Sstevel@tonic-gate goto out; 471*0Sstevel@tonic-gate } 472*0Sstevel@tonic-gate 473*0Sstevel@tonic-gate if (scf_scope_get_service(scope, SCF_LEGACY_SERVICE, svc) != 0) { 474*0Sstevel@tonic-gate if (scf_error() != SCF_ERROR_NOT_FOUND) { 475*0Sstevel@tonic-gate scferr("scf_scope_get_service()"); 476*0Sstevel@tonic-gate goto out; 477*0Sstevel@tonic-gate } 478*0Sstevel@tonic-gate 479*0Sstevel@tonic-gate if (scf_scope_add_service(scope, SCF_LEGACY_SERVICE, svc) != 480*0Sstevel@tonic-gate 0) { 481*0Sstevel@tonic-gate scferr("scf_scope_add_service()"); 482*0Sstevel@tonic-gate goto out; 483*0Sstevel@tonic-gate } 484*0Sstevel@tonic-gate } 485*0Sstevel@tonic-gate 486*0Sstevel@tonic-gate if (start_flag) 487*0Sstevel@tonic-gate pg = get_start_pg(script, h, svc, ok); 488*0Sstevel@tonic-gate else 489*0Sstevel@tonic-gate pg = get_stop_pg(script, h, svc, ok); 490*0Sstevel@tonic-gate 491*0Sstevel@tonic-gate out: 492*0Sstevel@tonic-gate scf_service_destroy(svc); 493*0Sstevel@tonic-gate scf_scope_destroy(scope); 494*0Sstevel@tonic-gate return (pg); 495*0Sstevel@tonic-gate } 496*0Sstevel@tonic-gate 497*0Sstevel@tonic-gate static int 498*0Sstevel@tonic-gate prepare_contract() 499*0Sstevel@tonic-gate { 500*0Sstevel@tonic-gate int fd; 501*0Sstevel@tonic-gate 502*0Sstevel@tonic-gate do 503*0Sstevel@tonic-gate fd = open64(CTFS_ROOT "/process/template", O_RDWR); 504*0Sstevel@tonic-gate while (fd < 0 && errno == EINTR); 505*0Sstevel@tonic-gate if (fd < 0) { 506*0Sstevel@tonic-gate uu_warn(gettext("Can not create contract")); 507*0Sstevel@tonic-gate return (-1); 508*0Sstevel@tonic-gate } 509*0Sstevel@tonic-gate 510*0Sstevel@tonic-gate /* Leave HWERR in fatal set. */ 511*0Sstevel@tonic-gate 512*0Sstevel@tonic-gate errno = ct_tmpl_activate(fd); 513*0Sstevel@tonic-gate if (errno != 0) { 514*0Sstevel@tonic-gate assert(errno == EPERM); 515*0Sstevel@tonic-gate uu_warn(gettext("Can not activate contract template")); 516*0Sstevel@tonic-gate (void) close(fd); 517*0Sstevel@tonic-gate return (-1); 518*0Sstevel@tonic-gate } 519*0Sstevel@tonic-gate 520*0Sstevel@tonic-gate (void) close(fd); 521*0Sstevel@tonic-gate return (0); 522*0Sstevel@tonic-gate } 523*0Sstevel@tonic-gate 524*0Sstevel@tonic-gate static void 525*0Sstevel@tonic-gate cleanup_pg(scf_propertygroup_t *pg) 526*0Sstevel@tonic-gate { 527*0Sstevel@tonic-gate scf_error_t err; 528*0Sstevel@tonic-gate char buf[80]; 529*0Sstevel@tonic-gate 530*0Sstevel@tonic-gate if (scf_pg_delete(pg) == 0) 531*0Sstevel@tonic-gate return; 532*0Sstevel@tonic-gate 533*0Sstevel@tonic-gate err = scf_error(); 534*0Sstevel@tonic-gate 535*0Sstevel@tonic-gate if (scf_pg_to_fmri(pg, buf, sizeof (buf)) != 0) 536*0Sstevel@tonic-gate (void) strcpy(buf, "?"); 537*0Sstevel@tonic-gate 538*0Sstevel@tonic-gate uu_warn(gettext("Could not remove property group %s: %s.\n"), buf, 539*0Sstevel@tonic-gate scf_strerror(err)); 540*0Sstevel@tonic-gate } 541*0Sstevel@tonic-gate 542*0Sstevel@tonic-gate /* 543*0Sstevel@tonic-gate * Create a duplicate environment which only contains approved 544*0Sstevel@tonic-gate * variables---those in evars_to_pass and those beginning with "_INIT_". 545*0Sstevel@tonic-gate */ 546*0Sstevel@tonic-gate static char ** 547*0Sstevel@tonic-gate approved_env(char **env) 548*0Sstevel@tonic-gate { 549*0Sstevel@tonic-gate char **newenv; 550*0Sstevel@tonic-gate int i, i_new, j; 551*0Sstevel@tonic-gate 552*0Sstevel@tonic-gate for (i = 0; env[i] != NULL; ++i) 553*0Sstevel@tonic-gate ; 554*0Sstevel@tonic-gate 555*0Sstevel@tonic-gate newenv = malloc(sizeof (*newenv) * (i + 1)); 556*0Sstevel@tonic-gate if (newenv == NULL) 557*0Sstevel@tonic-gate return (NULL); 558*0Sstevel@tonic-gate 559*0Sstevel@tonic-gate i_new = 0; 560*0Sstevel@tonic-gate 561*0Sstevel@tonic-gate for (i = 0; env[i] != NULL; ++i) { 562*0Sstevel@tonic-gate if (strncmp(env[i], "_INIT_", sizeof ("_INIT_") - 1) == 0) { 563*0Sstevel@tonic-gate newenv[i_new++] = env[i]; 564*0Sstevel@tonic-gate continue; 565*0Sstevel@tonic-gate } 566*0Sstevel@tonic-gate 567*0Sstevel@tonic-gate for (j = 0; j < EVARS_TO_PASS_NUM; ++j) { 568*0Sstevel@tonic-gate size_t l = strlen(evars_to_pass[j]); 569*0Sstevel@tonic-gate 570*0Sstevel@tonic-gate if (env[i][l] == '=' && 571*0Sstevel@tonic-gate strncmp(env[i], evars_to_pass[j], l) == 0) 572*0Sstevel@tonic-gate newenv[i_new++] = env[i]; 573*0Sstevel@tonic-gate } 574*0Sstevel@tonic-gate } 575*0Sstevel@tonic-gate 576*0Sstevel@tonic-gate newenv[i_new] = NULL; 577*0Sstevel@tonic-gate 578*0Sstevel@tonic-gate return (newenv); 579*0Sstevel@tonic-gate } 580*0Sstevel@tonic-gate 581*0Sstevel@tonic-gate /* 582*0Sstevel@tonic-gate * Create a duplicate environment which does not contain any SMF_ variables. 583*0Sstevel@tonic-gate */ 584*0Sstevel@tonic-gate static char ** 585*0Sstevel@tonic-gate env_without_smf(char **env) 586*0Sstevel@tonic-gate { 587*0Sstevel@tonic-gate char **newenv; 588*0Sstevel@tonic-gate int i, i_new; 589*0Sstevel@tonic-gate 590*0Sstevel@tonic-gate for (i = 0; env[i] != NULL; ++i) 591*0Sstevel@tonic-gate ; 592*0Sstevel@tonic-gate 593*0Sstevel@tonic-gate newenv = malloc(sizeof (*newenv) * (i + 1)); 594*0Sstevel@tonic-gate if (newenv == NULL) 595*0Sstevel@tonic-gate return (NULL); 596*0Sstevel@tonic-gate 597*0Sstevel@tonic-gate i_new = 0; 598*0Sstevel@tonic-gate 599*0Sstevel@tonic-gate for (i = 0; env[i] != NULL; ++i) { 600*0Sstevel@tonic-gate if (strncmp(env[i], "SMF_", sizeof ("SMF_") - 1) == 0) 601*0Sstevel@tonic-gate continue; 602*0Sstevel@tonic-gate 603*0Sstevel@tonic-gate newenv[i_new++] = env[i]; 604*0Sstevel@tonic-gate } 605*0Sstevel@tonic-gate 606*0Sstevel@tonic-gate newenv[i_new] = NULL; 607*0Sstevel@tonic-gate 608*0Sstevel@tonic-gate return (newenv); 609*0Sstevel@tonic-gate } 610*0Sstevel@tonic-gate 611*0Sstevel@tonic-gate static int 612*0Sstevel@tonic-gate add_new_property(scf_handle_t *h, scf_transaction_t *tx, const char *name, 613*0Sstevel@tonic-gate scf_type_t ty, const void *val) 614*0Sstevel@tonic-gate { 615*0Sstevel@tonic-gate scf_transaction_entry_t *e; 616*0Sstevel@tonic-gate scf_value_t *v; 617*0Sstevel@tonic-gate const char *func; 618*0Sstevel@tonic-gate const struct timeval *t; 619*0Sstevel@tonic-gate int r; 620*0Sstevel@tonic-gate 621*0Sstevel@tonic-gate if ((e = scf_entry_create(h)) == NULL) { 622*0Sstevel@tonic-gate func = "scf_entry_create()"; 623*0Sstevel@tonic-gate goto err; 624*0Sstevel@tonic-gate } 625*0Sstevel@tonic-gate 626*0Sstevel@tonic-gate if ((v = scf_value_create(h)) == NULL) { 627*0Sstevel@tonic-gate func = "scf_value_create()"; 628*0Sstevel@tonic-gate goto err; 629*0Sstevel@tonic-gate } 630*0Sstevel@tonic-gate 631*0Sstevel@tonic-gate r = scf_transaction_property_new(tx, e, name, ty); 632*0Sstevel@tonic-gate if (r != 0) { 633*0Sstevel@tonic-gate func = "scf_transaction_property_new()"; 634*0Sstevel@tonic-gate goto err; 635*0Sstevel@tonic-gate } 636*0Sstevel@tonic-gate 637*0Sstevel@tonic-gate switch (ty) { 638*0Sstevel@tonic-gate case SCF_TYPE_COUNT: 639*0Sstevel@tonic-gate scf_value_set_count(v, (uint64_t)val); 640*0Sstevel@tonic-gate break; 641*0Sstevel@tonic-gate 642*0Sstevel@tonic-gate case SCF_TYPE_TIME: 643*0Sstevel@tonic-gate t = val; 644*0Sstevel@tonic-gate r = scf_value_set_time(v, t->tv_sec, 1000 * t->tv_usec); 645*0Sstevel@tonic-gate assert(r == 0); 646*0Sstevel@tonic-gate break; 647*0Sstevel@tonic-gate 648*0Sstevel@tonic-gate case SCF_TYPE_ASTRING: 649*0Sstevel@tonic-gate r = scf_value_set_astring(v, val); 650*0Sstevel@tonic-gate assert(r == 0); 651*0Sstevel@tonic-gate break; 652*0Sstevel@tonic-gate 653*0Sstevel@tonic-gate default: 654*0Sstevel@tonic-gate assert(0); 655*0Sstevel@tonic-gate abort(); 656*0Sstevel@tonic-gate } 657*0Sstevel@tonic-gate 658*0Sstevel@tonic-gate if (scf_entry_add_value(e, v) == 0) 659*0Sstevel@tonic-gate return (0); 660*0Sstevel@tonic-gate 661*0Sstevel@tonic-gate func = "scf_entry_add_value()"; 662*0Sstevel@tonic-gate 663*0Sstevel@tonic-gate err: 664*0Sstevel@tonic-gate uu_warn(gettext("%s failed (%s).\n"), func, scf_strerror(scf_error())); 665*0Sstevel@tonic-gate return (-1); 666*0Sstevel@tonic-gate } 667*0Sstevel@tonic-gate 668*0Sstevel@tonic-gate static void 669*0Sstevel@tonic-gate set_legacy_service(scf_propertygroup_t *pg, const char *script) 670*0Sstevel@tonic-gate { 671*0Sstevel@tonic-gate scf_handle_t *h; 672*0Sstevel@tonic-gate const char *func; 673*0Sstevel@tonic-gate char *suffix; 674*0Sstevel@tonic-gate scf_transaction_t *tx; 675*0Sstevel@tonic-gate struct timeval tstamp; 676*0Sstevel@tonic-gate struct stat st; 677*0Sstevel@tonic-gate ctid_t ctid; 678*0Sstevel@tonic-gate char *svc_name = NULL; 679*0Sstevel@tonic-gate int ret; 680*0Sstevel@tonic-gate 681*0Sstevel@tonic-gate h = scf_pg_handle(pg); 682*0Sstevel@tonic-gate if (h == NULL) { 683*0Sstevel@tonic-gate func = "scf_pg_handle()"; 684*0Sstevel@tonic-gate goto scferr; 685*0Sstevel@tonic-gate } 686*0Sstevel@tonic-gate 687*0Sstevel@tonic-gate ret = gettimeofday(&tstamp, NULL); 688*0Sstevel@tonic-gate assert(ret == 0); 689*0Sstevel@tonic-gate 690*0Sstevel@tonic-gate if (stat(script, &st) != 0) { 691*0Sstevel@tonic-gate uu_warn(gettext("Couldn't stat %s (%s).\n"), script, 692*0Sstevel@tonic-gate strerror(errno)); 693*0Sstevel@tonic-gate goto err; 694*0Sstevel@tonic-gate } 695*0Sstevel@tonic-gate 696*0Sstevel@tonic-gate if (errno = contract_latest(&ctid)) { 697*0Sstevel@tonic-gate uu_warn(gettext("Could not get contract")); 698*0Sstevel@tonic-gate goto err; 699*0Sstevel@tonic-gate } 700*0Sstevel@tonic-gate 701*0Sstevel@tonic-gate tx = scf_transaction_create(h); 702*0Sstevel@tonic-gate if (tx == NULL) { 703*0Sstevel@tonic-gate func = "scf_transaction_create()"; 704*0Sstevel@tonic-gate goto scferr; 705*0Sstevel@tonic-gate } 706*0Sstevel@tonic-gate 707*0Sstevel@tonic-gate if (scf_transaction_start(tx, pg) != 0) { 708*0Sstevel@tonic-gate func = "scf_transaction_start()"; 709*0Sstevel@tonic-gate goto scferr; 710*0Sstevel@tonic-gate } 711*0Sstevel@tonic-gate 712*0Sstevel@tonic-gate /* 713*0Sstevel@tonic-gate * We'd like to use the prettier svc_name, but if path_to_svc_name() 714*0Sstevel@tonic-gate * fails, we can use the script name anyway. 715*0Sstevel@tonic-gate */ 716*0Sstevel@tonic-gate svc_name = path_to_svc_name(script); 717*0Sstevel@tonic-gate 718*0Sstevel@tonic-gate if (add_new_property(h, tx, SCF_LEGACY_PROPERTY_NAME, SCF_TYPE_ASTRING, 719*0Sstevel@tonic-gate (void *)(svc_name ? svc_name : script)) != 0) 720*0Sstevel@tonic-gate goto err; 721*0Sstevel@tonic-gate 722*0Sstevel@tonic-gate if (add_new_property(h, tx, SCF_PROPERTY_STATE_TIMESTAMP, 723*0Sstevel@tonic-gate SCF_TYPE_TIME, &tstamp) != 0) 724*0Sstevel@tonic-gate goto err; 725*0Sstevel@tonic-gate 726*0Sstevel@tonic-gate if (add_new_property(h, tx, SCF_LEGACY_PROPERTY_INODE, 727*0Sstevel@tonic-gate SCF_TYPE_COUNT, (void *)st.st_ino) != 0) 728*0Sstevel@tonic-gate goto err; 729*0Sstevel@tonic-gate 730*0Sstevel@tonic-gate if ((suffix = script_suffix(script)) != NULL) { 731*0Sstevel@tonic-gate if (add_new_property(h, tx, SCF_LEGACY_PROPERTY_SUFFIX, 732*0Sstevel@tonic-gate SCF_TYPE_ASTRING, (void *)suffix) != 0) 733*0Sstevel@tonic-gate goto err; 734*0Sstevel@tonic-gate 735*0Sstevel@tonic-gate free(suffix); 736*0Sstevel@tonic-gate } 737*0Sstevel@tonic-gate 738*0Sstevel@tonic-gate if (add_new_property(h, tx, SCF_PROPERTY_CONTRACT, SCF_TYPE_COUNT, 739*0Sstevel@tonic-gate (void *)ctid) != 0) 740*0Sstevel@tonic-gate goto err; 741*0Sstevel@tonic-gate 742*0Sstevel@tonic-gate for (;;) { 743*0Sstevel@tonic-gate switch (scf_transaction_commit(tx)) { 744*0Sstevel@tonic-gate case 1: 745*0Sstevel@tonic-gate free(svc_name); 746*0Sstevel@tonic-gate return; 747*0Sstevel@tonic-gate 748*0Sstevel@tonic-gate case 0: 749*0Sstevel@tonic-gate if (scf_pg_update(pg) == -1) { 750*0Sstevel@tonic-gate func = "scf_pg_update()"; 751*0Sstevel@tonic-gate goto scferr; 752*0Sstevel@tonic-gate } 753*0Sstevel@tonic-gate continue; 754*0Sstevel@tonic-gate 755*0Sstevel@tonic-gate case -1: 756*0Sstevel@tonic-gate func = "scf_transaction_commit()"; 757*0Sstevel@tonic-gate goto scferr; 758*0Sstevel@tonic-gate 759*0Sstevel@tonic-gate default: 760*0Sstevel@tonic-gate assert(0); 761*0Sstevel@tonic-gate abort(); 762*0Sstevel@tonic-gate } 763*0Sstevel@tonic-gate } 764*0Sstevel@tonic-gate 765*0Sstevel@tonic-gate scferr: 766*0Sstevel@tonic-gate uu_warn(gettext("%s failed (%s).\n"), func, scf_strerror(scf_error())); 767*0Sstevel@tonic-gate err: 768*0Sstevel@tonic-gate uu_die(gettext("Could not commit property values to repository.\n")); 769*0Sstevel@tonic-gate } 770*0Sstevel@tonic-gate 771*0Sstevel@tonic-gate int 772*0Sstevel@tonic-gate main(int argc, char *argv[], char *envp[]) 773*0Sstevel@tonic-gate { 774*0Sstevel@tonic-gate const char *restarter, *script, *action; 775*0Sstevel@tonic-gate boolean_t source = 0; 776*0Sstevel@tonic-gate int o; 777*0Sstevel@tonic-gate boolean_t start_flag; 778*0Sstevel@tonic-gate char **newenv; 779*0Sstevel@tonic-gate pid_t pid; 780*0Sstevel@tonic-gate int pipefds[2]; 781*0Sstevel@tonic-gate char c; 782*0Sstevel@tonic-gate int exitstatus; 783*0Sstevel@tonic-gate 784*0Sstevel@tonic-gate scf_propertygroup_t *pg; 785*0Sstevel@tonic-gate boolean_t pg_ok; 786*0Sstevel@tonic-gate 787*0Sstevel@tonic-gate (void) uu_setpname(argv[0]); 788*0Sstevel@tonic-gate uu_alt_exit(UU_PROFILE_LAUNCHER); 789*0Sstevel@tonic-gate 790*0Sstevel@tonic-gate /* Make sure we were run by svc.startd. */ 791*0Sstevel@tonic-gate if ((restarter = getenv("SMF_RESTARTER")) == NULL || 792*0Sstevel@tonic-gate strcmp(restarter, SCF_SERVICE_STARTD) != 0) 793*0Sstevel@tonic-gate uu_die(gettext("invocation outside smf(5) inappropriate\n")); 794*0Sstevel@tonic-gate 795*0Sstevel@tonic-gate while ((o = getopt(argc, argv, "s")) != -1) { 796*0Sstevel@tonic-gate switch (o) { 797*0Sstevel@tonic-gate case 's': 798*0Sstevel@tonic-gate source = 1; 799*0Sstevel@tonic-gate break; 800*0Sstevel@tonic-gate 801*0Sstevel@tonic-gate default: 802*0Sstevel@tonic-gate usage(); 803*0Sstevel@tonic-gate } 804*0Sstevel@tonic-gate } 805*0Sstevel@tonic-gate 806*0Sstevel@tonic-gate if (argc - optind != 2) 807*0Sstevel@tonic-gate usage(); 808*0Sstevel@tonic-gate 809*0Sstevel@tonic-gate script = argv[optind]; 810*0Sstevel@tonic-gate action = argv[optind + 1]; 811*0Sstevel@tonic-gate 812*0Sstevel@tonic-gate if (strcmp(action, "start") == 0) 813*0Sstevel@tonic-gate start_flag = 1; 814*0Sstevel@tonic-gate else if (strcmp(action, "stop") == 0) 815*0Sstevel@tonic-gate start_flag = 0; 816*0Sstevel@tonic-gate else 817*0Sstevel@tonic-gate usage(); 818*0Sstevel@tonic-gate 819*0Sstevel@tonic-gate /* 820*0Sstevel@tonic-gate * Look for the pg & exit if appropriate. Also, if we're starting, 821*0Sstevel@tonic-gate * add the pg now so we can exit before launching the script if we 822*0Sstevel@tonic-gate * have insufficient repository privilege. 823*0Sstevel@tonic-gate * 824*0Sstevel@tonic-gate * If any other problem occurs, we carry on anyway. 825*0Sstevel@tonic-gate */ 826*0Sstevel@tonic-gate pg = get_script_pg(script, start_flag, &pg_ok); 827*0Sstevel@tonic-gate 828*0Sstevel@tonic-gate /* Clean the environment. Now so we can fail early. */ 829*0Sstevel@tonic-gate if (!source) 830*0Sstevel@tonic-gate newenv = approved_env(envp); 831*0Sstevel@tonic-gate else 832*0Sstevel@tonic-gate newenv = env_without_smf(envp); 833*0Sstevel@tonic-gate if (newenv == NULL) 834*0Sstevel@tonic-gate uu_die(gettext( 835*0Sstevel@tonic-gate "Could not create new environment: out of memory.\n")); 836*0Sstevel@tonic-gate 837*0Sstevel@tonic-gate if (prepare_contract() == -1) { 838*0Sstevel@tonic-gate if (start_flag && pg != NULL) 839*0Sstevel@tonic-gate cleanup_pg(pg); 840*0Sstevel@tonic-gate 841*0Sstevel@tonic-gate exit(UU_EXIT_FATAL); 842*0Sstevel@tonic-gate } 843*0Sstevel@tonic-gate 844*0Sstevel@tonic-gate /* pipe to communicate exec success or failure */ 845*0Sstevel@tonic-gate if (pipe(pipefds) != 0) { 846*0Sstevel@tonic-gate uu_warn(gettext("Could not create pipe")); 847*0Sstevel@tonic-gate 848*0Sstevel@tonic-gate if (start_flag && pg != NULL) 849*0Sstevel@tonic-gate cleanup_pg(pg); 850*0Sstevel@tonic-gate 851*0Sstevel@tonic-gate exit(UU_EXIT_FATAL); 852*0Sstevel@tonic-gate } 853*0Sstevel@tonic-gate 854*0Sstevel@tonic-gate if (!pg_ok) 855*0Sstevel@tonic-gate (void) printf(gettext("Executing legacy init script \"%s\" " 856*0Sstevel@tonic-gate "despite previous errors.\n"), script); 857*0Sstevel@tonic-gate else 858*0Sstevel@tonic-gate (void) printf(gettext("Executing legacy init script \"%s\".\n"), 859*0Sstevel@tonic-gate script); 860*0Sstevel@tonic-gate (void) fflush(stdout); 861*0Sstevel@tonic-gate 862*0Sstevel@tonic-gate pid = fork(); 863*0Sstevel@tonic-gate if (pid < 0) { 864*0Sstevel@tonic-gate uu_warn(gettext("Could not fork")); 865*0Sstevel@tonic-gate 866*0Sstevel@tonic-gate if (start_flag && pg != NULL) 867*0Sstevel@tonic-gate cleanup_pg(pg); 868*0Sstevel@tonic-gate 869*0Sstevel@tonic-gate exit(UU_EXIT_FATAL); 870*0Sstevel@tonic-gate } 871*0Sstevel@tonic-gate 872*0Sstevel@tonic-gate if (pid == 0) { 873*0Sstevel@tonic-gate /* child */ 874*0Sstevel@tonic-gate 875*0Sstevel@tonic-gate const char *arg1, *arg2, *arg3; 876*0Sstevel@tonic-gate 877*0Sstevel@tonic-gate (void) close(pipefds[0]); 878*0Sstevel@tonic-gate (void) fcntl(pipefds[1], F_SETFD, FD_CLOEXEC); 879*0Sstevel@tonic-gate 880*0Sstevel@tonic-gate if (!source) { 881*0Sstevel@tonic-gate arg1 = "/bin/sh"; 882*0Sstevel@tonic-gate arg2 = script; 883*0Sstevel@tonic-gate arg3 = action; 884*0Sstevel@tonic-gate } else { 885*0Sstevel@tonic-gate arg1 = "/bin/sh"; 886*0Sstevel@tonic-gate arg2 = "-c"; 887*0Sstevel@tonic-gate arg3 = script; 888*0Sstevel@tonic-gate } 889*0Sstevel@tonic-gate 890*0Sstevel@tonic-gate (void) execle(arg1, arg1, arg2, arg3, NULL, newenv); 891*0Sstevel@tonic-gate 892*0Sstevel@tonic-gate uu_warn(gettext("Could not exec \"%s %s %s\""), arg1, 893*0Sstevel@tonic-gate arg2, arg3); 894*0Sstevel@tonic-gate 895*0Sstevel@tonic-gate 896*0Sstevel@tonic-gate /* Notify parent of the failure. */ 897*0Sstevel@tonic-gate while (write(pipefds[1], &c, 1) != 1) { 898*0Sstevel@tonic-gate switch (errno) { 899*0Sstevel@tonic-gate case EAGAIN: 900*0Sstevel@tonic-gate (void) sleep(1); 901*0Sstevel@tonic-gate 902*0Sstevel@tonic-gate /* FALLTHROUGH */ 903*0Sstevel@tonic-gate 904*0Sstevel@tonic-gate case EINTR: 905*0Sstevel@tonic-gate continue; 906*0Sstevel@tonic-gate } 907*0Sstevel@tonic-gate 908*0Sstevel@tonic-gate uu_warn(gettext("Could not inform parent of error")); 909*0Sstevel@tonic-gate break; 910*0Sstevel@tonic-gate } 911*0Sstevel@tonic-gate 912*0Sstevel@tonic-gate exit(UU_EXIT_FATAL); 913*0Sstevel@tonic-gate } 914*0Sstevel@tonic-gate 915*0Sstevel@tonic-gate (void) close(pipefds[1]); 916*0Sstevel@tonic-gate 917*0Sstevel@tonic-gate if (read(pipefds[0], &c, sizeof (c)) > 0) { 918*0Sstevel@tonic-gate if (!start_flag) 919*0Sstevel@tonic-gate uu_die(gettext("exec() failed; leaving properties.\n")); 920*0Sstevel@tonic-gate else { 921*0Sstevel@tonic-gate uu_warn(gettext("exec() failed.\n")); 922*0Sstevel@tonic-gate if (pg != NULL) 923*0Sstevel@tonic-gate cleanup_pg(pg); 924*0Sstevel@tonic-gate exit(UU_EXIT_FATAL); 925*0Sstevel@tonic-gate } 926*0Sstevel@tonic-gate } 927*0Sstevel@tonic-gate 928*0Sstevel@tonic-gate while (waitpid(pid, &exitstatus, 0) == -1) { 929*0Sstevel@tonic-gate assert(errno == EINTR); 930*0Sstevel@tonic-gate } 931*0Sstevel@tonic-gate 932*0Sstevel@tonic-gate if (WIFSIGNALED(exitstatus)) { 933*0Sstevel@tonic-gate char buf[SIG2STR_MAX]; 934*0Sstevel@tonic-gate (void) sig2str(WTERMSIG(exitstatus), buf); 935*0Sstevel@tonic-gate (void) printf(gettext("Legacy init script \"%s\" failed due " 936*0Sstevel@tonic-gate "to signal %s.\n"), script, buf); 937*0Sstevel@tonic-gate } else { 938*0Sstevel@tonic-gate (void) printf(gettext("Legacy init script \"%s\" exited with " 939*0Sstevel@tonic-gate "return code %d.\n"), script, WEXITSTATUS(exitstatus)); 940*0Sstevel@tonic-gate } 941*0Sstevel@tonic-gate 942*0Sstevel@tonic-gate if (pg != NULL) { 943*0Sstevel@tonic-gate if (start_flag) 944*0Sstevel@tonic-gate set_legacy_service(pg, script); 945*0Sstevel@tonic-gate else 946*0Sstevel@tonic-gate cleanup_pg(pg); 947*0Sstevel@tonic-gate scf_pg_destroy(pg); 948*0Sstevel@tonic-gate } 949*0Sstevel@tonic-gate 950*0Sstevel@tonic-gate return (UU_EXIT_OK); 951*0Sstevel@tonic-gate } 952