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
usage()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 *
safe_malloc(size_t sz)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 *
safe_strdup(const char * cp)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
vmessage(const char * fmt,va_list va)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
warn(const char * fmt,...)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
synerr(int com)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
semerr(const char * fmt,...)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
initialize(int argc,char * argv[])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
main(int argc,char * argv[])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