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