1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate /* 30*0Sstevel@tonic-gate * "pmconfig" performs a mixture of Energy-Star configuration tasks 31*0Sstevel@tonic-gate * for both CheckPoint-Resume and Power-Management services. 32*0Sstevel@tonic-gate * Tasks include parsing a config file (usually "/etc/power.conf"), 33*0Sstevel@tonic-gate * updating CPR and PM config files, and setting various PM options 34*0Sstevel@tonic-gate * via ioctl requests. From the mix, pmconfig should have a more 35*0Sstevel@tonic-gate * generalized name similar to "estarconfig". 36*0Sstevel@tonic-gate * 37*0Sstevel@tonic-gate * OPTIONS: 38*0Sstevel@tonic-gate * "-r" reset CPR and PM options to default and exit. 39*0Sstevel@tonic-gate * "-f file" specify an alternate config file; this is a 40*0Sstevel@tonic-gate * private/non-advertised option used by "dtpower". 41*0Sstevel@tonic-gate */ 42*0Sstevel@tonic-gate 43*0Sstevel@tonic-gate #include "pmconfig.h" 44*0Sstevel@tonic-gate #include <sys/wait.h> 45*0Sstevel@tonic-gate #include <signal.h> 46*0Sstevel@tonic-gate #include <stdarg.h> 47*0Sstevel@tonic-gate #include <locale.h> 48*0Sstevel@tonic-gate #include "powerd.h" 49*0Sstevel@tonic-gate 50*0Sstevel@tonic-gate 51*0Sstevel@tonic-gate #define MCCPY_FIELD(dst, src, field) \ 52*0Sstevel@tonic-gate (void) memccpy(&dst.field, &src.field, 0, sizeof (dst.field) - 1) 53*0Sstevel@tonic-gate 54*0Sstevel@tonic-gate 55*0Sstevel@tonic-gate static char conf_header[] = 56*0Sstevel@tonic-gate "#\n" 57*0Sstevel@tonic-gate "# Copyright 1996-2002 Sun Microsystems, Inc. All rights reserved.\n" 58*0Sstevel@tonic-gate "# Use is subject to license terms.\n" 59*0Sstevel@tonic-gate "#\n" 60*0Sstevel@tonic-gate "#pragma ident \"@(#)power.conf 2.1 02/03/04 SMI\"\n" 61*0Sstevel@tonic-gate "#\n" 62*0Sstevel@tonic-gate "# Power Management Configuration File\n" 63*0Sstevel@tonic-gate "#\n\n"; 64*0Sstevel@tonic-gate 65*0Sstevel@tonic-gate static char *prog; 66*0Sstevel@tonic-gate static char *cpr_conf = CPR_CONFIG; 67*0Sstevel@tonic-gate static char tmp_conf[] = "/etc/.tmp.conf.XXXXXX"; 68*0Sstevel@tonic-gate static char orig_conf[] = "/etc/power.conf-Orig"; 69*0Sstevel@tonic-gate static char default_conf[] = "/etc/power.conf"; 70*0Sstevel@tonic-gate static char *power_conf = default_conf; 71*0Sstevel@tonic-gate static pid_t powerd_pid; 72*0Sstevel@tonic-gate static prmup_t *checkup; 73*0Sstevel@tonic-gate static int tmp_fd; 74*0Sstevel@tonic-gate 75*0Sstevel@tonic-gate char estar_vers = ESTAR_VNONE; 76*0Sstevel@tonic-gate int ua_err = 0; 77*0Sstevel@tonic-gate int debug = 0; 78*0Sstevel@tonic-gate 79*0Sstevel@tonic-gate static struct cprconfig disk_cc; 80*0Sstevel@tonic-gate struct cprconfig new_cc; 81*0Sstevel@tonic-gate struct stat def_info; 82*0Sstevel@tonic-gate static int fflag, rflag; 83*0Sstevel@tonic-gate int pm_fd; 84*0Sstevel@tonic-gate uid_t ruid; 85*0Sstevel@tonic-gate int def_src; 86*0Sstevel@tonic-gate 87*0Sstevel@tonic-gate 88*0Sstevel@tonic-gate static void 89*0Sstevel@tonic-gate cleanup(void) 90*0Sstevel@tonic-gate { 91*0Sstevel@tonic-gate free(line_args); 92*0Sstevel@tonic-gate if (access(tmp_conf, F_OK) == 0) 93*0Sstevel@tonic-gate (void) unlink(tmp_conf); 94*0Sstevel@tonic-gate } 95*0Sstevel@tonic-gate 96*0Sstevel@tonic-gate 97*0Sstevel@tonic-gate /* 98*0Sstevel@tonic-gate * Multi-purpose message output routine; also exits when 99*0Sstevel@tonic-gate * (status == MEXIT), other status is non-fatal. 100*0Sstevel@tonic-gate * VARARGS2 101*0Sstevel@tonic-gate */ 102*0Sstevel@tonic-gate void 103*0Sstevel@tonic-gate mesg(int code, char *fmt, ...) 104*0Sstevel@tonic-gate { 105*0Sstevel@tonic-gate va_list vargs; 106*0Sstevel@tonic-gate 107*0Sstevel@tonic-gate /* 108*0Sstevel@tonic-gate * debug is checked once here, avoiding N duplicate checks 109*0Sstevel@tonic-gate * before each MDEBUG caller and unnecessary text dupduplication. 110*0Sstevel@tonic-gate */ 111*0Sstevel@tonic-gate if (debug == 0) { 112*0Sstevel@tonic-gate /* 113*0Sstevel@tonic-gate * If debug is not enabled, skip a debug message; 114*0Sstevel@tonic-gate * lead with the program name for an error message, 115*0Sstevel@tonic-gate * and follow with a filename and line number if an 116*0Sstevel@tonic-gate * error occurs while parsing a conf file. 117*0Sstevel@tonic-gate */ 118*0Sstevel@tonic-gate if (code == MDEBUG) 119*0Sstevel@tonic-gate return; 120*0Sstevel@tonic-gate fprintf(stderr, "%s: ", prog); 121*0Sstevel@tonic-gate if (lineno) 122*0Sstevel@tonic-gate fprintf(stderr, "\"%s\" line %d, ", power_conf, lineno); 123*0Sstevel@tonic-gate } 124*0Sstevel@tonic-gate 125*0Sstevel@tonic-gate va_start(vargs, fmt); 126*0Sstevel@tonic-gate (void) vfprintf(stderr, gettext(fmt), vargs); 127*0Sstevel@tonic-gate va_end(vargs); 128*0Sstevel@tonic-gate 129*0Sstevel@tonic-gate if (code == MEXIT) { 130*0Sstevel@tonic-gate cleanup(); 131*0Sstevel@tonic-gate exit(MEXIT); 132*0Sstevel@tonic-gate } 133*0Sstevel@tonic-gate } 134*0Sstevel@tonic-gate 135*0Sstevel@tonic-gate 136*0Sstevel@tonic-gate static void 137*0Sstevel@tonic-gate usage(void) 138*0Sstevel@tonic-gate { 139*0Sstevel@tonic-gate (void) fprintf(stderr, "Usage: %s [-r]\n", prog); 140*0Sstevel@tonic-gate exit(1); 141*0Sstevel@tonic-gate } 142*0Sstevel@tonic-gate 143*0Sstevel@tonic-gate 144*0Sstevel@tonic-gate /* 145*0Sstevel@tonic-gate * Lookup estar version, check if uadmin() service is supported, 146*0Sstevel@tonic-gate * and read cpr_config info from disk. 147*0Sstevel@tonic-gate */ 148*0Sstevel@tonic-gate static void 149*0Sstevel@tonic-gate get_cpr_info(void) 150*0Sstevel@tonic-gate { 151*0Sstevel@tonic-gate ssize_t nread; 152*0Sstevel@tonic-gate char *err_fmt; 153*0Sstevel@tonic-gate int fd; 154*0Sstevel@tonic-gate 155*0Sstevel@tonic-gate #ifdef sparc 156*0Sstevel@tonic-gate lookup_estar_vers(); 157*0Sstevel@tonic-gate if (estar_vers == ESTAR_V2) 158*0Sstevel@tonic-gate new_cc.is_cpr_default = 1; 159*0Sstevel@tonic-gate else if (estar_vers == ESTAR_V3) 160*0Sstevel@tonic-gate new_cc.is_autopm_default = 1; 161*0Sstevel@tonic-gate 162*0Sstevel@tonic-gate if (uadmin(A_FREEZE, AD_CHECK, 0) == 0) 163*0Sstevel@tonic-gate new_cc.is_cpr_capable = 1; 164*0Sstevel@tonic-gate else 165*0Sstevel@tonic-gate ua_err = errno; 166*0Sstevel@tonic-gate 167*0Sstevel@tonic-gate if ((fd = open("/dev/tod", O_RDONLY)) != -1) { 168*0Sstevel@tonic-gate new_cc.is_autowakeup_capable = 1; 169*0Sstevel@tonic-gate (void) close(fd); 170*0Sstevel@tonic-gate } 171*0Sstevel@tonic-gate #endif /* sparc */ 172*0Sstevel@tonic-gate 173*0Sstevel@tonic-gate /* 174*0Sstevel@tonic-gate * Read in the cpr conf file. If any open or read error occurs, 175*0Sstevel@tonic-gate * display an error message only for a non-root user. The file 176*0Sstevel@tonic-gate * may not exist on a newly installed system. 177*0Sstevel@tonic-gate */ 178*0Sstevel@tonic-gate err_fmt = "%s %s; please rerun %s as root\n"; 179*0Sstevel@tonic-gate if ((fd = open(cpr_conf, O_RDONLY)) == -1) { 180*0Sstevel@tonic-gate if (ruid) 181*0Sstevel@tonic-gate mesg(MEXIT, err_fmt, gettext("cannot open"), 182*0Sstevel@tonic-gate cpr_conf, prog); 183*0Sstevel@tonic-gate } else { 184*0Sstevel@tonic-gate nread = read(fd, &disk_cc, sizeof (disk_cc)); 185*0Sstevel@tonic-gate (void) close(fd); 186*0Sstevel@tonic-gate if (nread != (ssize_t)sizeof (disk_cc)) { 187*0Sstevel@tonic-gate if (ruid) 188*0Sstevel@tonic-gate mesg(MEXIT, err_fmt, cpr_conf, 189*0Sstevel@tonic-gate gettext("file corrupted"), prog); 190*0Sstevel@tonic-gate else { 191*0Sstevel@tonic-gate (void) unlink(cpr_conf); 192*0Sstevel@tonic-gate bzero(&disk_cc, sizeof (disk_cc)); 193*0Sstevel@tonic-gate } 194*0Sstevel@tonic-gate } 195*0Sstevel@tonic-gate } 196*0Sstevel@tonic-gate } 197*0Sstevel@tonic-gate 198*0Sstevel@tonic-gate 199*0Sstevel@tonic-gate /* 200*0Sstevel@tonic-gate * Unconfigure and reset PM, device is left open for later use. 201*0Sstevel@tonic-gate */ 202*0Sstevel@tonic-gate static void 203*0Sstevel@tonic-gate pm_rem_reset(void) 204*0Sstevel@tonic-gate { 205*0Sstevel@tonic-gate char *err_fmt = NULL; 206*0Sstevel@tonic-gate 207*0Sstevel@tonic-gate if ((pm_fd = open("/dev/pm", O_RDWR)) == -1) 208*0Sstevel@tonic-gate err_fmt = "cannot open \"/dev/pm\": %s\n"; 209*0Sstevel@tonic-gate else if (ioctl(pm_fd, PM_RESET_PM, 0) == -1) 210*0Sstevel@tonic-gate err_fmt = "cannot reset pm state: %s\n"; 211*0Sstevel@tonic-gate if (err_fmt) 212*0Sstevel@tonic-gate mesg(MEXIT, err_fmt, strerror(errno)); 213*0Sstevel@tonic-gate } 214*0Sstevel@tonic-gate 215*0Sstevel@tonic-gate 216*0Sstevel@tonic-gate static void 217*0Sstevel@tonic-gate get_powerd_pid(void) 218*0Sstevel@tonic-gate { 219*0Sstevel@tonic-gate char pidstr[16]; 220*0Sstevel@tonic-gate int fd; 221*0Sstevel@tonic-gate 222*0Sstevel@tonic-gate if ((fd = open(PIDPATH, O_RDONLY)) == -1) 223*0Sstevel@tonic-gate return; 224*0Sstevel@tonic-gate bzero(pidstr, sizeof (pidstr)); 225*0Sstevel@tonic-gate if (read(fd, pidstr, sizeof (pidstr)) > 0) { 226*0Sstevel@tonic-gate powerd_pid = atoi(pidstr); 227*0Sstevel@tonic-gate mesg(MDEBUG, "got powerd pid %ld\n", powerd_pid); 228*0Sstevel@tonic-gate } 229*0Sstevel@tonic-gate (void) close(fd); 230*0Sstevel@tonic-gate } 231*0Sstevel@tonic-gate 232*0Sstevel@tonic-gate 233*0Sstevel@tonic-gate /* 234*0Sstevel@tonic-gate * Write revised cprconfig struct to disk based on perms; 235*0Sstevel@tonic-gate * returns 1 if any error, otherwise 0. 236*0Sstevel@tonic-gate */ 237*0Sstevel@tonic-gate static int 238*0Sstevel@tonic-gate update_cprconfig(void) 239*0Sstevel@tonic-gate { 240*0Sstevel@tonic-gate struct cprconfig *wrt_cc = &new_cc; 241*0Sstevel@tonic-gate char *err_fmt = NULL; 242*0Sstevel@tonic-gate int fd; 243*0Sstevel@tonic-gate 244*0Sstevel@tonic-gate if (rflag) { 245*0Sstevel@tonic-gate /* For "pmconfig -r" case, copy select cpr-related fields. */ 246*0Sstevel@tonic-gate new_cc.cf_magic = disk_cc.cf_magic; 247*0Sstevel@tonic-gate new_cc.cf_type = disk_cc.cf_type; 248*0Sstevel@tonic-gate MCCPY_FIELD(new_cc, disk_cc, cf_path); 249*0Sstevel@tonic-gate MCCPY_FIELD(new_cc, disk_cc, cf_fs); 250*0Sstevel@tonic-gate MCCPY_FIELD(new_cc, disk_cc, cf_devfs); 251*0Sstevel@tonic-gate MCCPY_FIELD(new_cc, disk_cc, cf_dev_prom); 252*0Sstevel@tonic-gate } 253*0Sstevel@tonic-gate 254*0Sstevel@tonic-gate if (!pm_status.perm) { 255*0Sstevel@tonic-gate if (cpr_status.update == NOUP) 256*0Sstevel@tonic-gate return (1); 257*0Sstevel@tonic-gate /* save new struct data with old autopm setting */ 258*0Sstevel@tonic-gate MCCPY_FIELD(new_cc, disk_cc, apm_behavior); 259*0Sstevel@tonic-gate } else if (!cpr_status.perm) { 260*0Sstevel@tonic-gate if (pm_status.update == NOUP) 261*0Sstevel@tonic-gate return (1); 262*0Sstevel@tonic-gate /* save original struct with new autopm setting */ 263*0Sstevel@tonic-gate MCCPY_FIELD(disk_cc, new_cc, apm_behavior); 264*0Sstevel@tonic-gate wrt_cc = &disk_cc; 265*0Sstevel@tonic-gate } else if (cpr_status.update == NOUP || pm_status.update == NOUP) 266*0Sstevel@tonic-gate return (1); 267*0Sstevel@tonic-gate 268*0Sstevel@tonic-gate if ((fd = open(cpr_conf, O_CREAT | O_TRUNC | O_WRONLY, 0644)) == -1) 269*0Sstevel@tonic-gate err_fmt = "cannot open/create \"%s\", %s\n"; 270*0Sstevel@tonic-gate else if (write(fd, wrt_cc, sizeof (*wrt_cc)) != sizeof (*wrt_cc)) 271*0Sstevel@tonic-gate err_fmt = "error writing \"%s\", %s\n"; 272*0Sstevel@tonic-gate (void) close(fd); 273*0Sstevel@tonic-gate if (err_fmt) 274*0Sstevel@tonic-gate mesg(MERR, err_fmt, cpr_conf, strerror(errno)); 275*0Sstevel@tonic-gate return (err_fmt != NULL); 276*0Sstevel@tonic-gate } 277*0Sstevel@tonic-gate 278*0Sstevel@tonic-gate 279*0Sstevel@tonic-gate /* 280*0Sstevel@tonic-gate * Signal old powerd when there's a valid pid, or start a new one; 281*0Sstevel@tonic-gate * returns 1 if any error, otherwise 0. 282*0Sstevel@tonic-gate */ 283*0Sstevel@tonic-gate static int 284*0Sstevel@tonic-gate restart_powerd(void) 285*0Sstevel@tonic-gate { 286*0Sstevel@tonic-gate char *powerd = "/usr/lib/power/powerd"; 287*0Sstevel@tonic-gate int status = 0; 288*0Sstevel@tonic-gate pid_t pid, wp; 289*0Sstevel@tonic-gate 290*0Sstevel@tonic-gate if (powerd_pid > 0) { 291*0Sstevel@tonic-gate if (sigsend(P_PID, powerd_pid, SIGHUP) == 0) 292*0Sstevel@tonic-gate return (0); 293*0Sstevel@tonic-gate else if (errno != ESRCH) { 294*0Sstevel@tonic-gate mesg(MERR, "cannot deliver hangup to powerd\n"); 295*0Sstevel@tonic-gate return (1); 296*0Sstevel@tonic-gate } 297*0Sstevel@tonic-gate } 298*0Sstevel@tonic-gate 299*0Sstevel@tonic-gate if ((pid = fork()) == NOPID) 300*0Sstevel@tonic-gate wp = -1; 301*0Sstevel@tonic-gate else if (pid == P_MYPID) { 302*0Sstevel@tonic-gate (void) setreuid(0, 0); 303*0Sstevel@tonic-gate (void) setregid(0, 0); 304*0Sstevel@tonic-gate (void) setgroups(0, NULL); 305*0Sstevel@tonic-gate (void) execle(powerd, powerd, NULL, NULL); 306*0Sstevel@tonic-gate exit(1); 307*0Sstevel@tonic-gate } else { 308*0Sstevel@tonic-gate do { 309*0Sstevel@tonic-gate wp = waitpid(pid, &status, 0); 310*0Sstevel@tonic-gate } while (wp == -1 && errno == EINTR); 311*0Sstevel@tonic-gate } 312*0Sstevel@tonic-gate 313*0Sstevel@tonic-gate if (wp == -1) 314*0Sstevel@tonic-gate mesg(MERR, "could not start %s\n", powerd); 315*0Sstevel@tonic-gate return (wp == -1 || status != 0); 316*0Sstevel@tonic-gate } 317*0Sstevel@tonic-gate 318*0Sstevel@tonic-gate 319*0Sstevel@tonic-gate static void 320*0Sstevel@tonic-gate save_orig(void) 321*0Sstevel@tonic-gate { 322*0Sstevel@tonic-gate static char *args[] = { "/usr/bin/cp", default_conf, orig_conf, NULL }; 323*0Sstevel@tonic-gate struct stat stbuf; 324*0Sstevel@tonic-gate int pid; 325*0Sstevel@tonic-gate 326*0Sstevel@tonic-gate if (stat(orig_conf, &stbuf) == 0 && stbuf.st_size) 327*0Sstevel@tonic-gate return; 328*0Sstevel@tonic-gate pid = fork(); 329*0Sstevel@tonic-gate if (pid == NOPID) 330*0Sstevel@tonic-gate return; 331*0Sstevel@tonic-gate else if (pid == P_MYPID) { 332*0Sstevel@tonic-gate (void) execve(args[0], args, NULL); 333*0Sstevel@tonic-gate exit(1); 334*0Sstevel@tonic-gate } else 335*0Sstevel@tonic-gate (void) waitpid(pid, NULL, 0); 336*0Sstevel@tonic-gate } 337*0Sstevel@tonic-gate 338*0Sstevel@tonic-gate 339*0Sstevel@tonic-gate static void 340*0Sstevel@tonic-gate tmp_write(void *buf, size_t len) 341*0Sstevel@tonic-gate { 342*0Sstevel@tonic-gate if (write(tmp_fd, buf, len) != (ssize_t)len) 343*0Sstevel@tonic-gate mesg(MEXIT, "error writing tmp file, %s\n", strerror(errno)); 344*0Sstevel@tonic-gate } 345*0Sstevel@tonic-gate 346*0Sstevel@tonic-gate 347*0Sstevel@tonic-gate static void 348*0Sstevel@tonic-gate tmp_save_line(char *line, size_t len, cinfo_t *cip) 349*0Sstevel@tonic-gate { 350*0Sstevel@tonic-gate if (cip && cip->cmt) 351*0Sstevel@tonic-gate tmp_write(cip->cmt, strlen(cip->cmt)); 352*0Sstevel@tonic-gate tmp_write(line, len); 353*0Sstevel@tonic-gate } 354*0Sstevel@tonic-gate 355*0Sstevel@tonic-gate 356*0Sstevel@tonic-gate /* 357*0Sstevel@tonic-gate * Filter conf lines and write them to the tmp file. 358*0Sstevel@tonic-gate */ 359*0Sstevel@tonic-gate static void 360*0Sstevel@tonic-gate filter(char *line, size_t len, cinfo_t *cip) 361*0Sstevel@tonic-gate { 362*0Sstevel@tonic-gate int selected; 363*0Sstevel@tonic-gate 364*0Sstevel@tonic-gate /* 365*0Sstevel@tonic-gate * Lines from an alt conf file are selected when either: 366*0Sstevel@tonic-gate * cip is NULL (keyword not matched, probably an old-style device), 367*0Sstevel@tonic-gate * OR: it's both OK to accept the conf line (alt) AND either: 368*0Sstevel@tonic-gate * preference is not set (NULL checkup) OR the cpr/pm preference 369*0Sstevel@tonic-gate * (checkup) matches conftab status. 370*0Sstevel@tonic-gate */ 371*0Sstevel@tonic-gate selected = (cip == NULL || (cip->alt && 372*0Sstevel@tonic-gate (checkup == NULL || checkup == cip->status))); 373*0Sstevel@tonic-gate mesg(MDEBUG, "filter: set \"%s\", selected %d\n", 374*0Sstevel@tonic-gate cip ? cip->status->set : "none", selected); 375*0Sstevel@tonic-gate if (selected) 376*0Sstevel@tonic-gate tmp_save_line(line, len, cip); 377*0Sstevel@tonic-gate } 378*0Sstevel@tonic-gate 379*0Sstevel@tonic-gate 380*0Sstevel@tonic-gate /* 381*0Sstevel@tonic-gate * Set checkup for conf line selection and parse a conf file with filtering. 382*0Sstevel@tonic-gate * When pref is NULL, filter selects all conf lines from the new conf file; 383*0Sstevel@tonic-gate * otherwise filter selects only cpr or pm related lines from the new or 384*0Sstevel@tonic-gate * default conf file based on cpr or pm perm. 385*0Sstevel@tonic-gate */ 386*0Sstevel@tonic-gate static void 387*0Sstevel@tonic-gate conf_scanner(prmup_t *pref) 388*0Sstevel@tonic-gate { 389*0Sstevel@tonic-gate mesg(MDEBUG, "\nscanning set is %s\n", pref ? pref->set : "both"); 390*0Sstevel@tonic-gate checkup = pref; 391*0Sstevel@tonic-gate parse_conf_file((pref == NULL || pref->perm) 392*0Sstevel@tonic-gate ? power_conf : default_conf, filter); 393*0Sstevel@tonic-gate } 394*0Sstevel@tonic-gate 395*0Sstevel@tonic-gate 396*0Sstevel@tonic-gate /* 397*0Sstevel@tonic-gate * Search for any non-alt entries, call the handler routine, 398*0Sstevel@tonic-gate * and write entries to the tmp file. 399*0Sstevel@tonic-gate */ 400*0Sstevel@tonic-gate static void 401*0Sstevel@tonic-gate search(char *line, size_t len, cinfo_t *cip) 402*0Sstevel@tonic-gate { 403*0Sstevel@tonic-gate int skip; 404*0Sstevel@tonic-gate 405*0Sstevel@tonic-gate skip = (cip == NULL || cip->alt); 406*0Sstevel@tonic-gate mesg(MDEBUG, "search: %s\n", skip ? "skipped" : "retained"); 407*0Sstevel@tonic-gate if (skip) 408*0Sstevel@tonic-gate return; 409*0Sstevel@tonic-gate if (cip->status->perm) 410*0Sstevel@tonic-gate (void) (*cip->handler)(); 411*0Sstevel@tonic-gate tmp_save_line(line, len, cip); 412*0Sstevel@tonic-gate } 413*0Sstevel@tonic-gate 414*0Sstevel@tonic-gate 415*0Sstevel@tonic-gate /* 416*0Sstevel@tonic-gate * When perm and update status are OK, write a new conf file 417*0Sstevel@tonic-gate * and rename to default_conf with the original attributes; 418*0Sstevel@tonic-gate * returns 1 if any error, otherwise 0. 419*0Sstevel@tonic-gate */ 420*0Sstevel@tonic-gate static int 421*0Sstevel@tonic-gate write_conf(void) 422*0Sstevel@tonic-gate { 423*0Sstevel@tonic-gate char *name, *err_str = NULL; 424*0Sstevel@tonic-gate struct stat stbuf; 425*0Sstevel@tonic-gate 426*0Sstevel@tonic-gate if ((cpr_status.perm && cpr_status.update != OKUP) || 427*0Sstevel@tonic-gate (pm_status.perm && pm_status.update != OKUP)) { 428*0Sstevel@tonic-gate mesg(MDEBUG, "\nconf not written, " 429*0Sstevel@tonic-gate "(cpr perm %d update %d), (pm perm %d update %d)\n", 430*0Sstevel@tonic-gate cpr_status.perm, cpr_status.update, 431*0Sstevel@tonic-gate pm_status.perm, pm_status.update); 432*0Sstevel@tonic-gate return (1); 433*0Sstevel@tonic-gate } 434*0Sstevel@tonic-gate 435*0Sstevel@tonic-gate save_orig(); 436*0Sstevel@tonic-gate if ((tmp_fd = mkstemp(tmp_conf)) == -1) { 437*0Sstevel@tonic-gate mesg(MERR, "cannot open/create tmp file \"%s\"\n", tmp_conf); 438*0Sstevel@tonic-gate return (1); 439*0Sstevel@tonic-gate } 440*0Sstevel@tonic-gate tmp_write(conf_header, sizeof (conf_header) - 1); 441*0Sstevel@tonic-gate 442*0Sstevel@tonic-gate /* 443*0Sstevel@tonic-gate * When both perms are set, save selected lines from the new file; 444*0Sstevel@tonic-gate * otherwise save selected subsets from the new and default files. 445*0Sstevel@tonic-gate */ 446*0Sstevel@tonic-gate if (cpr_status.perm && pm_status.perm) 447*0Sstevel@tonic-gate conf_scanner(NULL); 448*0Sstevel@tonic-gate else { 449*0Sstevel@tonic-gate conf_scanner(&cpr_status); 450*0Sstevel@tonic-gate conf_scanner(&pm_status); 451*0Sstevel@tonic-gate } 452*0Sstevel@tonic-gate 453*0Sstevel@tonic-gate /* 454*0Sstevel@tonic-gate * "dtpower" will craft an alt conf file with modified content from 455*0Sstevel@tonic-gate * /etc/power.conf, but any alt conf file is not a trusted source; 456*0Sstevel@tonic-gate * since some alt conf lines may be skipped, the trusted source is 457*0Sstevel@tonic-gate * searched for those lines to retain their functionality. 458*0Sstevel@tonic-gate */ 459*0Sstevel@tonic-gate parse_conf_file(default_conf, search); 460*0Sstevel@tonic-gate 461*0Sstevel@tonic-gate (void) close(tmp_fd); 462*0Sstevel@tonic-gate 463*0Sstevel@tonic-gate if (stat(name = default_conf, &stbuf) == -1) 464*0Sstevel@tonic-gate err_str = "stat"; 465*0Sstevel@tonic-gate else if (chmod(name = tmp_conf, stbuf.st_mode) == -1) 466*0Sstevel@tonic-gate err_str = "chmod"; 467*0Sstevel@tonic-gate else if (chown(tmp_conf, stbuf.st_uid, stbuf.st_gid) == -1) 468*0Sstevel@tonic-gate err_str = "chown"; 469*0Sstevel@tonic-gate else if (rename(tmp_conf, default_conf) == -1) 470*0Sstevel@tonic-gate err_str = "rename"; 471*0Sstevel@tonic-gate else 472*0Sstevel@tonic-gate mesg(MDEBUG, "\n\"%s\" renamed to \"%s\"\n", 473*0Sstevel@tonic-gate tmp_conf, default_conf); 474*0Sstevel@tonic-gate if (err_str) 475*0Sstevel@tonic-gate mesg(MERR, "cannot %s \"%s\", %s\n", 476*0Sstevel@tonic-gate err_str, name, strerror(errno)); 477*0Sstevel@tonic-gate 478*0Sstevel@tonic-gate return (err_str != NULL); 479*0Sstevel@tonic-gate } 480*0Sstevel@tonic-gate 481*0Sstevel@tonic-gate 482*0Sstevel@tonic-gate /* ARGSUSED */ 483*0Sstevel@tonic-gate int 484*0Sstevel@tonic-gate main(int cnt, char **vec) 485*0Sstevel@tonic-gate { 486*0Sstevel@tonic-gate int rval = 0; 487*0Sstevel@tonic-gate 488*0Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 489*0Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 490*0Sstevel@tonic-gate 491*0Sstevel@tonic-gate for (prog = *vec++; *vec && **vec == '-'; vec++) { 492*0Sstevel@tonic-gate if (strlen(*vec) > 2) 493*0Sstevel@tonic-gate usage(); 494*0Sstevel@tonic-gate switch (*(*vec + 1)) { 495*0Sstevel@tonic-gate case 'd': 496*0Sstevel@tonic-gate debug = 1; 497*0Sstevel@tonic-gate break; 498*0Sstevel@tonic-gate case 'f': 499*0Sstevel@tonic-gate fflag = 1; 500*0Sstevel@tonic-gate if ((power_conf = *++vec) == NULL) 501*0Sstevel@tonic-gate usage(); 502*0Sstevel@tonic-gate break; 503*0Sstevel@tonic-gate case 'r': 504*0Sstevel@tonic-gate rflag = 1; 505*0Sstevel@tonic-gate break; 506*0Sstevel@tonic-gate default: 507*0Sstevel@tonic-gate usage(); 508*0Sstevel@tonic-gate break; 509*0Sstevel@tonic-gate } 510*0Sstevel@tonic-gate } 511*0Sstevel@tonic-gate if (rflag && fflag) 512*0Sstevel@tonic-gate usage(); 513*0Sstevel@tonic-gate 514*0Sstevel@tonic-gate lookup_perms(); 515*0Sstevel@tonic-gate mesg(MDEBUG, "ruid %d, perms: cpr %d, pm %d\n", 516*0Sstevel@tonic-gate ruid, cpr_status.perm, pm_status.perm); 517*0Sstevel@tonic-gate 518*0Sstevel@tonic-gate if ((!cpr_status.perm && !pm_status.perm) || 519*0Sstevel@tonic-gate (rflag && !(cpr_status.perm && pm_status.perm))) 520*0Sstevel@tonic-gate mesg(MEXIT, "%s\n", strerror(EACCES)); 521*0Sstevel@tonic-gate if (rflag == 0 && access(power_conf, R_OK)) 522*0Sstevel@tonic-gate mesg(MEXIT, "\"%s\" is not readable\n", power_conf); 523*0Sstevel@tonic-gate 524*0Sstevel@tonic-gate get_cpr_info(); 525*0Sstevel@tonic-gate 526*0Sstevel@tonic-gate if (pm_status.perm) 527*0Sstevel@tonic-gate pm_rem_reset(); 528*0Sstevel@tonic-gate get_powerd_pid(); 529*0Sstevel@tonic-gate (void) umask(022); 530*0Sstevel@tonic-gate if (rflag) 531*0Sstevel@tonic-gate return (update_cprconfig() || restart_powerd()); 532*0Sstevel@tonic-gate if (stat(default_conf, &def_info) == -1) 533*0Sstevel@tonic-gate mesg(MEXIT, "cannot stat %s, %s\n", default_conf, 534*0Sstevel@tonic-gate strerror(errno)); 535*0Sstevel@tonic-gate new_cc.loadaverage_thold = DFLT_THOLD; 536*0Sstevel@tonic-gate parse_conf_file(power_conf, NULL); 537*0Sstevel@tonic-gate if (pm_status.perm) 538*0Sstevel@tonic-gate (void) close(pm_fd); 539*0Sstevel@tonic-gate if (fflag) 540*0Sstevel@tonic-gate rval = write_conf(); 541*0Sstevel@tonic-gate cleanup(); 542*0Sstevel@tonic-gate if (rval == 0) 543*0Sstevel@tonic-gate rval = (update_cprconfig() || restart_powerd()); 544*0Sstevel@tonic-gate 545*0Sstevel@tonic-gate return (rval); 546*0Sstevel@tonic-gate } 547