17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 77c478bd9Sstevel@tonic-gate * with the License. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate * and limitations under the License. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * CDDL HEADER END 217c478bd9Sstevel@tonic-gate */ 227c478bd9Sstevel@tonic-gate /* 23*0b5c9250Shg115875 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate /* 307c478bd9Sstevel@tonic-gate * lsvcrun - run an rc?.d script, modifying appropriate data in the 317c478bd9Sstevel@tonic-gate * repository to reflect legacy behavior. 327c478bd9Sstevel@tonic-gate * 337c478bd9Sstevel@tonic-gate * We try to keep track of what we can for the legacy scripts via 347c478bd9Sstevel@tonic-gate * property groups under the smf/legacy_run service. Each property 357c478bd9Sstevel@tonic-gate * group identifies a service, named in the form 'rc2_d_S10foo'. 367c478bd9Sstevel@tonic-gate * 377c478bd9Sstevel@tonic-gate * Each group has the following properties: name, the script name 387c478bd9Sstevel@tonic-gate * displayed by svcs(1m); state_timestamp; contract, contract ID; 397c478bd9Sstevel@tonic-gate * inode, the inode of the script; and suffix, the suffix of the 407c478bd9Sstevel@tonic-gate * script name, e.g. 'foo'. 417c478bd9Sstevel@tonic-gate * 427c478bd9Sstevel@tonic-gate * When we run a K script, we try to identify and remove the 437c478bd9Sstevel@tonic-gate * property group by means of examining the inode and script 447c478bd9Sstevel@tonic-gate * suffix. The inode check means more than one script with the 457c478bd9Sstevel@tonic-gate * same suffix will still work as intended in the common case. 467c478bd9Sstevel@tonic-gate * 477c478bd9Sstevel@tonic-gate * If we cannot find a property group, or one already exists 487c478bd9Sstevel@tonic-gate * when we try to add one, then we print a suitable warning. These 497c478bd9Sstevel@tonic-gate * are warnings because there was no strict requirement that K 507c478bd9Sstevel@tonic-gate * and S scripts be matched up. 517c478bd9Sstevel@tonic-gate * 527c478bd9Sstevel@tonic-gate * In the face of these assumptions being proved wrong, we always 537c478bd9Sstevel@tonic-gate * make sure to execute the script anyway in an attempt to keep 547c478bd9Sstevel@tonic-gate * things working as they used to. If we can't execute the script, 557c478bd9Sstevel@tonic-gate * we try to leave the repository in the state it was before. 567c478bd9Sstevel@tonic-gate */ 577c478bd9Sstevel@tonic-gate 587c478bd9Sstevel@tonic-gate #include <sys/ctfs.h> 597c478bd9Sstevel@tonic-gate #include <sys/types.h> 607c478bd9Sstevel@tonic-gate #include <sys/wait.h> 617c478bd9Sstevel@tonic-gate #include <sys/stat.h> 627c478bd9Sstevel@tonic-gate #include <assert.h> 637c478bd9Sstevel@tonic-gate #include <ctype.h> 647c478bd9Sstevel@tonic-gate #include <errno.h> 657c478bd9Sstevel@tonic-gate #include <fcntl.h> 667c478bd9Sstevel@tonic-gate #include <fnmatch.h> 677c478bd9Sstevel@tonic-gate #include <libcontract.h> 687c478bd9Sstevel@tonic-gate #include <libcontract_priv.h> 697c478bd9Sstevel@tonic-gate #include <libintl.h> 707c478bd9Sstevel@tonic-gate #include <libscf.h> 717c478bd9Sstevel@tonic-gate #include <libscf_priv.h> 727c478bd9Sstevel@tonic-gate #include <libuutil.h> 737c478bd9Sstevel@tonic-gate #include <signal.h> 747c478bd9Sstevel@tonic-gate #include <stdio.h> 757c478bd9Sstevel@tonic-gate #include <stdlib.h> 767c478bd9Sstevel@tonic-gate #include <string.h> 777c478bd9Sstevel@tonic-gate #include <strings.h> 787c478bd9Sstevel@tonic-gate #include <time.h> 797c478bd9Sstevel@tonic-gate #include <unistd.h> 807c478bd9Sstevel@tonic-gate #include <limits.h> 817c478bd9Sstevel@tonic-gate 827c478bd9Sstevel@tonic-gate 837c478bd9Sstevel@tonic-gate /* Environment variables to pass on. See clean_environment(). */ 847c478bd9Sstevel@tonic-gate static char *evars_to_pass[] = { "LANG", "LC_ALL", "LC_COLLATE", "LC_CTYPE", 857c478bd9Sstevel@tonic-gate "LC_MESSAGES", "LC_MONETARY", "LC_NUMERIC", "LC_TIME", "PATH", "TZ" 867c478bd9Sstevel@tonic-gate }; 877c478bd9Sstevel@tonic-gate 887c478bd9Sstevel@tonic-gate #define EVARS_TO_PASS_NUM \ 897c478bd9Sstevel@tonic-gate (sizeof (evars_to_pass) / sizeof (*evars_to_pass)) 907c478bd9Sstevel@tonic-gate 917c478bd9Sstevel@tonic-gate 927c478bd9Sstevel@tonic-gate static void 937c478bd9Sstevel@tonic-gate usage() 947c478bd9Sstevel@tonic-gate { 957c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 967c478bd9Sstevel@tonic-gate gettext("Usage: %s [-s] script {start | stop}\n"), uu_getpname()); 977c478bd9Sstevel@tonic-gate exit(UU_EXIT_USAGE); 987c478bd9Sstevel@tonic-gate } 997c478bd9Sstevel@tonic-gate 1007c478bd9Sstevel@tonic-gate /* 1017c478bd9Sstevel@tonic-gate * Pick out the script name and convert it for use as an SMF property 1027c478bd9Sstevel@tonic-gate * group name. 1037c478bd9Sstevel@tonic-gate */ 1047c478bd9Sstevel@tonic-gate static char * 1057c478bd9Sstevel@tonic-gate start_pg_name(const char *path) 1067c478bd9Sstevel@tonic-gate { 1077c478bd9Sstevel@tonic-gate char *out, *cp; 1087c478bd9Sstevel@tonic-gate 1097c478bd9Sstevel@tonic-gate if (fnmatch("/etc/rc[0-6S].d/S*", path, FNM_PATHNAME) != 0) { 1107c478bd9Sstevel@tonic-gate uu_warn(gettext("couldn't parse name %s.\n"), path); 1117c478bd9Sstevel@tonic-gate return (NULL); 1127c478bd9Sstevel@tonic-gate } 1137c478bd9Sstevel@tonic-gate 1147c478bd9Sstevel@tonic-gate out = strdup(path + sizeof ("/etc/") - 1); 1157c478bd9Sstevel@tonic-gate 1167c478bd9Sstevel@tonic-gate if (out == NULL) { 1177c478bd9Sstevel@tonic-gate uu_warn(gettext("strdup() failed (%s).\n"), strerror(errno)); 1187c478bd9Sstevel@tonic-gate return (NULL); 1197c478bd9Sstevel@tonic-gate } 1207c478bd9Sstevel@tonic-gate 1217c478bd9Sstevel@tonic-gate /* Convert illegal characters to _. */ 1227c478bd9Sstevel@tonic-gate for (cp = out; *cp != '\0'; ++cp) { 1237c478bd9Sstevel@tonic-gate /* locale problem? */ 1247c478bd9Sstevel@tonic-gate if (!isalnum(*cp) && *cp != '-') 1257c478bd9Sstevel@tonic-gate *cp = '_'; 1267c478bd9Sstevel@tonic-gate } 1277c478bd9Sstevel@tonic-gate 1287c478bd9Sstevel@tonic-gate return (out); 1297c478bd9Sstevel@tonic-gate } 1307c478bd9Sstevel@tonic-gate 1317c478bd9Sstevel@tonic-gate static char * 1327c478bd9Sstevel@tonic-gate script_suffix(const char *path) 1337c478bd9Sstevel@tonic-gate { 1347c478bd9Sstevel@tonic-gate const char *cp; 1357c478bd9Sstevel@tonic-gate char *out; 1367c478bd9Sstevel@tonic-gate 1377c478bd9Sstevel@tonic-gate if (fnmatch("/etc/rc[0-6S].d/[SK]*", path, FNM_PATHNAME) != 0) { 1387c478bd9Sstevel@tonic-gate uu_warn(gettext("couldn't parse name %s.\n"), path); 1397c478bd9Sstevel@tonic-gate return (NULL); 1407c478bd9Sstevel@tonic-gate } 1417c478bd9Sstevel@tonic-gate 1427c478bd9Sstevel@tonic-gate cp = path + sizeof ("/etc/rc0.d/S") - 1; 1437c478bd9Sstevel@tonic-gate 1447c478bd9Sstevel@tonic-gate while (isdigit(*cp)) 1457c478bd9Sstevel@tonic-gate cp++; 1467c478bd9Sstevel@tonic-gate 1477c478bd9Sstevel@tonic-gate if (*cp == '\0') { 1487c478bd9Sstevel@tonic-gate uu_warn(gettext("couldn't parse name %s.\n"), path); 1497c478bd9Sstevel@tonic-gate return (NULL); 1507c478bd9Sstevel@tonic-gate } 1517c478bd9Sstevel@tonic-gate 1527c478bd9Sstevel@tonic-gate out = strdup(cp); 1537c478bd9Sstevel@tonic-gate if (out == NULL) 1547c478bd9Sstevel@tonic-gate uu_warn(gettext("strdup() failed (%s).\n"), strerror(errno)); 1557c478bd9Sstevel@tonic-gate 1567c478bd9Sstevel@tonic-gate return (out); 1577c478bd9Sstevel@tonic-gate } 1587c478bd9Sstevel@tonic-gate 1597c478bd9Sstevel@tonic-gate /* 1607c478bd9Sstevel@tonic-gate * Convert a path to an acceptable SMF (service) name. 1617c478bd9Sstevel@tonic-gate */ 1627c478bd9Sstevel@tonic-gate static char * 1637c478bd9Sstevel@tonic-gate path_to_svc_name(const char *path) 1647c478bd9Sstevel@tonic-gate { 1657c478bd9Sstevel@tonic-gate char *out, *cp; 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate out = strdup(path); 1687c478bd9Sstevel@tonic-gate if (out == NULL) { 1697c478bd9Sstevel@tonic-gate uu_warn(gettext("strdup() failed (%s).\n"), strerror(errno)); 1707c478bd9Sstevel@tonic-gate return (NULL); 1717c478bd9Sstevel@tonic-gate } 1727c478bd9Sstevel@tonic-gate 1737c478bd9Sstevel@tonic-gate /* Convert illegal characters to _. */ 1747c478bd9Sstevel@tonic-gate for (cp = out; *cp != '\0'; ++cp) { 1757c478bd9Sstevel@tonic-gate /* locale problem? */ 1767c478bd9Sstevel@tonic-gate if (!isalnum(*cp) && *cp != '-' && *cp != '/') 1777c478bd9Sstevel@tonic-gate *cp = '_'; 1787c478bd9Sstevel@tonic-gate } 1797c478bd9Sstevel@tonic-gate 1807c478bd9Sstevel@tonic-gate /* If the first character is _, use a instead. */ 1817c478bd9Sstevel@tonic-gate if (*out == '_') 1827c478bd9Sstevel@tonic-gate *out = 'a'; 1837c478bd9Sstevel@tonic-gate 1847c478bd9Sstevel@tonic-gate return (out); 1857c478bd9Sstevel@tonic-gate } 1867c478bd9Sstevel@tonic-gate 1877c478bd9Sstevel@tonic-gate static void 1887c478bd9Sstevel@tonic-gate scferr(const char *func) 1897c478bd9Sstevel@tonic-gate { 1907c478bd9Sstevel@tonic-gate uu_warn(gettext("%s failed (%s). Repository will not be modified.\n"), 1917c478bd9Sstevel@tonic-gate func, scf_strerror(scf_error())); 1927c478bd9Sstevel@tonic-gate } 1937c478bd9Sstevel@tonic-gate 1947c478bd9Sstevel@tonic-gate static scf_propertygroup_t * 1957c478bd9Sstevel@tonic-gate get_start_pg(const char *script, scf_handle_t *h, scf_service_t *svc, 1967c478bd9Sstevel@tonic-gate boolean_t *ok) 1977c478bd9Sstevel@tonic-gate { 1987c478bd9Sstevel@tonic-gate char *pg_name = NULL; 1997c478bd9Sstevel@tonic-gate scf_propertygroup_t *pg = NULL; 2007c478bd9Sstevel@tonic-gate scf_property_t *prop = NULL; 2017c478bd9Sstevel@tonic-gate 2027c478bd9Sstevel@tonic-gate if ((pg_name = start_pg_name(script)) == NULL) 2037c478bd9Sstevel@tonic-gate return (NULL); 2047c478bd9Sstevel@tonic-gate 2057c478bd9Sstevel@tonic-gate if ((pg = scf_pg_create(h)) == NULL) { 2067c478bd9Sstevel@tonic-gate scferr("scf_pg_create()"); 2077c478bd9Sstevel@tonic-gate goto out; 2087c478bd9Sstevel@tonic-gate } 2097c478bd9Sstevel@tonic-gate 2107c478bd9Sstevel@tonic-gate add: 2117c478bd9Sstevel@tonic-gate if (scf_service_add_pg(svc, pg_name, SCF_GROUP_FRAMEWORK, 2127c478bd9Sstevel@tonic-gate SCF_PG_FLAG_NONPERSISTENT, pg) == 0) { 2137c478bd9Sstevel@tonic-gate *ok = 1; 2147c478bd9Sstevel@tonic-gate free(pg_name); 2157c478bd9Sstevel@tonic-gate return (pg); 2167c478bd9Sstevel@tonic-gate } 2177c478bd9Sstevel@tonic-gate 2187c478bd9Sstevel@tonic-gate switch (scf_error()) { 2197c478bd9Sstevel@tonic-gate case SCF_ERROR_INVALID_ARGUMENT: 2207c478bd9Sstevel@tonic-gate assert(0); 2217c478bd9Sstevel@tonic-gate abort(); 2227c478bd9Sstevel@tonic-gate /* NOTREACHED */ 2237c478bd9Sstevel@tonic-gate 2247c478bd9Sstevel@tonic-gate case SCF_ERROR_EXISTS: 2257c478bd9Sstevel@tonic-gate break; 2267c478bd9Sstevel@tonic-gate 2277c478bd9Sstevel@tonic-gate case SCF_ERROR_PERMISSION_DENIED: 2287c478bd9Sstevel@tonic-gate uu_die(gettext( 2297c478bd9Sstevel@tonic-gate "Insufficient privilege to add repository properties; " 2307c478bd9Sstevel@tonic-gate "not launching \"%s\".\n"), script); 2317c478bd9Sstevel@tonic-gate /* NOTREACHED */ 2327c478bd9Sstevel@tonic-gate 2337c478bd9Sstevel@tonic-gate default: 2347c478bd9Sstevel@tonic-gate scferr("scf_service_add_pg()"); 2357c478bd9Sstevel@tonic-gate scf_pg_destroy(pg); 2367c478bd9Sstevel@tonic-gate pg = NULL; 2377c478bd9Sstevel@tonic-gate goto out; 2387c478bd9Sstevel@tonic-gate } 2397c478bd9Sstevel@tonic-gate 2407c478bd9Sstevel@tonic-gate if (scf_service_get_pg(svc, pg_name, pg) != 0) { 2417c478bd9Sstevel@tonic-gate switch (scf_error()) { 2427c478bd9Sstevel@tonic-gate case SCF_ERROR_INVALID_ARGUMENT: 2437c478bd9Sstevel@tonic-gate assert(0); 2447c478bd9Sstevel@tonic-gate abort(); 2457c478bd9Sstevel@tonic-gate /* NOTREACHED */ 2467c478bd9Sstevel@tonic-gate 2477c478bd9Sstevel@tonic-gate case SCF_ERROR_NOT_FOUND: 2487c478bd9Sstevel@tonic-gate goto add; 2497c478bd9Sstevel@tonic-gate 2507c478bd9Sstevel@tonic-gate default: 2517c478bd9Sstevel@tonic-gate scferr("scf_service_get_pg()"); 2527c478bd9Sstevel@tonic-gate scf_pg_destroy(pg); 2537c478bd9Sstevel@tonic-gate pg = NULL; 2547c478bd9Sstevel@tonic-gate goto out; 2557c478bd9Sstevel@tonic-gate } 2567c478bd9Sstevel@tonic-gate } 2577c478bd9Sstevel@tonic-gate 2587c478bd9Sstevel@tonic-gate if ((prop = scf_property_create(h)) == NULL) { 2597c478bd9Sstevel@tonic-gate scferr("scf_property_create()"); 2607c478bd9Sstevel@tonic-gate scf_pg_destroy(pg); 2617c478bd9Sstevel@tonic-gate pg = NULL; 2627c478bd9Sstevel@tonic-gate goto out; 2637c478bd9Sstevel@tonic-gate } 2647c478bd9Sstevel@tonic-gate 2657c478bd9Sstevel@tonic-gate /* 2667c478bd9Sstevel@tonic-gate * See if the pg has the name property. If it has, that 2677c478bd9Sstevel@tonic-gate * implies we successfully ran the same script before. We 2687c478bd9Sstevel@tonic-gate * should re-run it anyway, but not modify the existing pg; 2697c478bd9Sstevel@tonic-gate * this might lose contract-control but there's not much we 2707c478bd9Sstevel@tonic-gate * can do. 2717c478bd9Sstevel@tonic-gate * 2727c478bd9Sstevel@tonic-gate * If there's no name property, then we probably couldn't 2737c478bd9Sstevel@tonic-gate * remove the pg fully after a script failed to run. 2747c478bd9Sstevel@tonic-gate */ 2757c478bd9Sstevel@tonic-gate 2767c478bd9Sstevel@tonic-gate if (scf_pg_get_property(pg, SCF_LEGACY_PROPERTY_NAME, prop) == 0) { 2777c478bd9Sstevel@tonic-gate uu_warn(gettext("Service matching \"%s\" " 2787c478bd9Sstevel@tonic-gate "seems to be running.\n"), script); 2797c478bd9Sstevel@tonic-gate scf_pg_destroy(pg); 2807c478bd9Sstevel@tonic-gate pg = NULL; 2817c478bd9Sstevel@tonic-gate } else if (scf_error() != SCF_ERROR_NOT_FOUND) { 2827c478bd9Sstevel@tonic-gate scferr("scf_pg_get_property()"); 2837c478bd9Sstevel@tonic-gate scf_pg_destroy(pg); 2847c478bd9Sstevel@tonic-gate pg = NULL; 2857c478bd9Sstevel@tonic-gate } else { 2867c478bd9Sstevel@tonic-gate uu_warn(gettext("Service \"%s\" has an invalid property " 2877c478bd9Sstevel@tonic-gate "group.\n"), script); 2887c478bd9Sstevel@tonic-gate } 2897c478bd9Sstevel@tonic-gate 2907c478bd9Sstevel@tonic-gate out: 2917c478bd9Sstevel@tonic-gate free(pg_name); 2927c478bd9Sstevel@tonic-gate scf_property_destroy(prop); 2937c478bd9Sstevel@tonic-gate return (pg); 2947c478bd9Sstevel@tonic-gate } 2957c478bd9Sstevel@tonic-gate 2967c478bd9Sstevel@tonic-gate static scf_propertygroup_t * 2977c478bd9Sstevel@tonic-gate pg_match(scf_handle_t *h, scf_service_t *svc, ino_t ino, const char *suffix) 2987c478bd9Sstevel@tonic-gate { 2997c478bd9Sstevel@tonic-gate char buf[PATH_MAX]; 3007c478bd9Sstevel@tonic-gate scf_iter_t *iter = NULL; 3017c478bd9Sstevel@tonic-gate scf_propertygroup_t *pg = NULL; 3027c478bd9Sstevel@tonic-gate scf_property_t *prop = NULL; 3037c478bd9Sstevel@tonic-gate scf_value_t *val = NULL; 3047c478bd9Sstevel@tonic-gate 3057c478bd9Sstevel@tonic-gate if ((pg = scf_pg_create(h)) == NULL) { 3067c478bd9Sstevel@tonic-gate scferr("scf_pg_create()"); 3077c478bd9Sstevel@tonic-gate goto err; 3087c478bd9Sstevel@tonic-gate } 3097c478bd9Sstevel@tonic-gate 3107c478bd9Sstevel@tonic-gate if ((iter = scf_iter_create(h)) == NULL) { 3117c478bd9Sstevel@tonic-gate scferr("scf_iter_create()"); 3127c478bd9Sstevel@tonic-gate goto err; 3137c478bd9Sstevel@tonic-gate } 3147c478bd9Sstevel@tonic-gate 3157c478bd9Sstevel@tonic-gate if ((prop = scf_property_create(h)) == NULL) { 3167c478bd9Sstevel@tonic-gate scferr("scf_property_create()"); 3177c478bd9Sstevel@tonic-gate goto err; 3187c478bd9Sstevel@tonic-gate } 3197c478bd9Sstevel@tonic-gate 3207c478bd9Sstevel@tonic-gate if ((val = scf_value_create(h)) == NULL) { 3217c478bd9Sstevel@tonic-gate scferr("scf_value_create()"); 3227c478bd9Sstevel@tonic-gate goto err; 3237c478bd9Sstevel@tonic-gate } 3247c478bd9Sstevel@tonic-gate 3257c478bd9Sstevel@tonic-gate if (scf_iter_service_pgs_typed(iter, svc, SCF_GROUP_FRAMEWORK) != 3267c478bd9Sstevel@tonic-gate 0) { 3277c478bd9Sstevel@tonic-gate scferr("scf_iter_service_pgs_typed()"); 3287c478bd9Sstevel@tonic-gate goto err; 3297c478bd9Sstevel@tonic-gate } 3307c478bd9Sstevel@tonic-gate 3317c478bd9Sstevel@tonic-gate while (scf_iter_next_pg(iter, pg) > 0) { 3327c478bd9Sstevel@tonic-gate int match = 1; 3337c478bd9Sstevel@tonic-gate 3347c478bd9Sstevel@tonic-gate if (suffix != NULL) { 3357c478bd9Sstevel@tonic-gate ssize_t len; 3367c478bd9Sstevel@tonic-gate 3377c478bd9Sstevel@tonic-gate if (scf_pg_get_property(pg, SCF_LEGACY_PROPERTY_SUFFIX, 3387c478bd9Sstevel@tonic-gate prop) != 0) 3397c478bd9Sstevel@tonic-gate continue; 3407c478bd9Sstevel@tonic-gate 3417c478bd9Sstevel@tonic-gate if (scf_property_get_value(prop, val) != 0) 3427c478bd9Sstevel@tonic-gate continue; 3437c478bd9Sstevel@tonic-gate 3447c478bd9Sstevel@tonic-gate len = scf_value_get_astring(val, buf, sizeof (buf)); 3457c478bd9Sstevel@tonic-gate if (len < 0) { 3467c478bd9Sstevel@tonic-gate scferr("scf_value_get_astring()"); 3477c478bd9Sstevel@tonic-gate goto err; 3487c478bd9Sstevel@tonic-gate } 3497c478bd9Sstevel@tonic-gate if (len >= sizeof (buf)) 3507c478bd9Sstevel@tonic-gate continue; 3517c478bd9Sstevel@tonic-gate 3527c478bd9Sstevel@tonic-gate match = (strcmp(buf, suffix) == 0); 3537c478bd9Sstevel@tonic-gate } 3547c478bd9Sstevel@tonic-gate 3557c478bd9Sstevel@tonic-gate if (ino != 0) { 3567c478bd9Sstevel@tonic-gate uint64_t pval; 3577c478bd9Sstevel@tonic-gate 3587c478bd9Sstevel@tonic-gate if (scf_pg_get_property(pg, SCF_LEGACY_PROPERTY_INODE, 3597c478bd9Sstevel@tonic-gate prop) != 0) 3607c478bd9Sstevel@tonic-gate continue; 3617c478bd9Sstevel@tonic-gate 3627c478bd9Sstevel@tonic-gate if (scf_property_get_value(prop, val) != 0) 3637c478bd9Sstevel@tonic-gate continue; 3647c478bd9Sstevel@tonic-gate 3657c478bd9Sstevel@tonic-gate if (scf_value_get_count(val, &pval) != 0) 3667c478bd9Sstevel@tonic-gate continue; 3677c478bd9Sstevel@tonic-gate 3687c478bd9Sstevel@tonic-gate match = (ino == pval) && match; 3697c478bd9Sstevel@tonic-gate } 3707c478bd9Sstevel@tonic-gate 3717c478bd9Sstevel@tonic-gate if (match) 3727c478bd9Sstevel@tonic-gate goto out; 3737c478bd9Sstevel@tonic-gate } 3747c478bd9Sstevel@tonic-gate 3757c478bd9Sstevel@tonic-gate err: 3767c478bd9Sstevel@tonic-gate scf_pg_destroy(pg); 3777c478bd9Sstevel@tonic-gate pg = NULL; 3787c478bd9Sstevel@tonic-gate 3797c478bd9Sstevel@tonic-gate out: 3807c478bd9Sstevel@tonic-gate scf_value_destroy(val); 3817c478bd9Sstevel@tonic-gate scf_iter_destroy(iter); 3827c478bd9Sstevel@tonic-gate scf_property_destroy(prop); 3837c478bd9Sstevel@tonic-gate return (pg); 3847c478bd9Sstevel@tonic-gate } 3857c478bd9Sstevel@tonic-gate 3867c478bd9Sstevel@tonic-gate /* 3877c478bd9Sstevel@tonic-gate * Try and find the property group matching the service this script 3887c478bd9Sstevel@tonic-gate * stops. First we look for a matching inode plus a matching suffix. 3897c478bd9Sstevel@tonic-gate * This commonly succeeds, but if not, we just search for inode. 3907c478bd9Sstevel@tonic-gate * Finally, we try for just the script suffix. 3917c478bd9Sstevel@tonic-gate */ 3927c478bd9Sstevel@tonic-gate static scf_propertygroup_t * 3937c478bd9Sstevel@tonic-gate get_stop_pg(const char *script, scf_handle_t *h, scf_service_t *svc, 3947c478bd9Sstevel@tonic-gate boolean_t *ok) 3957c478bd9Sstevel@tonic-gate { 3967c478bd9Sstevel@tonic-gate struct stat st; 3977c478bd9Sstevel@tonic-gate char *suffix; 3987c478bd9Sstevel@tonic-gate scf_propertygroup_t *pg; 3997c478bd9Sstevel@tonic-gate 4007c478bd9Sstevel@tonic-gate if (stat(script, &st) != 0) { 4017c478bd9Sstevel@tonic-gate uu_warn(gettext("Couldn't stat %s (%s).\n"), script, 4027c478bd9Sstevel@tonic-gate strerror(errno)); 4037c478bd9Sstevel@tonic-gate return (NULL); 4047c478bd9Sstevel@tonic-gate } 4057c478bd9Sstevel@tonic-gate 4067c478bd9Sstevel@tonic-gate if ((suffix = script_suffix(script)) == NULL) { 4077c478bd9Sstevel@tonic-gate pg = pg_match(h, svc, st.st_ino, NULL); 4087c478bd9Sstevel@tonic-gate if (pg != NULL) 4097c478bd9Sstevel@tonic-gate goto out; 4107c478bd9Sstevel@tonic-gate return (NULL); 4117c478bd9Sstevel@tonic-gate } 4127c478bd9Sstevel@tonic-gate 4137c478bd9Sstevel@tonic-gate if ((pg = pg_match(h, svc, st.st_ino, suffix)) != NULL) 4147c478bd9Sstevel@tonic-gate goto out; 4157c478bd9Sstevel@tonic-gate 4167c478bd9Sstevel@tonic-gate if ((pg = pg_match(h, svc, st.st_ino, NULL)) != NULL) 4177c478bd9Sstevel@tonic-gate goto out; 4187c478bd9Sstevel@tonic-gate 4197c478bd9Sstevel@tonic-gate if ((pg = pg_match(h, svc, 0, suffix)) == NULL) { 4207c478bd9Sstevel@tonic-gate uu_warn(gettext("Service matching \"%s\" " 4217c478bd9Sstevel@tonic-gate "doesn't seem to be running.\n"), script); 4227c478bd9Sstevel@tonic-gate free(suffix); 4237c478bd9Sstevel@tonic-gate return (NULL); 4247c478bd9Sstevel@tonic-gate } 4257c478bd9Sstevel@tonic-gate 4267c478bd9Sstevel@tonic-gate out: 4277c478bd9Sstevel@tonic-gate *ok = 1; 4287c478bd9Sstevel@tonic-gate free(suffix); 4297c478bd9Sstevel@tonic-gate return (pg); 4307c478bd9Sstevel@tonic-gate } 4317c478bd9Sstevel@tonic-gate 4327c478bd9Sstevel@tonic-gate static scf_propertygroup_t * 4337c478bd9Sstevel@tonic-gate get_script_pg(const char *script, boolean_t start_flag, boolean_t *ok) 4347c478bd9Sstevel@tonic-gate { 4357c478bd9Sstevel@tonic-gate scf_handle_t *h = NULL; 4367c478bd9Sstevel@tonic-gate scf_scope_t *scope = NULL; 4377c478bd9Sstevel@tonic-gate scf_service_t *svc = NULL; 4387c478bd9Sstevel@tonic-gate scf_propertygroup_t *pg = NULL; 4397c478bd9Sstevel@tonic-gate 4407c478bd9Sstevel@tonic-gate *ok = 0; 4417c478bd9Sstevel@tonic-gate 4427c478bd9Sstevel@tonic-gate h = scf_handle_create(SCF_VERSION); 4437c478bd9Sstevel@tonic-gate if (h == NULL) { 4447c478bd9Sstevel@tonic-gate scferr("scf_handle_create()"); 4457c478bd9Sstevel@tonic-gate goto out; 4467c478bd9Sstevel@tonic-gate } 4477c478bd9Sstevel@tonic-gate 4487c478bd9Sstevel@tonic-gate if (scf_handle_bind(h) != 0) { 4497c478bd9Sstevel@tonic-gate if (scf_error() != SCF_ERROR_NO_SERVER) { 4507c478bd9Sstevel@tonic-gate scferr("scf_handle_bind()"); 4517c478bd9Sstevel@tonic-gate } else { 4527c478bd9Sstevel@tonic-gate uu_warn(gettext( 4537c478bd9Sstevel@tonic-gate "Could not connect to svc.configd.\n")); 4547c478bd9Sstevel@tonic-gate } 4557c478bd9Sstevel@tonic-gate goto out; 4567c478bd9Sstevel@tonic-gate } 4577c478bd9Sstevel@tonic-gate 4587c478bd9Sstevel@tonic-gate if ((scope = scf_scope_create(h)) == NULL) { 4597c478bd9Sstevel@tonic-gate scferr("scf_scope_create()"); 4607c478bd9Sstevel@tonic-gate goto out; 4617c478bd9Sstevel@tonic-gate } 4627c478bd9Sstevel@tonic-gate 4637c478bd9Sstevel@tonic-gate if ((svc = scf_service_create(h)) == NULL) { 4647c478bd9Sstevel@tonic-gate scferr("scf_service_create()"); 4657c478bd9Sstevel@tonic-gate goto out; 4667c478bd9Sstevel@tonic-gate } 4677c478bd9Sstevel@tonic-gate 4687c478bd9Sstevel@tonic-gate if (scf_handle_get_scope(h, SCF_SCOPE_LOCAL, scope) != 0) { 4697c478bd9Sstevel@tonic-gate scferr("scf_handle_get_local_scope()"); 4707c478bd9Sstevel@tonic-gate goto out; 4717c478bd9Sstevel@tonic-gate } 4727c478bd9Sstevel@tonic-gate 4737c478bd9Sstevel@tonic-gate if (scf_scope_get_service(scope, SCF_LEGACY_SERVICE, svc) != 0) { 4747c478bd9Sstevel@tonic-gate if (scf_error() != SCF_ERROR_NOT_FOUND) { 4757c478bd9Sstevel@tonic-gate scferr("scf_scope_get_service()"); 4767c478bd9Sstevel@tonic-gate goto out; 4777c478bd9Sstevel@tonic-gate } 4787c478bd9Sstevel@tonic-gate 4797c478bd9Sstevel@tonic-gate if (scf_scope_add_service(scope, SCF_LEGACY_SERVICE, svc) != 4807c478bd9Sstevel@tonic-gate 0) { 4817c478bd9Sstevel@tonic-gate scferr("scf_scope_add_service()"); 4827c478bd9Sstevel@tonic-gate goto out; 4837c478bd9Sstevel@tonic-gate } 4847c478bd9Sstevel@tonic-gate } 4857c478bd9Sstevel@tonic-gate 4867c478bd9Sstevel@tonic-gate if (start_flag) 4877c478bd9Sstevel@tonic-gate pg = get_start_pg(script, h, svc, ok); 4887c478bd9Sstevel@tonic-gate else 4897c478bd9Sstevel@tonic-gate pg = get_stop_pg(script, h, svc, ok); 4907c478bd9Sstevel@tonic-gate 4917c478bd9Sstevel@tonic-gate out: 4927c478bd9Sstevel@tonic-gate scf_service_destroy(svc); 4937c478bd9Sstevel@tonic-gate scf_scope_destroy(scope); 4947c478bd9Sstevel@tonic-gate return (pg); 4957c478bd9Sstevel@tonic-gate } 4967c478bd9Sstevel@tonic-gate 4977c478bd9Sstevel@tonic-gate static int 4987c478bd9Sstevel@tonic-gate prepare_contract() 4997c478bd9Sstevel@tonic-gate { 5007c478bd9Sstevel@tonic-gate int fd; 5017c478bd9Sstevel@tonic-gate 5027c478bd9Sstevel@tonic-gate do 5037c478bd9Sstevel@tonic-gate fd = open64(CTFS_ROOT "/process/template", O_RDWR); 5047c478bd9Sstevel@tonic-gate while (fd < 0 && errno == EINTR); 5057c478bd9Sstevel@tonic-gate if (fd < 0) { 5067c478bd9Sstevel@tonic-gate uu_warn(gettext("Can not create contract")); 5077c478bd9Sstevel@tonic-gate return (-1); 5087c478bd9Sstevel@tonic-gate } 5097c478bd9Sstevel@tonic-gate 5107c478bd9Sstevel@tonic-gate /* Leave HWERR in fatal set. */ 5117c478bd9Sstevel@tonic-gate 5127c478bd9Sstevel@tonic-gate errno = ct_tmpl_activate(fd); 5137c478bd9Sstevel@tonic-gate if (errno != 0) { 5147c478bd9Sstevel@tonic-gate assert(errno == EPERM); 5157c478bd9Sstevel@tonic-gate uu_warn(gettext("Can not activate contract template")); 5167c478bd9Sstevel@tonic-gate (void) close(fd); 5177c478bd9Sstevel@tonic-gate return (-1); 5187c478bd9Sstevel@tonic-gate } 5197c478bd9Sstevel@tonic-gate 5207c478bd9Sstevel@tonic-gate (void) close(fd); 5217c478bd9Sstevel@tonic-gate return (0); 5227c478bd9Sstevel@tonic-gate } 5237c478bd9Sstevel@tonic-gate 5247c478bd9Sstevel@tonic-gate static void 5257c478bd9Sstevel@tonic-gate cleanup_pg(scf_propertygroup_t *pg) 5267c478bd9Sstevel@tonic-gate { 5277c478bd9Sstevel@tonic-gate scf_error_t err; 5287c478bd9Sstevel@tonic-gate char buf[80]; 5297c478bd9Sstevel@tonic-gate 5307c478bd9Sstevel@tonic-gate if (scf_pg_delete(pg) == 0) 5317c478bd9Sstevel@tonic-gate return; 5327c478bd9Sstevel@tonic-gate 5337c478bd9Sstevel@tonic-gate err = scf_error(); 5347c478bd9Sstevel@tonic-gate 5357c478bd9Sstevel@tonic-gate if (scf_pg_to_fmri(pg, buf, sizeof (buf)) != 0) 5367c478bd9Sstevel@tonic-gate (void) strcpy(buf, "?"); 5377c478bd9Sstevel@tonic-gate 5387c478bd9Sstevel@tonic-gate uu_warn(gettext("Could not remove property group %s: %s.\n"), buf, 5397c478bd9Sstevel@tonic-gate scf_strerror(err)); 5407c478bd9Sstevel@tonic-gate } 5417c478bd9Sstevel@tonic-gate 5427c478bd9Sstevel@tonic-gate /* 5437c478bd9Sstevel@tonic-gate * Create a duplicate environment which only contains approved 5447c478bd9Sstevel@tonic-gate * variables---those in evars_to_pass and those beginning with "_INIT_". 5457c478bd9Sstevel@tonic-gate */ 5467c478bd9Sstevel@tonic-gate static char ** 5477c478bd9Sstevel@tonic-gate approved_env(char **env) 5487c478bd9Sstevel@tonic-gate { 5497c478bd9Sstevel@tonic-gate char **newenv; 5507c478bd9Sstevel@tonic-gate int i, i_new, j; 5517c478bd9Sstevel@tonic-gate 5527c478bd9Sstevel@tonic-gate for (i = 0; env[i] != NULL; ++i) 5537c478bd9Sstevel@tonic-gate ; 5547c478bd9Sstevel@tonic-gate 5557c478bd9Sstevel@tonic-gate newenv = malloc(sizeof (*newenv) * (i + 1)); 5567c478bd9Sstevel@tonic-gate if (newenv == NULL) 5577c478bd9Sstevel@tonic-gate return (NULL); 5587c478bd9Sstevel@tonic-gate 5597c478bd9Sstevel@tonic-gate i_new = 0; 5607c478bd9Sstevel@tonic-gate 5617c478bd9Sstevel@tonic-gate for (i = 0; env[i] != NULL; ++i) { 5627c478bd9Sstevel@tonic-gate if (strncmp(env[i], "_INIT_", sizeof ("_INIT_") - 1) == 0) { 5637c478bd9Sstevel@tonic-gate newenv[i_new++] = env[i]; 5647c478bd9Sstevel@tonic-gate continue; 5657c478bd9Sstevel@tonic-gate } 5667c478bd9Sstevel@tonic-gate 5677c478bd9Sstevel@tonic-gate for (j = 0; j < EVARS_TO_PASS_NUM; ++j) { 5687c478bd9Sstevel@tonic-gate size_t l = strlen(evars_to_pass[j]); 5697c478bd9Sstevel@tonic-gate 5707c478bd9Sstevel@tonic-gate if (env[i][l] == '=' && 5717c478bd9Sstevel@tonic-gate strncmp(env[i], evars_to_pass[j], l) == 0) 5727c478bd9Sstevel@tonic-gate newenv[i_new++] = env[i]; 5737c478bd9Sstevel@tonic-gate } 5747c478bd9Sstevel@tonic-gate } 5757c478bd9Sstevel@tonic-gate 5767c478bd9Sstevel@tonic-gate newenv[i_new] = NULL; 5777c478bd9Sstevel@tonic-gate 5787c478bd9Sstevel@tonic-gate return (newenv); 5797c478bd9Sstevel@tonic-gate } 5807c478bd9Sstevel@tonic-gate 5817c478bd9Sstevel@tonic-gate /* 5827c478bd9Sstevel@tonic-gate * Create a duplicate environment which does not contain any SMF_ variables. 5837c478bd9Sstevel@tonic-gate */ 5847c478bd9Sstevel@tonic-gate static char ** 5857c478bd9Sstevel@tonic-gate env_without_smf(char **env) 5867c478bd9Sstevel@tonic-gate { 5877c478bd9Sstevel@tonic-gate char **newenv; 5887c478bd9Sstevel@tonic-gate int i, i_new; 5897c478bd9Sstevel@tonic-gate 5907c478bd9Sstevel@tonic-gate for (i = 0; env[i] != NULL; ++i) 5917c478bd9Sstevel@tonic-gate ; 5927c478bd9Sstevel@tonic-gate 5937c478bd9Sstevel@tonic-gate newenv = malloc(sizeof (*newenv) * (i + 1)); 5947c478bd9Sstevel@tonic-gate if (newenv == NULL) 5957c478bd9Sstevel@tonic-gate return (NULL); 5967c478bd9Sstevel@tonic-gate 5977c478bd9Sstevel@tonic-gate i_new = 0; 5987c478bd9Sstevel@tonic-gate 5997c478bd9Sstevel@tonic-gate for (i = 0; env[i] != NULL; ++i) { 6007c478bd9Sstevel@tonic-gate if (strncmp(env[i], "SMF_", sizeof ("SMF_") - 1) == 0) 6017c478bd9Sstevel@tonic-gate continue; 6027c478bd9Sstevel@tonic-gate 6037c478bd9Sstevel@tonic-gate newenv[i_new++] = env[i]; 6047c478bd9Sstevel@tonic-gate } 6057c478bd9Sstevel@tonic-gate 6067c478bd9Sstevel@tonic-gate newenv[i_new] = NULL; 6077c478bd9Sstevel@tonic-gate 6087c478bd9Sstevel@tonic-gate return (newenv); 6097c478bd9Sstevel@tonic-gate } 6107c478bd9Sstevel@tonic-gate 6117c478bd9Sstevel@tonic-gate static int 6127c478bd9Sstevel@tonic-gate add_new_property(scf_handle_t *h, scf_transaction_t *tx, const char *name, 6137c478bd9Sstevel@tonic-gate scf_type_t ty, const void *val) 6147c478bd9Sstevel@tonic-gate { 6157c478bd9Sstevel@tonic-gate scf_transaction_entry_t *e; 6167c478bd9Sstevel@tonic-gate scf_value_t *v; 6177c478bd9Sstevel@tonic-gate const char *func; 6187c478bd9Sstevel@tonic-gate const struct timeval *t; 6197c478bd9Sstevel@tonic-gate int r; 6207c478bd9Sstevel@tonic-gate 6217c478bd9Sstevel@tonic-gate if ((e = scf_entry_create(h)) == NULL) { 6227c478bd9Sstevel@tonic-gate func = "scf_entry_create()"; 6237c478bd9Sstevel@tonic-gate goto err; 6247c478bd9Sstevel@tonic-gate } 6257c478bd9Sstevel@tonic-gate 6267c478bd9Sstevel@tonic-gate if ((v = scf_value_create(h)) == NULL) { 6277c478bd9Sstevel@tonic-gate func = "scf_value_create()"; 6287c478bd9Sstevel@tonic-gate goto err; 6297c478bd9Sstevel@tonic-gate } 6307c478bd9Sstevel@tonic-gate 6317c478bd9Sstevel@tonic-gate r = scf_transaction_property_new(tx, e, name, ty); 6327c478bd9Sstevel@tonic-gate if (r != 0) { 6337c478bd9Sstevel@tonic-gate func = "scf_transaction_property_new()"; 6347c478bd9Sstevel@tonic-gate goto err; 6357c478bd9Sstevel@tonic-gate } 6367c478bd9Sstevel@tonic-gate 6377c478bd9Sstevel@tonic-gate switch (ty) { 6387c478bd9Sstevel@tonic-gate case SCF_TYPE_COUNT: 639*0b5c9250Shg115875 scf_value_set_count(v, (uint64_t)(uintptr_t)val); 6407c478bd9Sstevel@tonic-gate break; 6417c478bd9Sstevel@tonic-gate 6427c478bd9Sstevel@tonic-gate case SCF_TYPE_TIME: 6437c478bd9Sstevel@tonic-gate t = val; 6447c478bd9Sstevel@tonic-gate r = scf_value_set_time(v, t->tv_sec, 1000 * t->tv_usec); 6457c478bd9Sstevel@tonic-gate assert(r == 0); 6467c478bd9Sstevel@tonic-gate break; 6477c478bd9Sstevel@tonic-gate 6487c478bd9Sstevel@tonic-gate case SCF_TYPE_ASTRING: 6497c478bd9Sstevel@tonic-gate r = scf_value_set_astring(v, val); 6507c478bd9Sstevel@tonic-gate assert(r == 0); 6517c478bd9Sstevel@tonic-gate break; 6527c478bd9Sstevel@tonic-gate 6537c478bd9Sstevel@tonic-gate default: 6547c478bd9Sstevel@tonic-gate assert(0); 6557c478bd9Sstevel@tonic-gate abort(); 6567c478bd9Sstevel@tonic-gate } 6577c478bd9Sstevel@tonic-gate 6587c478bd9Sstevel@tonic-gate if (scf_entry_add_value(e, v) == 0) 6597c478bd9Sstevel@tonic-gate return (0); 6607c478bd9Sstevel@tonic-gate 6617c478bd9Sstevel@tonic-gate func = "scf_entry_add_value()"; 6627c478bd9Sstevel@tonic-gate 6637c478bd9Sstevel@tonic-gate err: 6647c478bd9Sstevel@tonic-gate uu_warn(gettext("%s failed (%s).\n"), func, scf_strerror(scf_error())); 6657c478bd9Sstevel@tonic-gate return (-1); 6667c478bd9Sstevel@tonic-gate } 6677c478bd9Sstevel@tonic-gate 6687c478bd9Sstevel@tonic-gate static void 6697c478bd9Sstevel@tonic-gate set_legacy_service(scf_propertygroup_t *pg, const char *script) 6707c478bd9Sstevel@tonic-gate { 6717c478bd9Sstevel@tonic-gate scf_handle_t *h; 6727c478bd9Sstevel@tonic-gate const char *func; 6737c478bd9Sstevel@tonic-gate char *suffix; 6747c478bd9Sstevel@tonic-gate scf_transaction_t *tx; 6757c478bd9Sstevel@tonic-gate struct timeval tstamp; 6767c478bd9Sstevel@tonic-gate struct stat st; 6777c478bd9Sstevel@tonic-gate ctid_t ctid; 6787c478bd9Sstevel@tonic-gate char *svc_name = NULL; 6797c478bd9Sstevel@tonic-gate int ret; 6807c478bd9Sstevel@tonic-gate 6817c478bd9Sstevel@tonic-gate h = scf_pg_handle(pg); 6827c478bd9Sstevel@tonic-gate if (h == NULL) { 6837c478bd9Sstevel@tonic-gate func = "scf_pg_handle()"; 6847c478bd9Sstevel@tonic-gate goto scferr; 6857c478bd9Sstevel@tonic-gate } 6867c478bd9Sstevel@tonic-gate 6877c478bd9Sstevel@tonic-gate ret = gettimeofday(&tstamp, NULL); 6887c478bd9Sstevel@tonic-gate assert(ret == 0); 6897c478bd9Sstevel@tonic-gate 6907c478bd9Sstevel@tonic-gate if (stat(script, &st) != 0) { 6917c478bd9Sstevel@tonic-gate uu_warn(gettext("Couldn't stat %s (%s).\n"), script, 6927c478bd9Sstevel@tonic-gate strerror(errno)); 6937c478bd9Sstevel@tonic-gate goto err; 6947c478bd9Sstevel@tonic-gate } 6957c478bd9Sstevel@tonic-gate 6967c478bd9Sstevel@tonic-gate if (errno = contract_latest(&ctid)) { 6977c478bd9Sstevel@tonic-gate uu_warn(gettext("Could not get contract")); 6987c478bd9Sstevel@tonic-gate goto err; 6997c478bd9Sstevel@tonic-gate } 7007c478bd9Sstevel@tonic-gate 7017c478bd9Sstevel@tonic-gate tx = scf_transaction_create(h); 7027c478bd9Sstevel@tonic-gate if (tx == NULL) { 7037c478bd9Sstevel@tonic-gate func = "scf_transaction_create()"; 7047c478bd9Sstevel@tonic-gate goto scferr; 7057c478bd9Sstevel@tonic-gate } 7067c478bd9Sstevel@tonic-gate 7077c478bd9Sstevel@tonic-gate if (scf_transaction_start(tx, pg) != 0) { 7087c478bd9Sstevel@tonic-gate func = "scf_transaction_start()"; 7097c478bd9Sstevel@tonic-gate goto scferr; 7107c478bd9Sstevel@tonic-gate } 7117c478bd9Sstevel@tonic-gate 7127c478bd9Sstevel@tonic-gate /* 7137c478bd9Sstevel@tonic-gate * We'd like to use the prettier svc_name, but if path_to_svc_name() 7147c478bd9Sstevel@tonic-gate * fails, we can use the script name anyway. 7157c478bd9Sstevel@tonic-gate */ 7167c478bd9Sstevel@tonic-gate svc_name = path_to_svc_name(script); 7177c478bd9Sstevel@tonic-gate 7187c478bd9Sstevel@tonic-gate if (add_new_property(h, tx, SCF_LEGACY_PROPERTY_NAME, SCF_TYPE_ASTRING, 7197c478bd9Sstevel@tonic-gate (void *)(svc_name ? svc_name : script)) != 0) 7207c478bd9Sstevel@tonic-gate goto err; 7217c478bd9Sstevel@tonic-gate 7227c478bd9Sstevel@tonic-gate if (add_new_property(h, tx, SCF_PROPERTY_STATE_TIMESTAMP, 7237c478bd9Sstevel@tonic-gate SCF_TYPE_TIME, &tstamp) != 0) 7247c478bd9Sstevel@tonic-gate goto err; 7257c478bd9Sstevel@tonic-gate 7267c478bd9Sstevel@tonic-gate if (add_new_property(h, tx, SCF_LEGACY_PROPERTY_INODE, 7277c478bd9Sstevel@tonic-gate SCF_TYPE_COUNT, (void *)st.st_ino) != 0) 7287c478bd9Sstevel@tonic-gate goto err; 7297c478bd9Sstevel@tonic-gate 7307c478bd9Sstevel@tonic-gate if ((suffix = script_suffix(script)) != NULL) { 7317c478bd9Sstevel@tonic-gate if (add_new_property(h, tx, SCF_LEGACY_PROPERTY_SUFFIX, 7327c478bd9Sstevel@tonic-gate SCF_TYPE_ASTRING, (void *)suffix) != 0) 7337c478bd9Sstevel@tonic-gate goto err; 7347c478bd9Sstevel@tonic-gate 7357c478bd9Sstevel@tonic-gate free(suffix); 7367c478bd9Sstevel@tonic-gate } 7377c478bd9Sstevel@tonic-gate 7387c478bd9Sstevel@tonic-gate if (add_new_property(h, tx, SCF_PROPERTY_CONTRACT, SCF_TYPE_COUNT, 7397c478bd9Sstevel@tonic-gate (void *)ctid) != 0) 7407c478bd9Sstevel@tonic-gate goto err; 7417c478bd9Sstevel@tonic-gate 7427c478bd9Sstevel@tonic-gate for (;;) { 7437c478bd9Sstevel@tonic-gate switch (scf_transaction_commit(tx)) { 7447c478bd9Sstevel@tonic-gate case 1: 7457c478bd9Sstevel@tonic-gate free(svc_name); 7467c478bd9Sstevel@tonic-gate return; 7477c478bd9Sstevel@tonic-gate 7487c478bd9Sstevel@tonic-gate case 0: 7497c478bd9Sstevel@tonic-gate if (scf_pg_update(pg) == -1) { 7507c478bd9Sstevel@tonic-gate func = "scf_pg_update()"; 7517c478bd9Sstevel@tonic-gate goto scferr; 7527c478bd9Sstevel@tonic-gate } 7537c478bd9Sstevel@tonic-gate continue; 7547c478bd9Sstevel@tonic-gate 7557c478bd9Sstevel@tonic-gate case -1: 7567c478bd9Sstevel@tonic-gate func = "scf_transaction_commit()"; 7577c478bd9Sstevel@tonic-gate goto scferr; 7587c478bd9Sstevel@tonic-gate 7597c478bd9Sstevel@tonic-gate default: 7607c478bd9Sstevel@tonic-gate assert(0); 7617c478bd9Sstevel@tonic-gate abort(); 7627c478bd9Sstevel@tonic-gate } 7637c478bd9Sstevel@tonic-gate } 7647c478bd9Sstevel@tonic-gate 7657c478bd9Sstevel@tonic-gate scferr: 7667c478bd9Sstevel@tonic-gate uu_warn(gettext("%s failed (%s).\n"), func, scf_strerror(scf_error())); 7677c478bd9Sstevel@tonic-gate err: 7687c478bd9Sstevel@tonic-gate uu_die(gettext("Could not commit property values to repository.\n")); 7697c478bd9Sstevel@tonic-gate } 7707c478bd9Sstevel@tonic-gate 7717c478bd9Sstevel@tonic-gate int 7727c478bd9Sstevel@tonic-gate main(int argc, char *argv[], char *envp[]) 7737c478bd9Sstevel@tonic-gate { 7747c478bd9Sstevel@tonic-gate const char *restarter, *script, *action; 7757c478bd9Sstevel@tonic-gate boolean_t source = 0; 7767c478bd9Sstevel@tonic-gate int o; 7777c478bd9Sstevel@tonic-gate boolean_t start_flag; 7787c478bd9Sstevel@tonic-gate char **newenv; 7797c478bd9Sstevel@tonic-gate pid_t pid; 7807c478bd9Sstevel@tonic-gate int pipefds[2]; 7817c478bd9Sstevel@tonic-gate char c; 7827c478bd9Sstevel@tonic-gate int exitstatus; 7837c478bd9Sstevel@tonic-gate 7847c478bd9Sstevel@tonic-gate scf_propertygroup_t *pg; 7857c478bd9Sstevel@tonic-gate boolean_t pg_ok; 7867c478bd9Sstevel@tonic-gate 7877c478bd9Sstevel@tonic-gate (void) uu_setpname(argv[0]); 7887c478bd9Sstevel@tonic-gate uu_alt_exit(UU_PROFILE_LAUNCHER); 7897c478bd9Sstevel@tonic-gate 7907c478bd9Sstevel@tonic-gate /* Make sure we were run by svc.startd. */ 7917c478bd9Sstevel@tonic-gate if ((restarter = getenv("SMF_RESTARTER")) == NULL || 7927c478bd9Sstevel@tonic-gate strcmp(restarter, SCF_SERVICE_STARTD) != 0) 7937c478bd9Sstevel@tonic-gate uu_die(gettext("invocation outside smf(5) inappropriate\n")); 7947c478bd9Sstevel@tonic-gate 7957c478bd9Sstevel@tonic-gate while ((o = getopt(argc, argv, "s")) != -1) { 7967c478bd9Sstevel@tonic-gate switch (o) { 7977c478bd9Sstevel@tonic-gate case 's': 7987c478bd9Sstevel@tonic-gate source = 1; 7997c478bd9Sstevel@tonic-gate break; 8007c478bd9Sstevel@tonic-gate 8017c478bd9Sstevel@tonic-gate default: 8027c478bd9Sstevel@tonic-gate usage(); 8037c478bd9Sstevel@tonic-gate } 8047c478bd9Sstevel@tonic-gate } 8057c478bd9Sstevel@tonic-gate 8067c478bd9Sstevel@tonic-gate if (argc - optind != 2) 8077c478bd9Sstevel@tonic-gate usage(); 8087c478bd9Sstevel@tonic-gate 8097c478bd9Sstevel@tonic-gate script = argv[optind]; 8107c478bd9Sstevel@tonic-gate action = argv[optind + 1]; 8117c478bd9Sstevel@tonic-gate 8127c478bd9Sstevel@tonic-gate if (strcmp(action, "start") == 0) 8137c478bd9Sstevel@tonic-gate start_flag = 1; 8147c478bd9Sstevel@tonic-gate else if (strcmp(action, "stop") == 0) 8157c478bd9Sstevel@tonic-gate start_flag = 0; 8167c478bd9Sstevel@tonic-gate else 8177c478bd9Sstevel@tonic-gate usage(); 8187c478bd9Sstevel@tonic-gate 8197c478bd9Sstevel@tonic-gate /* 8207c478bd9Sstevel@tonic-gate * Look for the pg & exit if appropriate. Also, if we're starting, 8217c478bd9Sstevel@tonic-gate * add the pg now so we can exit before launching the script if we 8227c478bd9Sstevel@tonic-gate * have insufficient repository privilege. 8237c478bd9Sstevel@tonic-gate * 8247c478bd9Sstevel@tonic-gate * If any other problem occurs, we carry on anyway. 8257c478bd9Sstevel@tonic-gate */ 8267c478bd9Sstevel@tonic-gate pg = get_script_pg(script, start_flag, &pg_ok); 8277c478bd9Sstevel@tonic-gate 8287c478bd9Sstevel@tonic-gate /* Clean the environment. Now so we can fail early. */ 8297c478bd9Sstevel@tonic-gate if (!source) 8307c478bd9Sstevel@tonic-gate newenv = approved_env(envp); 8317c478bd9Sstevel@tonic-gate else 8327c478bd9Sstevel@tonic-gate newenv = env_without_smf(envp); 8337c478bd9Sstevel@tonic-gate if (newenv == NULL) 8347c478bd9Sstevel@tonic-gate uu_die(gettext( 8357c478bd9Sstevel@tonic-gate "Could not create new environment: out of memory.\n")); 8367c478bd9Sstevel@tonic-gate 8377c478bd9Sstevel@tonic-gate if (prepare_contract() == -1) { 8387c478bd9Sstevel@tonic-gate if (start_flag && pg != NULL) 8397c478bd9Sstevel@tonic-gate cleanup_pg(pg); 8407c478bd9Sstevel@tonic-gate 8417c478bd9Sstevel@tonic-gate exit(UU_EXIT_FATAL); 8427c478bd9Sstevel@tonic-gate } 8437c478bd9Sstevel@tonic-gate 8447c478bd9Sstevel@tonic-gate /* pipe to communicate exec success or failure */ 8457c478bd9Sstevel@tonic-gate if (pipe(pipefds) != 0) { 8467c478bd9Sstevel@tonic-gate uu_warn(gettext("Could not create pipe")); 8477c478bd9Sstevel@tonic-gate 8487c478bd9Sstevel@tonic-gate if (start_flag && pg != NULL) 8497c478bd9Sstevel@tonic-gate cleanup_pg(pg); 8507c478bd9Sstevel@tonic-gate 8517c478bd9Sstevel@tonic-gate exit(UU_EXIT_FATAL); 8527c478bd9Sstevel@tonic-gate } 8537c478bd9Sstevel@tonic-gate 8547c478bd9Sstevel@tonic-gate if (!pg_ok) 8557c478bd9Sstevel@tonic-gate (void) printf(gettext("Executing legacy init script \"%s\" " 8567c478bd9Sstevel@tonic-gate "despite previous errors.\n"), script); 8577c478bd9Sstevel@tonic-gate else 8587c478bd9Sstevel@tonic-gate (void) printf(gettext("Executing legacy init script \"%s\".\n"), 8597c478bd9Sstevel@tonic-gate script); 8607c478bd9Sstevel@tonic-gate (void) fflush(stdout); 8617c478bd9Sstevel@tonic-gate 8627c478bd9Sstevel@tonic-gate pid = fork(); 8637c478bd9Sstevel@tonic-gate if (pid < 0) { 8647c478bd9Sstevel@tonic-gate uu_warn(gettext("Could not fork")); 8657c478bd9Sstevel@tonic-gate 8667c478bd9Sstevel@tonic-gate if (start_flag && pg != NULL) 8677c478bd9Sstevel@tonic-gate cleanup_pg(pg); 8687c478bd9Sstevel@tonic-gate 8697c478bd9Sstevel@tonic-gate exit(UU_EXIT_FATAL); 8707c478bd9Sstevel@tonic-gate } 8717c478bd9Sstevel@tonic-gate 8727c478bd9Sstevel@tonic-gate if (pid == 0) { 8737c478bd9Sstevel@tonic-gate /* child */ 8747c478bd9Sstevel@tonic-gate 8757c478bd9Sstevel@tonic-gate const char *arg1, *arg2, *arg3; 8767c478bd9Sstevel@tonic-gate 8777c478bd9Sstevel@tonic-gate (void) close(pipefds[0]); 8787c478bd9Sstevel@tonic-gate (void) fcntl(pipefds[1], F_SETFD, FD_CLOEXEC); 8797c478bd9Sstevel@tonic-gate 8807c478bd9Sstevel@tonic-gate if (!source) { 8817c478bd9Sstevel@tonic-gate arg1 = "/bin/sh"; 8827c478bd9Sstevel@tonic-gate arg2 = script; 8837c478bd9Sstevel@tonic-gate arg3 = action; 8847c478bd9Sstevel@tonic-gate } else { 8857c478bd9Sstevel@tonic-gate arg1 = "/bin/sh"; 8867c478bd9Sstevel@tonic-gate arg2 = "-c"; 8877c478bd9Sstevel@tonic-gate arg3 = script; 8887c478bd9Sstevel@tonic-gate } 8897c478bd9Sstevel@tonic-gate 8907c478bd9Sstevel@tonic-gate (void) execle(arg1, arg1, arg2, arg3, NULL, newenv); 8917c478bd9Sstevel@tonic-gate 8927c478bd9Sstevel@tonic-gate uu_warn(gettext("Could not exec \"%s %s %s\""), arg1, 8937c478bd9Sstevel@tonic-gate arg2, arg3); 8947c478bd9Sstevel@tonic-gate 8957c478bd9Sstevel@tonic-gate 8967c478bd9Sstevel@tonic-gate /* Notify parent of the failure. */ 8977c478bd9Sstevel@tonic-gate while (write(pipefds[1], &c, 1) != 1) { 8987c478bd9Sstevel@tonic-gate switch (errno) { 8997c478bd9Sstevel@tonic-gate case EAGAIN: 9007c478bd9Sstevel@tonic-gate (void) sleep(1); 9017c478bd9Sstevel@tonic-gate 9027c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 9037c478bd9Sstevel@tonic-gate 9047c478bd9Sstevel@tonic-gate case EINTR: 9057c478bd9Sstevel@tonic-gate continue; 9067c478bd9Sstevel@tonic-gate } 9077c478bd9Sstevel@tonic-gate 9087c478bd9Sstevel@tonic-gate uu_warn(gettext("Could not inform parent of error")); 9097c478bd9Sstevel@tonic-gate break; 9107c478bd9Sstevel@tonic-gate } 9117c478bd9Sstevel@tonic-gate 9127c478bd9Sstevel@tonic-gate exit(UU_EXIT_FATAL); 9137c478bd9Sstevel@tonic-gate } 9147c478bd9Sstevel@tonic-gate 9157c478bd9Sstevel@tonic-gate (void) close(pipefds[1]); 9167c478bd9Sstevel@tonic-gate 9177c478bd9Sstevel@tonic-gate if (read(pipefds[0], &c, sizeof (c)) > 0) { 9187c478bd9Sstevel@tonic-gate if (!start_flag) 9197c478bd9Sstevel@tonic-gate uu_die(gettext("exec() failed; leaving properties.\n")); 9207c478bd9Sstevel@tonic-gate else { 9217c478bd9Sstevel@tonic-gate uu_warn(gettext("exec() failed.\n")); 9227c478bd9Sstevel@tonic-gate if (pg != NULL) 9237c478bd9Sstevel@tonic-gate cleanup_pg(pg); 9247c478bd9Sstevel@tonic-gate exit(UU_EXIT_FATAL); 9257c478bd9Sstevel@tonic-gate } 9267c478bd9Sstevel@tonic-gate } 9277c478bd9Sstevel@tonic-gate 9287c478bd9Sstevel@tonic-gate while (waitpid(pid, &exitstatus, 0) == -1) { 9297c478bd9Sstevel@tonic-gate assert(errno == EINTR); 9307c478bd9Sstevel@tonic-gate } 9317c478bd9Sstevel@tonic-gate 9327c478bd9Sstevel@tonic-gate if (WIFSIGNALED(exitstatus)) { 9337c478bd9Sstevel@tonic-gate char buf[SIG2STR_MAX]; 9347c478bd9Sstevel@tonic-gate (void) sig2str(WTERMSIG(exitstatus), buf); 9357c478bd9Sstevel@tonic-gate (void) printf(gettext("Legacy init script \"%s\" failed due " 9367c478bd9Sstevel@tonic-gate "to signal %s.\n"), script, buf); 9377c478bd9Sstevel@tonic-gate } else { 9387c478bd9Sstevel@tonic-gate (void) printf(gettext("Legacy init script \"%s\" exited with " 9397c478bd9Sstevel@tonic-gate "return code %d.\n"), script, WEXITSTATUS(exitstatus)); 9407c478bd9Sstevel@tonic-gate } 9417c478bd9Sstevel@tonic-gate 9427c478bd9Sstevel@tonic-gate if (pg != NULL) { 9437c478bd9Sstevel@tonic-gate if (start_flag) 9447c478bd9Sstevel@tonic-gate set_legacy_service(pg, script); 9457c478bd9Sstevel@tonic-gate else 9467c478bd9Sstevel@tonic-gate cleanup_pg(pg); 9477c478bd9Sstevel@tonic-gate scf_pg_destroy(pg); 9487c478bd9Sstevel@tonic-gate } 9497c478bd9Sstevel@tonic-gate 9507c478bd9Sstevel@tonic-gate return (UU_EXIT_OK); 9517c478bd9Sstevel@tonic-gate } 952