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