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