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 2004 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/types.h> 30 #include <sys/stat.h> 31 #include <sys/wait.h> 32 #include <fcntl.h> 33 #include <errno.h> 34 #include <signal.h> 35 #include <stdio.h> 36 #include <stdlib.h> 37 #include <strings.h> 38 #include <unistd.h> 39 #include <libscf.h> 40 #include <libscf_priv.h> 41 #include <libintl.h> 42 #include <locale.h> 43 44 #include "utils.h" 45 #include "rcapd.h" 46 #include "rcapd_conf.h" 47 #include "rcapd_stat.h" 48 49 #define CFG_TEMPLATE_SUFFIX ".XXXXXX" /* suffix of mkstemp() arg */ 50 #define RCAP_FMRI "system/rcap:default" 51 52 static void 53 usage() 54 { 55 (void) fprintf(stderr, 56 gettext("usage: rcapadm\n" 57 " [-E|-D] " 58 "# enable/disable rcapd\n" 59 " [-n] " 60 "# don't start/stop rcapd\n" 61 " [-i <scan|sample|report|config>=value] " 62 "# set intervals\n" 63 " [-c <percent>] " 64 "# set memory cap\n" 65 " " 66 "# enforcement threshold\n")); 67 exit(E_USAGE); 68 } 69 70 static rcfg_t conf; 71 static int enable = -1; 72 static int disable = -1; 73 static int pressure = -1; 74 static int no_starting_stopping = -1; 75 static int scan_interval = -1; 76 static int report_interval = -1; 77 static int config_interval = -1; 78 static int sample_interval = -1; 79 static char *fname = RCAPD_DEFAULT_CONF_FILE; 80 81 static char *subopt_v[] = { 82 "scan", 83 "sample", 84 "report", 85 "config", 86 NULL 87 }; 88 89 typedef enum { 90 OPT_SCAN = 0, 91 OPT_SAMPLE, 92 OPT_REPORT, 93 OPT_CONFIG 94 } subopt_idx_t; 95 96 static void 97 print_state(void) 98 { 99 scf_simple_prop_t *persistent_prop = NULL; 100 scf_simple_prop_t *temporary_prop = NULL; 101 uint8_t *persistent = NULL; 102 uint8_t *temporary = NULL; 103 scf_handle_t *h; 104 /* LINTED: conditionally assigned and used in function */ 105 ssize_t numvals; 106 107 if ((h = scf_handle_create(SCF_VERSION)) == NULL || 108 scf_handle_bind(h) != 0) 109 goto out; 110 111 if ((persistent_prop = scf_simple_prop_get(h, RCAP_FMRI, 112 SCF_PG_GENERAL, SCF_PROPERTY_ENABLED)) != NULL && (numvals = 113 scf_simple_prop_numvalues(persistent_prop)) > 0) 114 persistent = scf_simple_prop_next_boolean(persistent_prop); 115 116 if ((temporary_prop = scf_simple_prop_get(h, RCAP_FMRI, 117 SCF_PG_GENERAL_OVR, SCF_PROPERTY_ENABLED)) != NULL && (numvals = 118 scf_simple_prop_numvalues(temporary_prop)) > 0) 119 temporary = scf_simple_prop_next_boolean(temporary_prop); 120 121 out: 122 if (!persistent) 123 (void) printf(gettext(" " 124 "state: unknown")); 125 else if (temporary && *temporary != *persistent) 126 (void) printf(gettext(" " 127 "state: %s (%s at next boot)\n"), *temporary ? 128 gettext("enabled") : gettext("disabled"), *persistent ? 129 gettext("enabled") : gettext("disabled")); 130 else 131 (void) printf(gettext(" " 132 "state: %s\n"), *persistent ? gettext("enabled") : 133 gettext("disabled")); 134 135 scf_simple_prop_free(temporary_prop); 136 scf_simple_prop_free(persistent_prop); 137 scf_handle_destroy(h); 138 } 139 140 int 141 main(int argc, char *argv[]) 142 { 143 char *subopts, *optval, *template; 144 int modified = 0; 145 FILE *fp; 146 int fd, olderrno, opt; 147 148 (void) setprogname("rcapadm"); 149 (void) setlocale(LC_ALL, ""); 150 (void) textdomain(TEXT_DOMAIN); 151 152 while ((opt = getopt(argc, argv, "DEc:i:n")) != EOF) { 153 switch (opt) { 154 case 'n': 155 no_starting_stopping = 1; 156 break; 157 case 'c': 158 if ((pressure = xatoi(optarg)) < 0 || 159 pressure > 100 || 160 errno == EINVAL) 161 usage(); 162 modified++; 163 break; 164 case 'E': 165 enable = 1; 166 disable = 0; 167 modified++; 168 break; 169 case 'D': 170 disable = 1; 171 enable = 0; 172 modified++; 173 break; 174 case 'i': 175 subopts = optarg; 176 while (*subopts != '\0') { 177 switch (getsubopt(&subopts, subopt_v, 178 &optval)) { 179 case OPT_SCAN: 180 if (optval == NULL || 181 (scan_interval = 182 xatoi(optval)) <= 0) 183 usage(); 184 break; 185 case OPT_SAMPLE: 186 if (optval == NULL || 187 (sample_interval = 188 xatoi(optval)) <= 0) 189 usage(); 190 break; 191 case OPT_REPORT: 192 if (optval == NULL || 193 (report_interval = 194 xatoi(optval)) < 0) 195 usage(); 196 break; 197 case OPT_CONFIG: 198 if (optval == NULL || 199 (config_interval = 200 xatoi(optval)) < 0) 201 usage(); 202 break; 203 default: 204 usage(); 205 } 206 } 207 modified++; 208 break; 209 default: 210 usage(); 211 } 212 } 213 214 if (argc > optind) 215 usage(); 216 217 if (rcfg_read(fname, -1, &conf, NULL) < 0) { 218 if (!(errno == ENOENT && modified)) { 219 die(gettext("resource caps not configured\n")); 220 return (E_ERROR); 221 } 222 rcfg_init(&conf); 223 conf.rcfg_mode_name = "project"; 224 conf.rcfg_reconfiguration_interval = 60; 225 conf.rcfg_proc_walk_interval = 15; 226 conf.rcfg_report_interval = 5; 227 conf.rcfg_rss_sample_interval = 5; 228 } else { 229 /* 230 * The configuration file has been read. Warn that any lnode 231 * (or non-project) mode specification (by an SRM 232 * 1.3 configuration file, for example) is ignored. 233 */ 234 if (strcmp(conf.rcfg_mode_name, "project") != 0) { 235 warn(gettext("%s mode specification ignored -- using" 236 " project mode\n"), conf.rcfg_mode_name); 237 conf.rcfg_mode_name = "project"; 238 conf.rcfg_mode = rctype_project; 239 } 240 } 241 242 if (modified) { 243 if (pressure >= 0) 244 conf.rcfg_memory_cap_enforcement_pressure = pressure; 245 if (config_interval >= 0) 246 conf.rcfg_reconfiguration_interval = config_interval; 247 if (scan_interval >= 0) 248 conf.rcfg_proc_walk_interval = scan_interval; 249 if (report_interval >= 0) 250 conf.rcfg_report_interval = report_interval; 251 if (sample_interval >= 0) 252 conf.rcfg_rss_sample_interval = sample_interval; 253 254 if ((template = malloc(strlen(fname) + 255 strlen(CFG_TEMPLATE_SUFFIX) + 1)) == NULL) 256 die(gettext("memory allocation failure")); 257 (void) strcpy(template, fname); 258 (void) strcpy(template + strlen(template), CFG_TEMPLATE_SUFFIX); 259 if ((fd = mkstemp(template)) < 0) 260 die("%s", template); 261 if ((fp = fdopen(fd, "w")) == NULL) { 262 olderrno = errno; 263 (void) close(fd); 264 (void) unlink(template); 265 errno = olderrno; 266 die("%s", template); 267 return (E_ERROR); 268 } 269 (void) fputs("#\n# rcap.conf\n#\n" 270 "# Configuration parameters for resource capping daemon.\n" 271 "# Do NOT edit by hand -- use rcapadm(1m) instead.\n" 272 "#\n", fp); 273 (void) fprintf(fp, "RCAPD_MEMORY_CAP_ENFORCEMENT_PRESSURE " 274 "= %d\n", conf.rcfg_memory_cap_enforcement_pressure); 275 (void) fprintf(fp, "RCAPD_RECONFIGURATION_INTERVAL " 276 "= %d\n", conf.rcfg_reconfiguration_interval); 277 (void) fprintf(fp, "RCAPD_PROC_WALK_INTERVAL " 278 "= %d\n", conf.rcfg_proc_walk_interval); 279 (void) fprintf(fp, "RCAPD_REPORT_INTERVAL " 280 "= %d\n", conf.rcfg_report_interval); 281 (void) fprintf(fp, "RCAPD_RSS_SAMPLE_INTERVAL " 282 "= %d\n", conf.rcfg_rss_sample_interval); 283 if (fchmod(fd, 0644) != 0) { 284 olderrno = errno; 285 (void) close(fd); 286 (void) fclose(fp); 287 (void) unlink(template); 288 errno = olderrno; 289 die("%s", template); 290 } 291 if (rename(template, fname) != 0) { 292 olderrno = errno; 293 (void) close(fd); 294 (void) fclose(fp); 295 (void) unlink(template); 296 errno = olderrno; 297 die(gettext("cannot rename temporary file to %s"), 298 fname); 299 } 300 (void) fclose(fp); 301 (void) close(fd); 302 free(template); 303 304 if (enable > 0 && smf_enable_instance(RCAP_FMRI, 305 no_starting_stopping > 0 ? SMF_AT_NEXT_BOOT : 0) != 0) 306 die(gettext("cannot enable service: %s\n"), 307 scf_strerror(scf_error())); 308 else if (disable > 0 && smf_disable_instance(RCAP_FMRI, 309 no_starting_stopping > 0 ? SMF_AT_NEXT_BOOT : 0) != 0) 310 die(gettext("cannot disable service: %s\n"), 311 scf_strerror(scf_error())); 312 313 return (E_SUCCESS); 314 } 315 316 /* 317 * Display current configuration 318 */ 319 print_state(); 320 (void) printf(gettext(" memory cap enforcement" 321 " threshold: %d%%\n"), conf.rcfg_memory_cap_enforcement_pressure); 322 (void) printf(gettext(" process scan rate" 323 " (sec): %d\n"), conf.rcfg_proc_walk_interval); 324 (void) printf(gettext(" reconfiguration rate" 325 " (sec): %d\n"), conf.rcfg_reconfiguration_interval); 326 (void) printf(gettext(" report rate" 327 " (sec): %d\n"), conf.rcfg_report_interval); 328 (void) printf(gettext(" RSS sampling rate" 329 " (sec): %d\n"), conf.rcfg_rss_sample_interval); 330 331 return (E_SUCCESS); 332 } 333