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 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <sys/types.h> 29 #include <sys/stat.h> 30 #include <sys/wait.h> 31 #include <fcntl.h> 32 #include <errno.h> 33 #include <signal.h> 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <strings.h> 37 #include <unistd.h> 38 #include <libscf.h> 39 #include <libscf_priv.h> 40 #include <libintl.h> 41 #include <locale.h> 42 #include <zone.h> 43 #include <libzonecfg.h> 44 45 #include "utils.h" 46 #include "rcapd.h" 47 #include "rcapd_conf.h" 48 #include "rcapd_stat.h" 49 50 static void 51 usage() 52 { 53 (void) fprintf(stderr, 54 gettext("usage: rcapadm\n" 55 " [-E|-D] " 56 "# enable/disable rcapd\n" 57 " [-n] " 58 "# don't start/stop rcapd\n" 59 " [-i <scan|sample|report|config>=value] " 60 "# set intervals\n" 61 " [-c <percent>] " 62 "# set memory cap\n" 63 " " 64 "# enforcement threshold\n" 65 " [-z <zonename> -m <max-rss>] " 66 "# update zone memory cap\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 80 static char *subopt_v[] = { 81 "scan", 82 "sample", 83 "report", 84 "config", 85 NULL 86 }; 87 88 typedef enum { 89 OPT_SCAN = 0, 90 OPT_SAMPLE, 91 OPT_REPORT, 92 OPT_CONFIG 93 } subopt_idx_t; 94 95 static void 96 print_state(void) 97 { 98 scf_simple_prop_t *persistent_prop = NULL; 99 scf_simple_prop_t *temporary_prop = NULL; 100 uint8_t *persistent = NULL; 101 uint8_t *temporary = NULL; 102 scf_handle_t *h; 103 /* LINTED: conditionally assigned and used in function */ 104 ssize_t numvals; 105 106 if ((h = scf_handle_create(SCF_VERSION)) == NULL || 107 scf_handle_bind(h) != 0) 108 goto out; 109 110 if ((persistent_prop = scf_simple_prop_get(h, RCAP_FMRI, 111 SCF_PG_GENERAL, SCF_PROPERTY_ENABLED)) != NULL && (numvals = 112 scf_simple_prop_numvalues(persistent_prop)) > 0) 113 persistent = scf_simple_prop_next_boolean(persistent_prop); 114 115 if ((temporary_prop = scf_simple_prop_get(h, RCAP_FMRI, 116 SCF_PG_GENERAL_OVR, SCF_PROPERTY_ENABLED)) != NULL && (numvals = 117 scf_simple_prop_numvalues(temporary_prop)) > 0) 118 temporary = scf_simple_prop_next_boolean(temporary_prop); 119 120 out: 121 if (!persistent) 122 (void) printf(gettext(" " 123 "state: unknown")); 124 else if (temporary && *temporary != *persistent) 125 (void) printf(gettext(" " 126 "state: %s (%s at next boot)\n"), *temporary ? 127 gettext("enabled") : gettext("disabled"), *persistent ? 128 gettext("enabled") : gettext("disabled")); 129 else 130 (void) printf(gettext(" " 131 "state: %s\n"), *persistent ? gettext("enabled") : 132 gettext("disabled")); 133 134 (void) printf(gettext(" memory cap enforcement" 135 " threshold: %d%%\n"), conf.rcfg_memory_cap_enforcement_pressure); 136 (void) printf(gettext(" process scan rate" 137 " (sec): %d\n"), conf.rcfg_proc_walk_interval); 138 (void) printf(gettext(" reconfiguration rate" 139 " (sec): %d\n"), conf.rcfg_reconfiguration_interval); 140 (void) printf(gettext(" report rate" 141 " (sec): %d\n"), conf.rcfg_report_interval); 142 (void) printf(gettext(" RSS sampling rate" 143 " (sec): %d\n"), conf.rcfg_rss_sample_interval); 144 145 scf_simple_prop_free(temporary_prop); 146 scf_simple_prop_free(persistent_prop); 147 scf_handle_destroy(h); 148 } 149 150 /* 151 * Update the in-kernel memory cap for the specified zone. 152 */ 153 static int 154 update_zone_mcap(char *zonename, char *maxrss) 155 { 156 zoneid_t zone_id; 157 uint64_t num; 158 159 if (getzoneid() != GLOBAL_ZONEID || zonecfg_in_alt_root()) 160 return (E_SUCCESS); 161 162 /* get the running zone from the kernel */ 163 if ((zone_id = getzoneidbyname(zonename)) == -1) { 164 (void) fprintf(stderr, gettext("zone '%s' must be running\n"), 165 zonename); 166 return (E_ERROR); 167 } 168 169 if (zonecfg_str_to_bytes(maxrss, &num) == -1) { 170 (void) fprintf(stderr, gettext("invalid max-rss value\n")); 171 return (E_ERROR); 172 } 173 174 if (zone_setattr(zone_id, ZONE_ATTR_PHYS_MCAP, &num, 0) == -1) { 175 (void) fprintf(stderr, gettext("could not set memory " 176 "cap for zone '%s'\n"), zonename); 177 return (E_ERROR); 178 } 179 180 return (E_SUCCESS); 181 } 182 183 int 184 main(int argc, char *argv[]) 185 { 186 char *subopts, *optval; 187 int modified = 0; 188 boolean_t refresh = B_FALSE; 189 int opt; 190 char *zonename; 191 char *maxrss = NULL; 192 193 (void) setprogname("rcapadm"); 194 (void) setlocale(LC_ALL, ""); 195 (void) textdomain(TEXT_DOMAIN); 196 197 while ((opt = getopt(argc, argv, "DEc:i:m:nz:")) != EOF) { 198 switch (opt) { 199 case 'n': 200 no_starting_stopping = 1; 201 break; 202 case 'c': 203 if ((pressure = xatoi(optarg)) < 0 || 204 pressure > 100 || 205 errno == EINVAL) 206 usage(); 207 modified++; 208 break; 209 case 'E': 210 enable = 1; 211 disable = 0; 212 break; 213 case 'D': 214 disable = 1; 215 enable = 0; 216 break; 217 case 'i': 218 subopts = optarg; 219 while (*subopts != '\0') { 220 switch (getsubopt(&subopts, subopt_v, 221 &optval)) { 222 case OPT_SCAN: 223 if (optval == NULL || 224 (scan_interval = 225 xatoi(optval)) <= 0) 226 usage(); 227 break; 228 case OPT_SAMPLE: 229 if (optval == NULL || 230 (sample_interval = 231 xatoi(optval)) <= 0) 232 usage(); 233 break; 234 case OPT_REPORT: 235 if (optval == NULL || 236 (report_interval = 237 xatoi(optval)) < 0) 238 usage(); 239 break; 240 case OPT_CONFIG: 241 if (optval == NULL || 242 (config_interval = 243 xatoi(optval)) < 0) 244 usage(); 245 break; 246 default: 247 usage(); 248 } 249 } 250 modified++; 251 break; 252 case 'm': 253 maxrss = optarg; 254 break; 255 case 'z': 256 refresh = B_TRUE; 257 zonename = optarg; 258 break; 259 default: 260 usage(); 261 } 262 } 263 264 /* the -z & -m options must be used together */ 265 if (argc > optind || (refresh && maxrss == NULL) || 266 (!refresh && maxrss != NULL)) 267 usage(); 268 269 if (refresh && (no_starting_stopping > 0 || modified)) 270 usage(); 271 272 /* 273 * disable/enable before reading configuration from the repository 274 * which may fail and prevents the disabling/enabling to complete. 275 */ 276 if (disable > 0) { 277 if (smf_disable_instance(RCAP_FMRI, no_starting_stopping > 0 278 ? SMF_AT_NEXT_BOOT : 0) != 0) 279 die(gettext("cannot disable service: %s\n"), 280 scf_strerror(scf_error())); 281 } 282 283 if (enable > 0) { 284 if (smf_enable_instance(RCAP_FMRI, no_starting_stopping > 0 285 ? SMF_AT_NEXT_BOOT : 0) != 0) 286 die(gettext("cannot enable service: %s\n"), 287 scf_strerror(scf_error())); 288 } 289 290 if (rcfg_read(&conf, NULL) != E_SUCCESS) { 291 /* 292 * If instance is enabled, put it in maintenance since we 293 * failed to read configuration from the repository or 294 * create statistics file. 295 */ 296 if (strcmp(smf_get_state(RCAP_FMRI), 297 SCF_STATE_STRING_DISABLED) != 0) 298 (void) smf_maintain_instance(RCAP_FMRI, 0); 299 300 die(gettext("resource caps not configured\n")); 301 } else { 302 /* Done reading configuration */ 303 if (strcmp(conf.rcfg_mode_name, "project") != 0) { 304 warn(gettext("%s mode specification ignored -- using" 305 " project mode\n"), conf.rcfg_mode_name); 306 conf.rcfg_mode_name = "project"; 307 conf.rcfg_mode = rctype_project; 308 } 309 } 310 311 if (refresh) 312 return (update_zone_mcap(zonename, maxrss)); 313 314 if (modified) { 315 if (pressure >= 0) 316 conf.rcfg_memory_cap_enforcement_pressure = pressure; 317 if (config_interval >= 0) 318 conf.rcfg_reconfiguration_interval = config_interval; 319 if (scan_interval >= 0) 320 conf.rcfg_proc_walk_interval = scan_interval; 321 if (report_interval >= 0) 322 conf.rcfg_report_interval = report_interval; 323 if (sample_interval >= 0) 324 conf.rcfg_rss_sample_interval = sample_interval; 325 326 /* 327 * Modify configuration with the new parameter(s). The 328 * function will exit if it fails. 329 */ 330 if ((modify_config(&conf)) != 0) 331 die(gettext("Error updating repository \n")); 332 333 if (smf_refresh_instance(RCAP_FMRI) != 0) 334 die(gettext("cannot refresh service: %s\n"), 335 scf_strerror(scf_error())); 336 } 337 338 /* 339 * Display current configuration 340 */ 341 print_state(); 342 return (E_SUCCESS); 343 } 344