xref: /illumos-gate/usr/src/cmd/dumpadm/main.c (revision 60405de4d8688d96dd05157c28db3ade5c9bc234)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/stat.h>
30 #include <locale.h>
31 #include <unistd.h>
32 #include <stdlib.h>
33 #include <stdio.h>
34 
35 #include "dconf.h"
36 #include "minfree.h"
37 #include "utils.h"
38 
39 static const char USAGE[] = "\
40 Usage: %s [-nuy] [-c kernel | curproc | all ] [-d dump-device | swap ]\n\
41 	[-m min {k|m|%%} ] [-s savecore-dir] [-r root-dir]\n";
42 
43 static const char OPTS[] = "nuyc:d:m:s:r:";
44 
45 static const char PATH_DEVICE[] = "/dev/dump";
46 static const char PATH_CONFIG[] = "/etc/dumpadm.conf";
47 
48 int
49 main(int argc, char *argv[])
50 {
51 	const char *pname = getpname(argv[0]);
52 
53 	u_longlong_t minf;
54 	struct stat st;
55 	int c;
56 	int dflag = 0;			/* for checking in use during -d ops */
57 	int dcmode = DC_CURRENT;	/* kernel settings override unless -u */
58 	int modified = 0;		/* have we modified the dump config? */
59 	char *minfstr = NULL;		/* string value of -m argument */
60 	dumpconf_t dc;			/* current configuration */
61 
62 	(void) setlocale(LC_ALL, "");
63 	(void) textdomain(TEXT_DOMAIN);
64 
65 	/*
66 	 * Take an initial lap through argv hunting for -r root-dir,
67 	 * so that we can chroot before opening the configuration file.
68 	 * We also handle -u and any bad options at this point.
69 	 */
70 	while (optind < argc) {
71 		while ((c = getopt(argc, argv, OPTS)) != (int)EOF) {
72 			if (c == 'r' && chroot(optarg) == -1)
73 				die(gettext("failed to chroot to %s"), optarg);
74 			else if (c == 'u')
75 				dcmode = DC_OVERRIDE;
76 			else if (c == '?') {
77 				(void) fprintf(stderr, gettext(USAGE), pname);
78 				return (E_USAGE);
79 			}
80 		}
81 
82 		if (optind < argc) {
83 			warn(gettext("illegal argument -- %s\n"), argv[optind]);
84 			(void) fprintf(stderr, gettext(USAGE), pname);
85 			return (E_USAGE);
86 		}
87 	}
88 
89 	if (geteuid() != 0)
90 		die(gettext("you must be root to use %s\n"), pname);
91 
92 	/*
93 	 * If no config file exists yet, we're going to create an empty one,
94 	 * so set the modified flag to force writing out the file.
95 	 */
96 	if (access(PATH_CONFIG, F_OK) == -1)
97 		modified++;
98 
99 	/*
100 	 * Now open and read in the initial values from the config file.
101 	 * If it doesn't exist, we create an empty file and dc is
102 	 * initialized with the default values.
103 	 */
104 	if (dconf_open(&dc, PATH_DEVICE, PATH_CONFIG, dcmode) == -1)
105 		return (E_ERROR);
106 
107 	/*
108 	 * Take another lap through argv, processing options and
109 	 * modifying the dumpconf_t as appropriate.
110 	 */
111 	for (optind = 1; optind < argc; optind++) {
112 		while ((c = getopt(argc, argv, OPTS)) != (int)EOF) {
113 			switch (c) {
114 			case 'c':
115 				if (dconf_str2content(&dc, optarg) == -1)
116 					return (E_USAGE);
117 				modified++;
118 				break;
119 			case 'd':
120 				if (dconf_str2device(&dc, optarg) == -1)
121 					return (E_USAGE);
122 				dflag++;
123 				modified++;
124 				break;
125 
126 			case 'm':
127 				minfstr = optarg;
128 				break;
129 
130 			case 'n':
131 				dc.dc_enable = DC_OFF;
132 				modified++;
133 				break;
134 
135 			case 's':
136 				if (stat(optarg, &st) == -1 ||
137 				    !S_ISDIR(st.st_mode)) {
138 					warn(gettext("%s is missing or not a "
139 					    "directory\n"), optarg);
140 					return (E_USAGE);
141 				}
142 
143 				if (dconf_str2savdir(&dc, optarg) == -1)
144 					return (E_USAGE);
145 				modified++;
146 				break;
147 
148 			case 'y':
149 				dc.dc_enable = DC_ON;
150 				modified++;
151 				break;
152 			}
153 		}
154 	}
155 
156 	if (minfstr != NULL) {
157 		if (minfree_compute(dc.dc_savdir, minfstr, &minf) == -1)
158 			return (E_USAGE);
159 		if (minfree_write(dc.dc_savdir, minf) == -1)
160 			return (E_ERROR);
161 	}
162 
163 	if (dcmode == DC_OVERRIDE) {
164 		/*
165 		 * In override mode, we try to force an update.  If this
166 		 * fails, we re-load the kernel configuration and write that
167 		 * out to the file in order to force the file in sync.
168 		 */
169 		if (dconf_update(&dc, 0) == -1)
170 			(void) dconf_getdev(&dc);
171 		if (dconf_write(&dc) == -1)
172 			return (E_ERROR);
173 
174 	} else if (modified) {
175 		/*
176 		 * If we're modifying the configuration, then try
177 		 * to update it, and write out the file if successful.
178 		 */
179 		if (dconf_update(&dc, dflag) == -1 ||
180 		    dconf_write(&dc) == -1)
181 			return (E_ERROR);
182 	}
183 
184 	if (dcmode == DC_CURRENT)
185 		dconf_print(&dc, stdout);
186 
187 	if (dconf_close(&dc) == -1)
188 		warn(gettext("failed to close configuration file"));
189 
190 	return (E_SUCCESS);
191 }
192