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