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 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 package org.opensolaris.os.vp.panels.coreadm.client.swing; 28 29 import java.util.*; 30 import org.opensolaris.os.scf.common.*; 31 import org.opensolaris.os.vp.common.smf.ServiceMXBean; 32 import org.opensolaris.os.vp.panel.common.smf.*; 33 import org.opensolaris.os.vp.util.misc.Finder; 34 35 /** 36 * Wholly encapsulates core file configuration. Can be constructed 37 * manually or from an existing SMF configuration. 38 */ 39 public class CoreConfig { 40 41 /** 42 * Core file content types, enumerated. 43 */ 44 public enum ContentType { 45 ANON("anon"), CTF("ctf"), DATA("data"), DISM("dism"), HEAP("heap"), 46 ISM("ism"), RODATA("rodata"), SHANON("shanon"), SHFILE("shfile"), 47 SHM("shm"), STACK("stack"), SYMTAB("symtab"), TEXT("text"); 48 49 private final String literal_; 50 private ContentType(String literal) { 51 literal_ = literal; 52 } 53 54 /** 55 * Returns the string the system uses to represent the type. 56 * Should only be needed inside of CoreConfig. 57 * 58 * @return the string the system uses to represent the type 59 */ 60 private String getLiteral() 61 { 62 return (literal_); 63 } 64 65 /** 66 * Returns the natural language name of the content type. 67 * 68 * @return the natural language name of the content type. 69 */ 70 public String getName() 71 { 72 return (Finder.getString("coreadm.contents." + literal_)); 73 } 74 } 75 76 /* 77 * Ideally this would be unmodifiable, but there is no 78 * Collections.umodifiableEnumSet() and the EnumSet-specific 79 * interfaces are very useful. 80 */ 81 82 /** 83 * The default set of content types. 84 */ 85 private static final String LITERAL_DEFAULT = "default"; 86 public static final EnumSet<ContentType> CONTENT_DEFAULT = 87 EnumSet.complementOf(EnumSet.of(ContentType.SHFILE)); 88 89 private static final String LITERAL_NONE = "none"; 90 public static final EnumSet<ContentType> CONTENT_NONE = 91 EnumSet.noneOf(ContentType.class); 92 93 private static final String LITERAL_ALL = "all"; 94 public static final EnumSet<ContentType> CONTENT_ALL = 95 EnumSet.allOf(ContentType.class); 96 97 /* 98 * Constants for SMF representation. 99 */ 100 private static final String CONFIG_PG = "config_params"; 101 private static final String PROP_LOGGING = "global_log_enabled"; 102 103 private static final String PROP_SFX_CONTENT = "_content"; 104 private static final String PROP_SFX_PATTERN = "_pattern"; 105 private static final String PROP_SFX_ENABLED = "_enabled"; 106 private static final String PROP_SFX_SETID = "_setid_enabled"; 107 108 private static final String PROP_PFX_GLOBAL = "global"; 109 private static final String PROP_PFX_PROC = "process"; 110 /* Needed for content and pattern */ 111 private static final String PROP_PFX_ALTPROC = "init"; 112 113 /** 114 * Converts a literal content type into an EnumSet containing 115 * the appropriate ContentTypes. 116 * 117 * @param literal the string to convert to a ContentType 118 * @return the EnumSet of corresponding ContentTypes 119 * @throws IllegalArugmentException if literal isn't a valid 120 * content type literal 121 */ 122 private static EnumSet<ContentType> literalToSet(String literal) 123 { 124 /* 125 * This isn't the most efficient implementation, but 126 * it does the job. 127 */ 128 for (ContentType t : ContentType.values()) 129 if (t.getLiteral().equals(literal)) 130 return (EnumSet.of(t)); 131 132 if (literal.equals(LITERAL_DEFAULT)) 133 return (CONTENT_DEFAULT); 134 135 if (literal.equals(LITERAL_NONE)) 136 return (CONTENT_NONE); 137 138 if (literal.equals(LITERAL_ALL)) 139 return (CONTENT_ALL); 140 141 throw (new IllegalArgumentException(literal)); 142 } 143 144 /** 145 * Converts a Set of ContentTypes to a comma-separated list of 146 * system-recognized type names. 147 * 148 * @param s the Set of ContentTypes to convert to a String 149 * @return the comma-separated String representation of the Set 150 */ 151 private static String setToLiterals(EnumSet<ContentType> s) 152 { 153 if (s.equals(CONTENT_DEFAULT)) 154 return (LITERAL_DEFAULT); 155 156 if (s.equals(CONTENT_ALL)) 157 return (LITERAL_ALL); 158 159 if (s.equals(CONTENT_NONE)) 160 return (LITERAL_NONE); 161 162 StringBuilder sb = new StringBuilder(); 163 boolean comma = false; 164 for (ContentType t : s) { 165 if (comma) 166 sb.append("+"); 167 comma = true; 168 sb.append(t.getLiteral()); 169 } 170 return (sb.toString()); 171 } 172 173 /** 174 * Converts a list of content types in string form into a EnumSet 175 * of ContentTypes. 176 * 177 * @param lit the list of content types in string form 178 * @return an EnumSet containing the content types 179 */ 180 private static EnumSet<ContentType> literalsToSet(String lit) 181 { 182 boolean plus = true; 183 int offset = 0; 184 int max = lit.length(); 185 186 EnumSet<ContentType> result = EnumSet.noneOf(ContentType.class); 187 for (String s : lit.split("[+-]")) { 188 if (plus) 189 result.addAll(literalToSet(s)); 190 else 191 result.retainAll(EnumSet.complementOf(literalToSet(s))); 192 193 offset += s.length(); 194 if (offset < max) 195 plus = lit.charAt(offset) == '+'; 196 offset++; 197 } 198 return (result); 199 } 200 201 /** 202 * Encapsulates configuration that could apply to either 203 * the process or global scope. 204 */ 205 static public class ScopeConfig 206 { 207 private EnumSet<ContentType> content_; 208 private String pattern_; 209 private boolean enabled_; 210 private boolean setid_; 211 212 public ScopeConfig(EnumSet<ContentType> content, 213 String pattern, boolean enabled, boolean setid) 214 { 215 content_ = content; 216 pattern_ = pattern; 217 enabled_ = enabled; 218 setid_ = setid; 219 } 220 221 public ScopeConfig() 222 { 223 this(CONTENT_DEFAULT.clone(), "", false, false); 224 } 225 226 227 public ScopeConfig(ScopeConfig config) 228 { 229 this(config.content_.clone(), 230 config.pattern_, config.enabled_, config.setid_); 231 } 232 233 public ScopeConfig(ServiceMXBean service, String pfx, String altpfx) 234 throws ScfException, InvalidScfDataException, 235 MissingScfDataException 236 { 237 List<String> content = service.getSnapshotPropertyValues( 238 ScfConstants.SCF_RUNNING, CONFIG_PG, altpfx + PROP_SFX_CONTENT); 239 List<String> pattern = service.getSnapshotPropertyValues( 240 ScfConstants.SCF_RUNNING, CONFIG_PG, altpfx + PROP_SFX_PATTERN); 241 List<String> enabled = service.getSnapshotPropertyValues( 242 ScfConstants.SCF_RUNNING, CONFIG_PG, pfx + PROP_SFX_ENABLED); 243 List<String> setid = service.getSnapshotPropertyValues( 244 ScfConstants.SCF_RUNNING, CONFIG_PG, pfx + PROP_SFX_SETID); 245 246 String name = null; 247 String value = null; 248 try { 249 name = altpfx + PROP_SFX_CONTENT; 250 value = content.get(0); 251 content_ = literalsToSet(value); 252 253 name = altpfx + PROP_SFX_PATTERN; 254 pattern_ = pattern.get(0); 255 256 name = pfx + PROP_SFX_ENABLED; 257 enabled_ = Boolean.parseBoolean(enabled.get(0)); 258 259 name = pfx + PROP_SFX_SETID; 260 setid_ = Boolean.parseBoolean(setid.get(0)); 261 } catch (IndexOutOfBoundsException e) { 262 throw new MissingScfDataException(name); 263 } catch (IllegalArgumentException e) { 264 throw new InvalidScfDataException(name, value); 265 } 266 } 267 268 /* 269 * Object methods. 270 */ 271 272 @Override 273 public boolean equals(Object o) 274 { 275 if (!(o instanceof ScopeConfig)) 276 return (false); 277 ScopeConfig c = (ScopeConfig)o; 278 return (enabled_ == c.enabled_ && setid_ == c.setid_ && 279 pattern_.equals(c.pattern_) && content_.equals(c.content_)); 280 } 281 282 @Override 283 public int hashCode() 284 { 285 int hash = 7; 286 hash = 61 * hash + 287 (this.content_ != null ? this.content_.hashCode() : 0); 288 hash = 61 * hash + 289 (this.pattern_ != null ? this.pattern_.hashCode() : 0); 290 hash = 61 * hash + (this.enabled_ ? 1 : 0); 291 hash = 61 * hash + (this.setid_ ? 1 : 0); 292 return (hash); 293 } 294 295 /* 296 * ScopeConfig methods. 297 */ 298 299 void write(ServiceMXBean service, String pfx, String altpfx) 300 throws ScfException 301 { 302 service.setPropertyValues(CONFIG_PG, altpfx + PROP_SFX_CONTENT, 303 setToLiterals(content_)); 304 service.setPropertyValues(CONFIG_PG, altpfx + PROP_SFX_PATTERN, 305 pattern_); 306 service.setPropertyValues(CONFIG_PG, pfx + PROP_SFX_ENABLED, 307 Boolean.toString(enabled_)); 308 service.setPropertyValues(CONFIG_PG, pfx + PROP_SFX_SETID, 309 Boolean.toString(setid_)); 310 } 311 312 EnumSet<ContentType> getContent() 313 { 314 return (content_.clone()); 315 } 316 317 String getPattern() 318 { 319 return (pattern_); 320 } 321 322 boolean getEnabled() 323 { 324 return (enabled_); 325 } 326 327 boolean getSetid() 328 { 329 return (setid_); 330 } 331 332 void setContent(Set<ContentType> content) 333 { 334 content_.clear(); 335 content_.addAll(content); 336 } 337 338 void setPattern(String pattern) 339 { 340 pattern_ = pattern; 341 } 342 343 void setEnabled(boolean enabled) 344 { 345 enabled_ = enabled; 346 } 347 348 void setSetid(boolean setid) 349 { 350 setid_ = setid; 351 } 352 } 353 354 ScopeConfig processScope_; 355 ScopeConfig globalScope_; 356 boolean logging_; 357 358 CoreConfig(ScopeConfig global, ScopeConfig process, boolean logging) 359 { 360 globalScope_ = global; 361 processScope_ = process; 362 logging_ = logging; 363 } 364 365 CoreConfig() 366 { 367 this(new ScopeConfig(), new ScopeConfig(), false); 368 } 369 370 CoreConfig(String globalPattern, String processPattern, 371 boolean global, boolean globalSetid, 372 boolean process, boolean processSetid, 373 boolean logging) 374 { 375 this(new ScopeConfig(CONTENT_DEFAULT.clone(), 376 globalPattern, global, globalSetid), 377 new ScopeConfig(CONTENT_DEFAULT.clone(), 378 processPattern, process, processSetid), 379 logging); 380 } 381 382 /** 383 * Copy constructor. 384 * 385 * @param cc the CoreConfig object we are copying. 386 */ 387 CoreConfig(CoreConfig cc) 388 { 389 this(new ScopeConfig(cc.globalScope_), 390 new ScopeConfig(cc.processScope_), cc.logging_); 391 } 392 393 CoreConfig(ServiceMXBean service) throws ScfException, 394 InvalidScfDataException, MissingScfDataException 395 { 396 globalScope_ = 397 new ScopeConfig(service, PROP_PFX_GLOBAL, PROP_PFX_GLOBAL); 398 processScope_ = 399 new ScopeConfig(service, PROP_PFX_PROC, PROP_PFX_ALTPROC); 400 401 try { 402 List<String> logging = service.getSnapshotPropertyValues( 403 ScfConstants.SCF_RUNNING, CONFIG_PG, PROP_LOGGING); 404 logging_ = Boolean.parseBoolean(logging.get(0)); 405 } catch (IndexOutOfBoundsException e) { 406 throw new MissingScfDataException(PROP_LOGGING); 407 } 408 } 409 410 void write(ServiceMXBean service) throws ScfException 411 { 412 globalScope_.write(service, PROP_PFX_GLOBAL, PROP_PFX_GLOBAL); 413 processScope_.write(service, PROP_PFX_PROC, PROP_PFX_ALTPROC); 414 service.setPropertyValues(CONFIG_PG, PROP_LOGGING, 415 Boolean.toString(logging_)); 416 417 service.refresh(); 418 } 419 420 ScopeConfig getProcessScope() 421 { 422 return (processScope_); 423 } 424 425 ScopeConfig getGlobalScope() 426 { 427 return (globalScope_); 428 } 429 430 boolean getLogging() 431 { 432 return (logging_); 433 } 434 435 void setLogging(boolean logging) 436 { 437 logging_ = logging; 438 } 439 440 /* 441 * Object methods 442 */ 443 444 @Override 445 public boolean equals(Object o) 446 { 447 if (!(o instanceof CoreConfig)) 448 return (false); 449 CoreConfig c = (CoreConfig)o; 450 return (logging_ == c.logging_ && 451 globalScope_.equals(c.globalScope_) && 452 processScope_.equals(c.processScope_)); 453 } 454 455 @Override 456 public int hashCode() 457 { 458 int hash = 7; 459 hash = 97 * hash + 460 (this.processScope_ != null ? this.processScope_.hashCode() : 0); 461 hash = 97 * hash + 462 (this.globalScope_ != null ? this.globalScope_.hashCode() : 0); 463 hash = 97 * hash + (this.logging_ ? 1 : 0); 464 return (hash); 465 } 466 467 private String boolToEnabled(boolean b) 468 { 469 return (b ? "enabled" : "disabled"); 470 } 471 472 /** 473 * Pretty print a CoreConfig coreadm(1M)-style. 474 * 475 * @param ps the PrintStream to pretty-print to (e.g. System.out) 476 */ 477 public void dump(java.io.PrintStream ps) 478 { 479 ps.println(" global core file pattern: " + 480 globalScope_.getPattern()); 481 ps.println(" global core file content: " + 482 setToLiterals(globalScope_.getContent())); 483 ps.println(" init core file pattern: " + 484 processScope_.getPattern()); 485 ps.println(" init core file content: " + 486 setToLiterals(processScope_.getContent())); 487 ps.println(" global core dumps: " + 488 boolToEnabled(globalScope_.getEnabled())); 489 ps.println(" per-process core dumps: " + 490 boolToEnabled(processScope_.getEnabled())); 491 ps.println(" global setid core dumps: " + 492 boolToEnabled(globalScope_.getSetid())); 493 ps.println(" per-process setid core dumps: " + 494 boolToEnabled(processScope_.getSetid())); 495 ps.println(" global core dump logging: " + boolToEnabled(logging_)); 496 } 497 } 498