1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * Copyright 2023 Oxide Computer Company 28 */ 29 30 /* 31 * svccfg - modify service configuration repository 32 */ 33 34 #include <sys/stat.h> 35 #include <sys/types.h> 36 #include <sys/wait.h> 37 #include <sys/zone.h> 38 39 #include <errno.h> 40 #include <libintl.h> 41 #include <libscf.h> 42 #include <libscf_priv.h> 43 #include <libuutil.h> 44 #include <locale.h> 45 #include <signal.h> 46 #include <stdarg.h> 47 #include <stddef.h> 48 #include <stdio.h> 49 #include <stdlib.h> 50 #include <string.h> 51 #include <unistd.h> 52 #include <zone.h> 53 54 #include "svccfg.h" 55 56 #ifndef TEXT_DOMAIN 57 #define TEXT_DOMAIN "SUNW_OST_OSCMD" 58 #endif /* TEXT_DOMAIN */ 59 60 #define MAX_CMD_LINE_SZ 2048 61 62 static const char *myname; 63 int g_verbose = 0; 64 int g_do_zone = 0; 65 char g_zonename[ZONENAME_MAX]; 66 const char *fmri; 67 68 static void 69 usage() 70 { 71 (void) fprintf(stderr, gettext( 72 "Usage:\tsvccfg [-v] [-z zone] [-s FMRI] [-f file]\n" 73 "\tsvccfg [-v] [-z zone] [-s FMRI] <command> [args]\n")); 74 exit(UU_EXIT_USAGE); 75 } 76 77 void * 78 safe_malloc(size_t sz) 79 { 80 void *p; 81 82 if ((p = calloc(1, sz)) == NULL) 83 uu_die(gettext("Out of memory.\n")); 84 85 return (p); 86 } 87 88 char * 89 safe_strdup(const char *cp) 90 { 91 char *result; 92 93 result = strdup(cp); 94 if (result == NULL) 95 uu_die(gettext("Out of memory.\n")); 96 97 return (result); 98 } 99 100 /* 101 * Send a message to the user. If we're interactive, send it to stdout. 102 * Otherwise send it to stderr. 103 */ 104 static void 105 vmessage(const char *fmt, va_list va) 106 { 107 int interactive = est->sc_cmd_flags & SC_CMD_IACTIVE; 108 FILE *strm = interactive ? stdout : stderr; 109 const char *ptr; 110 111 if (!interactive) { 112 if (est->sc_cmd_file == NULL) 113 (void) fprintf(stderr, "%s: ", myname); 114 else 115 (void) fprintf(stderr, "%s (%s, line %d): ", myname, 116 est->sc_cmd_filename, est->sc_cmd_lineno - 1); 117 } 118 119 if (vfprintf(strm, fmt, va) < 0 && interactive) 120 uu_die(gettext("printf() error")); 121 122 ptr = strchr(fmt, '\0'); 123 if (*(ptr - 1) != '\n') 124 (void) fprintf(strm, ": %s.\n", strerror(errno)); 125 } 126 127 /* 128 * Display a warning. Should usually be predicated by g_verbose. 129 */ 130 /* PRINTFLIKE1 */ 131 void 132 warn(const char *fmt, ...) 133 { 134 va_list va; 135 136 va_start(va, fmt); 137 vmessage(fmt, va); 138 va_end(va); 139 } 140 141 /* 142 * Syntax error. 143 */ 144 void 145 synerr(int com) 146 { 147 if (est->sc_cmd_flags & SC_CMD_IACTIVE) { 148 help(com); 149 return; 150 } 151 152 warn(gettext("Syntax error.\n")); 153 154 if ((est->sc_cmd_flags & SC_CMD_DONT_EXIT) == 0) 155 exit(1); 156 } 157 158 /* 159 * Semantic error. Display the warning and exit if we're not interactive. 160 */ 161 /* PRINTFLIKE1 */ 162 void 163 semerr(const char *fmt, ...) 164 { 165 va_list va; 166 167 va_start(va, fmt); 168 vmessage(fmt, va); 169 va_end(va); 170 171 if ((est->sc_cmd_flags & (SC_CMD_IACTIVE | SC_CMD_DONT_EXIT)) == 0) 172 exit(1); 173 } 174 175 /*ARGSUSED*/ 176 static void 177 initialize(int argc, char *argv[]) 178 { 179 myname = uu_setpname(argv[0]); 180 (void) atexit(lscf_cleanup); 181 182 (void) setlocale(LC_ALL, ""); 183 (void) textdomain(TEXT_DOMAIN); 184 185 (void) lxml_init(); 186 internal_init(); 187 engine_init(); 188 lscf_init(); /* must follow engine_init() */ 189 tmpl_init(); 190 } 191 192 int 193 main(int argc, char *argv[]) 194 { 195 char *cmd, *command_file = NULL; 196 char *fmri = NULL; 197 int c; 198 199 while ((c = getopt(argc, argv, "vf:s:z:")) != EOF) { 200 switch (c) { 201 case 'v': 202 g_verbose = 1; 203 break; 204 205 case 's': 206 fmri = optarg; 207 break; 208 209 case 'f': 210 command_file = optarg; 211 break; 212 213 case 'z': 214 if (getzoneid() != GLOBAL_ZONEID) { 215 uu_die(gettext("svccfg -z may only be used " 216 "from the global zone\n")); 217 } 218 219 if (strlcpy(g_zonename, optarg, sizeof (g_zonename)) >= 220 sizeof (g_zonename)) { 221 uu_die(gettext( 222 "The provided zone name is too long, " 223 "max %zd\n"), sizeof (g_zonename) - 1); 224 } 225 g_do_zone = 1; 226 break; 227 228 default: 229 usage(); 230 break; 231 } 232 } 233 234 initialize(argc, argv); 235 236 if (fmri != NULL) 237 lscf_select(fmri); 238 239 if (command_file != NULL) 240 return (engine_source(command_file, 0)); 241 242 if (optind == argc) { 243 if (isatty(fileno(stdin))) 244 return (engine_interp()); 245 else 246 return (engine_source("-", 0)); 247 } 248 249 /* 250 * Knit together remaining arguments into a single statement. 251 */ 252 cmd = safe_malloc(MAX_CMD_LINE_SZ); 253 for (c = optind; c < argc; c++) { 254 (void) strlcat(cmd, argv[c], MAX_CMD_LINE_SZ); 255 (void) strlcat(cmd, " ", MAX_CMD_LINE_SZ); 256 } 257 258 return (engine_exec(cmd)); 259 } 260