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