xref: /illumos-gate/usr/src/cmd/svc/svccfg/svccfg_main.c (revision cbc1ee827389bb051e180a9bb8fe62c8136b0548)
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