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 53 #include "svccfg.h" 54 55 #ifndef TEXT_DOMAIN 56 #define TEXT_DOMAIN "SUNW_OST_OSCMD" 57 #endif /* TEXT_DOMAIN */ 58 59 #define MAX_CMD_LINE_SZ 2048 60 61 static const char *myname; 62 int g_verbose = 0; 63 int g_do_zone = 0; 64 char g_zonename[ZONENAME_MAX]; 65 const char *fmri; 66 67 static void 68 usage() 69 { 70 (void) fprintf(stderr, gettext( 71 "Usage:\tsvccfg [-v] [-z zone] [-s FMRI] [-f file]\n" 72 "\tsvccfg [-v] [-z zone] [-s FMRI] <command> [args]\n")); 73 exit(UU_EXIT_USAGE); 74 } 75 76 void * 77 safe_malloc(size_t sz) 78 { 79 void *p; 80 81 if ((p = calloc(1, sz)) == NULL) 82 uu_die(gettext("Out of memory.\n")); 83 84 return (p); 85 } 86 87 char * 88 safe_strdup(const char *cp) 89 { 90 char *result; 91 92 result = strdup(cp); 93 if (result == NULL) 94 uu_die(gettext("Out of memory.\n")); 95 96 return (result); 97 } 98 99 /* 100 * Send a message to the user. If we're interactive, send it to stdout. 101 * Otherwise send it to stderr. 102 */ 103 static void 104 vmessage(const char *fmt, va_list va) 105 { 106 int interactive = est->sc_cmd_flags & SC_CMD_IACTIVE; 107 FILE *strm = interactive ? stdout : stderr; 108 const char *ptr; 109 110 if (!interactive) { 111 if (est->sc_cmd_file == NULL) 112 (void) fprintf(stderr, "%s: ", myname); 113 else 114 (void) fprintf(stderr, "%s (%s, line %d): ", myname, 115 est->sc_cmd_filename, est->sc_cmd_lineno - 1); 116 } 117 118 if (vfprintf(strm, fmt, va) < 0 && interactive) 119 uu_die(gettext("printf() error")); 120 121 ptr = strchr(fmt, '\0'); 122 if (*(ptr - 1) != '\n') 123 (void) fprintf(strm, ": %s.\n", strerror(errno)); 124 } 125 126 /* 127 * Display a warning. Should usually be predicated by g_verbose. 128 */ 129 /* PRINTFLIKE1 */ 130 void 131 warn(const char *fmt, ...) 132 { 133 va_list va; 134 135 va_start(va, fmt); 136 vmessage(fmt, va); 137 va_end(va); 138 } 139 140 /* 141 * Syntax error. 142 */ 143 void 144 synerr(int com) 145 { 146 if (est->sc_cmd_flags & SC_CMD_IACTIVE) { 147 help(com); 148 return; 149 } 150 151 warn(gettext("Syntax error.\n")); 152 153 if ((est->sc_cmd_flags & SC_CMD_DONT_EXIT) == 0) 154 exit(1); 155 } 156 157 /* 158 * Semantic error. Display the warning and exit if we're not interactive. 159 */ 160 /* PRINTFLIKE1 */ 161 void 162 semerr(const char *fmt, ...) 163 { 164 va_list va; 165 166 va_start(va, fmt); 167 vmessage(fmt, va); 168 va_end(va); 169 170 if ((est->sc_cmd_flags & (SC_CMD_IACTIVE | SC_CMD_DONT_EXIT)) == 0) 171 exit(1); 172 } 173 174 /*ARGSUSED*/ 175 static void 176 initialize(int argc, char *argv[]) 177 { 178 myname = uu_setpname(argv[0]); 179 (void) atexit(lscf_cleanup); 180 181 (void) setlocale(LC_ALL, ""); 182 (void) textdomain(TEXT_DOMAIN); 183 184 (void) lxml_init(); 185 internal_init(); 186 engine_init(); 187 lscf_init(); /* must follow engine_init() */ 188 tmpl_init(); 189 } 190 191 int 192 main(int argc, char *argv[]) 193 { 194 char *cmd, *command_file = NULL; 195 char *fmri = NULL; 196 int c; 197 198 while ((c = getopt(argc, argv, "vf:s:z:")) != EOF) { 199 switch (c) { 200 case 'v': 201 g_verbose = 1; 202 break; 203 204 case 's': 205 fmri = optarg; 206 break; 207 208 case 'f': 209 command_file = optarg; 210 break; 211 212 case 'z': 213 if (getzoneid() != GLOBAL_ZONEID) { 214 uu_die(gettext("svccfg -z may only be used " 215 "from the global zone\n")); 216 } 217 218 if (strlcpy(g_zonename, optarg, sizeof (g_zonename)) >= 219 sizeof (g_zonename)) { 220 uu_die(gettext( 221 "The provided zone name is too long, " 222 "max %zd\n"), sizeof (g_zonename) - 1); 223 } 224 g_do_zone = 1; 225 break; 226 227 default: 228 usage(); 229 break; 230 } 231 } 232 233 initialize(argc, argv); 234 235 if (fmri != NULL) 236 lscf_select(fmri); 237 238 if (command_file != NULL) 239 return (engine_source(command_file, 0)); 240 241 if (optind == argc) { 242 if (isatty(fileno(stdin))) 243 return (engine_interp()); 244 else 245 return (engine_source("-", 0)); 246 } 247 248 /* 249 * Knit together remaining arguments into a single statement. 250 */ 251 cmd = safe_malloc(MAX_CMD_LINE_SZ); 252 for (c = optind; c < argc; c++) { 253 (void) strlcat(cmd, argv[c], MAX_CMD_LINE_SZ); 254 (void) strlcat(cmd, " ", MAX_CMD_LINE_SZ); 255 } 256 257 return (engine_exec(cmd)); 258 } 259