10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 55295Srandyf * Common Development and Distribution License (the "License"). 65295Srandyf * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 228702SBick.Torrejon@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate /* 270Sstevel@tonic-gate * "pmconfig" performs a mixture of Energy-Star configuration tasks 280Sstevel@tonic-gate * for both CheckPoint-Resume and Power-Management services. 290Sstevel@tonic-gate * Tasks include parsing a config file (usually "/etc/power.conf"), 300Sstevel@tonic-gate * updating CPR and PM config files, and setting various PM options 310Sstevel@tonic-gate * via ioctl requests. From the mix, pmconfig should have a more 320Sstevel@tonic-gate * generalized name similar to "estarconfig". 330Sstevel@tonic-gate * 340Sstevel@tonic-gate * OPTIONS: 350Sstevel@tonic-gate * "-r" reset CPR and PM options to default and exit. 360Sstevel@tonic-gate * "-f file" specify an alternate config file; this is a 370Sstevel@tonic-gate * private/non-advertised option used by "dtpower". 380Sstevel@tonic-gate */ 390Sstevel@tonic-gate 400Sstevel@tonic-gate #include "pmconfig.h" 410Sstevel@tonic-gate #include <sys/wait.h> 420Sstevel@tonic-gate #include <signal.h> 430Sstevel@tonic-gate #include <stdarg.h> 440Sstevel@tonic-gate #include <locale.h> 450Sstevel@tonic-gate #include "powerd.h" 460Sstevel@tonic-gate 470Sstevel@tonic-gate 480Sstevel@tonic-gate #define MCCPY_FIELD(dst, src, field) \ 490Sstevel@tonic-gate (void) memccpy(&dst.field, &src.field, 0, sizeof (dst.field) - 1) 500Sstevel@tonic-gate 510Sstevel@tonic-gate 520Sstevel@tonic-gate static char conf_header[] = 530Sstevel@tonic-gate "#\n" 540Sstevel@tonic-gate "# Copyright 1996-2002 Sun Microsystems, Inc. All rights reserved.\n" 550Sstevel@tonic-gate "# Use is subject to license terms.\n" 560Sstevel@tonic-gate "#\n" 570Sstevel@tonic-gate "#pragma ident \"@(#)power.conf 2.1 02/03/04 SMI\"\n" 580Sstevel@tonic-gate "#\n" 590Sstevel@tonic-gate "# Power Management Configuration File\n" 600Sstevel@tonic-gate "#\n\n"; 610Sstevel@tonic-gate 620Sstevel@tonic-gate static char *prog; 630Sstevel@tonic-gate static char *cpr_conf = CPR_CONFIG; 640Sstevel@tonic-gate static char tmp_conf[] = "/etc/.tmp.conf.XXXXXX"; 650Sstevel@tonic-gate static char orig_conf[] = "/etc/power.conf-Orig"; 660Sstevel@tonic-gate static char default_conf[] = "/etc/power.conf"; 670Sstevel@tonic-gate static char *power_conf = default_conf; 680Sstevel@tonic-gate static pid_t powerd_pid; 690Sstevel@tonic-gate static prmup_t *checkup; 700Sstevel@tonic-gate static int tmp_fd; 710Sstevel@tonic-gate 720Sstevel@tonic-gate char estar_vers = ESTAR_VNONE; 730Sstevel@tonic-gate int ua_err = 0; 740Sstevel@tonic-gate int debug = 0; 750Sstevel@tonic-gate 760Sstevel@tonic-gate static struct cprconfig disk_cc; 770Sstevel@tonic-gate struct cprconfig new_cc; 780Sstevel@tonic-gate struct stat def_info; 790Sstevel@tonic-gate static int fflag, rflag; 800Sstevel@tonic-gate int pm_fd; 810Sstevel@tonic-gate uid_t ruid; 820Sstevel@tonic-gate int def_src; 835295Srandyf /* 845295Srandyf * Until we get more graphics driver support, we only enable autopm, 855295Srandyf * S3 support and autoS3 by default on X86 systems that are on our whitelist. 865295Srandyf */ 875295Srandyf int whitelist_only = 1; 885295Srandyf 895295Srandyf int verify = 0; 900Sstevel@tonic-gate 910Sstevel@tonic-gate 920Sstevel@tonic-gate static void 930Sstevel@tonic-gate cleanup(void) 940Sstevel@tonic-gate { 950Sstevel@tonic-gate free(line_args); 960Sstevel@tonic-gate if (access(tmp_conf, F_OK) == 0) 970Sstevel@tonic-gate (void) unlink(tmp_conf); 980Sstevel@tonic-gate } 990Sstevel@tonic-gate 1000Sstevel@tonic-gate 1010Sstevel@tonic-gate /* 1020Sstevel@tonic-gate * Multi-purpose message output routine; also exits when 1030Sstevel@tonic-gate * (status == MEXIT), other status is non-fatal. 1040Sstevel@tonic-gate * VARARGS2 1050Sstevel@tonic-gate */ 1060Sstevel@tonic-gate void 1070Sstevel@tonic-gate mesg(int code, char *fmt, ...) 1080Sstevel@tonic-gate { 1090Sstevel@tonic-gate va_list vargs; 1100Sstevel@tonic-gate 1110Sstevel@tonic-gate /* 1120Sstevel@tonic-gate * debug is checked once here, avoiding N duplicate checks 1130Sstevel@tonic-gate * before each MDEBUG caller and unnecessary text dupduplication. 1140Sstevel@tonic-gate */ 1150Sstevel@tonic-gate if (debug == 0) { 1160Sstevel@tonic-gate /* 1170Sstevel@tonic-gate * If debug is not enabled, skip a debug message; 1180Sstevel@tonic-gate * lead with the program name for an error message, 1190Sstevel@tonic-gate * and follow with a filename and line number if an 1200Sstevel@tonic-gate * error occurs while parsing a conf file. 1210Sstevel@tonic-gate */ 1220Sstevel@tonic-gate if (code == MDEBUG) 1230Sstevel@tonic-gate return; 124*11053SSurya.Prakki@Sun.COM (void) fprintf(stderr, "%s: ", prog); 1250Sstevel@tonic-gate if (lineno) 126*11053SSurya.Prakki@Sun.COM (void) fprintf(stderr, 127*11053SSurya.Prakki@Sun.COM "\"%s\" line %d, ", power_conf, lineno); 1280Sstevel@tonic-gate } 1290Sstevel@tonic-gate 1300Sstevel@tonic-gate va_start(vargs, fmt); 1310Sstevel@tonic-gate (void) vfprintf(stderr, gettext(fmt), vargs); 1320Sstevel@tonic-gate va_end(vargs); 1330Sstevel@tonic-gate 1340Sstevel@tonic-gate if (code == MEXIT) { 1350Sstevel@tonic-gate cleanup(); 1360Sstevel@tonic-gate exit(MEXIT); 1370Sstevel@tonic-gate } 1380Sstevel@tonic-gate } 1390Sstevel@tonic-gate 1400Sstevel@tonic-gate 1410Sstevel@tonic-gate static void 1420Sstevel@tonic-gate usage(void) 1430Sstevel@tonic-gate { 144763Smh27603 (void) fprintf(stderr, gettext("Usage: %s [-r]\n"), prog); 1450Sstevel@tonic-gate exit(1); 1460Sstevel@tonic-gate } 1470Sstevel@tonic-gate 1480Sstevel@tonic-gate 1490Sstevel@tonic-gate /* 1500Sstevel@tonic-gate * Lookup estar version, check if uadmin() service is supported, 1510Sstevel@tonic-gate * and read cpr_config info from disk. 1520Sstevel@tonic-gate */ 1530Sstevel@tonic-gate static void 1540Sstevel@tonic-gate get_cpr_info(void) 1550Sstevel@tonic-gate { 1560Sstevel@tonic-gate ssize_t nread; 1570Sstevel@tonic-gate char *err_fmt; 1580Sstevel@tonic-gate int fd; 1590Sstevel@tonic-gate 1600Sstevel@tonic-gate #ifdef sparc 1610Sstevel@tonic-gate lookup_estar_vers(); 1620Sstevel@tonic-gate if (estar_vers == ESTAR_V2) 1630Sstevel@tonic-gate new_cc.is_cpr_default = 1; 1640Sstevel@tonic-gate else if (estar_vers == ESTAR_V3) 1650Sstevel@tonic-gate new_cc.is_autopm_default = 1; 1660Sstevel@tonic-gate 1670Sstevel@tonic-gate if (uadmin(A_FREEZE, AD_CHECK, 0) == 0) 1680Sstevel@tonic-gate new_cc.is_cpr_capable = 1; 1690Sstevel@tonic-gate else 1700Sstevel@tonic-gate ua_err = errno; 1710Sstevel@tonic-gate 1720Sstevel@tonic-gate if ((fd = open("/dev/tod", O_RDONLY)) != -1) { 1730Sstevel@tonic-gate new_cc.is_autowakeup_capable = 1; 1740Sstevel@tonic-gate (void) close(fd); 1750Sstevel@tonic-gate } 1760Sstevel@tonic-gate #endif /* sparc */ 1770Sstevel@tonic-gate 1780Sstevel@tonic-gate /* 1790Sstevel@tonic-gate * Read in the cpr conf file. If any open or read error occurs, 1800Sstevel@tonic-gate * display an error message only for a non-root user. The file 1810Sstevel@tonic-gate * may not exist on a newly installed system. 1820Sstevel@tonic-gate */ 1830Sstevel@tonic-gate err_fmt = "%s %s; please rerun %s as root\n"; 1840Sstevel@tonic-gate if ((fd = open(cpr_conf, O_RDONLY)) == -1) { 1850Sstevel@tonic-gate if (ruid) 1860Sstevel@tonic-gate mesg(MEXIT, err_fmt, gettext("cannot open"), 1870Sstevel@tonic-gate cpr_conf, prog); 1880Sstevel@tonic-gate } else { 1890Sstevel@tonic-gate nread = read(fd, &disk_cc, sizeof (disk_cc)); 1900Sstevel@tonic-gate (void) close(fd); 1910Sstevel@tonic-gate if (nread != (ssize_t)sizeof (disk_cc)) { 1920Sstevel@tonic-gate if (ruid) 1930Sstevel@tonic-gate mesg(MEXIT, err_fmt, cpr_conf, 1940Sstevel@tonic-gate gettext("file corrupted"), prog); 1950Sstevel@tonic-gate else { 1960Sstevel@tonic-gate (void) unlink(cpr_conf); 1970Sstevel@tonic-gate bzero(&disk_cc, sizeof (disk_cc)); 1980Sstevel@tonic-gate } 1990Sstevel@tonic-gate } 2000Sstevel@tonic-gate } 2010Sstevel@tonic-gate } 2020Sstevel@tonic-gate 2030Sstevel@tonic-gate 2040Sstevel@tonic-gate /* 2050Sstevel@tonic-gate * Unconfigure and reset PM, device is left open for later use. 2060Sstevel@tonic-gate */ 2070Sstevel@tonic-gate static void 2080Sstevel@tonic-gate pm_rem_reset(void) 2090Sstevel@tonic-gate { 2100Sstevel@tonic-gate char *err_fmt = NULL; 2110Sstevel@tonic-gate 2120Sstevel@tonic-gate if ((pm_fd = open("/dev/pm", O_RDWR)) == -1) 2130Sstevel@tonic-gate err_fmt = "cannot open \"/dev/pm\": %s\n"; 2140Sstevel@tonic-gate else if (ioctl(pm_fd, PM_RESET_PM, 0) == -1) 2150Sstevel@tonic-gate err_fmt = "cannot reset pm state: %s\n"; 2160Sstevel@tonic-gate if (err_fmt) 2170Sstevel@tonic-gate mesg(MEXIT, err_fmt, strerror(errno)); 2180Sstevel@tonic-gate } 2190Sstevel@tonic-gate 2200Sstevel@tonic-gate 2210Sstevel@tonic-gate static void 2220Sstevel@tonic-gate get_powerd_pid(void) 2230Sstevel@tonic-gate { 2240Sstevel@tonic-gate char pidstr[16]; 2250Sstevel@tonic-gate int fd; 2260Sstevel@tonic-gate 2270Sstevel@tonic-gate if ((fd = open(PIDPATH, O_RDONLY)) == -1) 2280Sstevel@tonic-gate return; 2290Sstevel@tonic-gate bzero(pidstr, sizeof (pidstr)); 2300Sstevel@tonic-gate if (read(fd, pidstr, sizeof (pidstr)) > 0) { 2310Sstevel@tonic-gate powerd_pid = atoi(pidstr); 2320Sstevel@tonic-gate mesg(MDEBUG, "got powerd pid %ld\n", powerd_pid); 2330Sstevel@tonic-gate } 2340Sstevel@tonic-gate (void) close(fd); 2350Sstevel@tonic-gate } 2360Sstevel@tonic-gate 2370Sstevel@tonic-gate 2380Sstevel@tonic-gate /* 2390Sstevel@tonic-gate * Write revised cprconfig struct to disk based on perms; 2400Sstevel@tonic-gate * returns 1 if any error, otherwise 0. 2410Sstevel@tonic-gate */ 2420Sstevel@tonic-gate static int 2430Sstevel@tonic-gate update_cprconfig(void) 2440Sstevel@tonic-gate { 2450Sstevel@tonic-gate struct cprconfig *wrt_cc = &new_cc; 2460Sstevel@tonic-gate char *err_fmt = NULL; 2470Sstevel@tonic-gate int fd; 2480Sstevel@tonic-gate 2490Sstevel@tonic-gate if (rflag) { 2500Sstevel@tonic-gate /* For "pmconfig -r" case, copy select cpr-related fields. */ 2510Sstevel@tonic-gate new_cc.cf_magic = disk_cc.cf_magic; 2520Sstevel@tonic-gate new_cc.cf_type = disk_cc.cf_type; 2530Sstevel@tonic-gate MCCPY_FIELD(new_cc, disk_cc, cf_path); 2540Sstevel@tonic-gate MCCPY_FIELD(new_cc, disk_cc, cf_fs); 2550Sstevel@tonic-gate MCCPY_FIELD(new_cc, disk_cc, cf_devfs); 2560Sstevel@tonic-gate MCCPY_FIELD(new_cc, disk_cc, cf_dev_prom); 2570Sstevel@tonic-gate } 2580Sstevel@tonic-gate 2590Sstevel@tonic-gate if (!pm_status.perm) { 2600Sstevel@tonic-gate if (cpr_status.update == NOUP) 2610Sstevel@tonic-gate return (1); 2620Sstevel@tonic-gate /* save new struct data with old autopm setting */ 2630Sstevel@tonic-gate MCCPY_FIELD(new_cc, disk_cc, apm_behavior); 2640Sstevel@tonic-gate } else if (!cpr_status.perm) { 2650Sstevel@tonic-gate if (pm_status.update == NOUP) 2660Sstevel@tonic-gate return (1); 2670Sstevel@tonic-gate /* save original struct with new autopm setting */ 2680Sstevel@tonic-gate MCCPY_FIELD(disk_cc, new_cc, apm_behavior); 2690Sstevel@tonic-gate wrt_cc = &disk_cc; 2700Sstevel@tonic-gate } else if (cpr_status.update == NOUP || pm_status.update == NOUP) 2710Sstevel@tonic-gate return (1); 2720Sstevel@tonic-gate 2730Sstevel@tonic-gate if ((fd = open(cpr_conf, O_CREAT | O_TRUNC | O_WRONLY, 0644)) == -1) 2740Sstevel@tonic-gate err_fmt = "cannot open/create \"%s\", %s\n"; 2750Sstevel@tonic-gate else if (write(fd, wrt_cc, sizeof (*wrt_cc)) != sizeof (*wrt_cc)) 2760Sstevel@tonic-gate err_fmt = "error writing \"%s\", %s\n"; 2770Sstevel@tonic-gate if (err_fmt) 2780Sstevel@tonic-gate mesg(MERR, err_fmt, cpr_conf, strerror(errno)); 2797300SEric.Taylor@Sun.COM if (fd != -1) 2807300SEric.Taylor@Sun.COM (void) close(fd); 2810Sstevel@tonic-gate return (err_fmt != NULL); 2820Sstevel@tonic-gate } 2830Sstevel@tonic-gate 2840Sstevel@tonic-gate 2850Sstevel@tonic-gate /* 2860Sstevel@tonic-gate * Signal old powerd when there's a valid pid, or start a new one; 2870Sstevel@tonic-gate * returns 1 if any error, otherwise 0. 2880Sstevel@tonic-gate */ 2890Sstevel@tonic-gate static int 2900Sstevel@tonic-gate restart_powerd(void) 2910Sstevel@tonic-gate { 2920Sstevel@tonic-gate char *powerd = "/usr/lib/power/powerd"; 2930Sstevel@tonic-gate int status = 0; 2940Sstevel@tonic-gate pid_t pid, wp; 2950Sstevel@tonic-gate 2960Sstevel@tonic-gate if (powerd_pid > 0) { 2970Sstevel@tonic-gate if (sigsend(P_PID, powerd_pid, SIGHUP) == 0) 2980Sstevel@tonic-gate return (0); 2990Sstevel@tonic-gate else if (errno != ESRCH) { 3000Sstevel@tonic-gate mesg(MERR, "cannot deliver hangup to powerd\n"); 3010Sstevel@tonic-gate return (1); 3020Sstevel@tonic-gate } 3030Sstevel@tonic-gate } 3040Sstevel@tonic-gate 3050Sstevel@tonic-gate if ((pid = fork()) == NOPID) 3060Sstevel@tonic-gate wp = -1; 3070Sstevel@tonic-gate else if (pid == P_MYPID) { 3080Sstevel@tonic-gate (void) setreuid(0, 0); 3090Sstevel@tonic-gate (void) setregid(0, 0); 3100Sstevel@tonic-gate (void) setgroups(0, NULL); 3115295Srandyf if (debug) 3125295Srandyf (void) execle(powerd, powerd, "-d", NULL, NULL); 3135295Srandyf else 3145295Srandyf (void) execle(powerd, powerd, NULL, NULL); 3150Sstevel@tonic-gate exit(1); 3160Sstevel@tonic-gate } else { 3170Sstevel@tonic-gate do { 3180Sstevel@tonic-gate wp = waitpid(pid, &status, 0); 3190Sstevel@tonic-gate } while (wp == -1 && errno == EINTR); 3200Sstevel@tonic-gate } 3210Sstevel@tonic-gate 3220Sstevel@tonic-gate if (wp == -1) 3230Sstevel@tonic-gate mesg(MERR, "could not start %s\n", powerd); 3240Sstevel@tonic-gate return (wp == -1 || status != 0); 3250Sstevel@tonic-gate } 3260Sstevel@tonic-gate 3270Sstevel@tonic-gate 3280Sstevel@tonic-gate static void 3290Sstevel@tonic-gate save_orig(void) 3300Sstevel@tonic-gate { 3310Sstevel@tonic-gate static char *args[] = { "/usr/bin/cp", default_conf, orig_conf, NULL }; 3320Sstevel@tonic-gate struct stat stbuf; 3330Sstevel@tonic-gate int pid; 3340Sstevel@tonic-gate 3350Sstevel@tonic-gate if (stat(orig_conf, &stbuf) == 0 && stbuf.st_size) 3360Sstevel@tonic-gate return; 3370Sstevel@tonic-gate pid = fork(); 3380Sstevel@tonic-gate if (pid == NOPID) 3390Sstevel@tonic-gate return; 3400Sstevel@tonic-gate else if (pid == P_MYPID) { 3410Sstevel@tonic-gate (void) execve(args[0], args, NULL); 3420Sstevel@tonic-gate exit(1); 3430Sstevel@tonic-gate } else 3440Sstevel@tonic-gate (void) waitpid(pid, NULL, 0); 3450Sstevel@tonic-gate } 3460Sstevel@tonic-gate 3470Sstevel@tonic-gate 3480Sstevel@tonic-gate static void 3490Sstevel@tonic-gate tmp_write(void *buf, size_t len) 3500Sstevel@tonic-gate { 3510Sstevel@tonic-gate if (write(tmp_fd, buf, len) != (ssize_t)len) 3520Sstevel@tonic-gate mesg(MEXIT, "error writing tmp file, %s\n", strerror(errno)); 3530Sstevel@tonic-gate } 3540Sstevel@tonic-gate 3550Sstevel@tonic-gate 3560Sstevel@tonic-gate static void 3570Sstevel@tonic-gate tmp_save_line(char *line, size_t len, cinfo_t *cip) 3580Sstevel@tonic-gate { 3590Sstevel@tonic-gate if (cip && cip->cmt) 3600Sstevel@tonic-gate tmp_write(cip->cmt, strlen(cip->cmt)); 3610Sstevel@tonic-gate tmp_write(line, len); 3620Sstevel@tonic-gate } 3630Sstevel@tonic-gate 3640Sstevel@tonic-gate 3650Sstevel@tonic-gate /* 3660Sstevel@tonic-gate * Filter conf lines and write them to the tmp file. 3670Sstevel@tonic-gate */ 3680Sstevel@tonic-gate static void 3690Sstevel@tonic-gate filter(char *line, size_t len, cinfo_t *cip) 3700Sstevel@tonic-gate { 3710Sstevel@tonic-gate int selected; 3720Sstevel@tonic-gate 3730Sstevel@tonic-gate /* 3740Sstevel@tonic-gate * Lines from an alt conf file are selected when either: 3750Sstevel@tonic-gate * cip is NULL (keyword not matched, probably an old-style device), 3760Sstevel@tonic-gate * OR: it's both OK to accept the conf line (alt) AND either: 3770Sstevel@tonic-gate * preference is not set (NULL checkup) OR the cpr/pm preference 3780Sstevel@tonic-gate * (checkup) matches conftab status. 3790Sstevel@tonic-gate */ 3800Sstevel@tonic-gate selected = (cip == NULL || (cip->alt && 3810Sstevel@tonic-gate (checkup == NULL || checkup == cip->status))); 3820Sstevel@tonic-gate mesg(MDEBUG, "filter: set \"%s\", selected %d\n", 3830Sstevel@tonic-gate cip ? cip->status->set : "none", selected); 3840Sstevel@tonic-gate if (selected) 3850Sstevel@tonic-gate tmp_save_line(line, len, cip); 3860Sstevel@tonic-gate } 3870Sstevel@tonic-gate 3880Sstevel@tonic-gate 3890Sstevel@tonic-gate /* 3900Sstevel@tonic-gate * Set checkup for conf line selection and parse a conf file with filtering. 3910Sstevel@tonic-gate * When pref is NULL, filter selects all conf lines from the new conf file; 3920Sstevel@tonic-gate * otherwise filter selects only cpr or pm related lines from the new or 3930Sstevel@tonic-gate * default conf file based on cpr or pm perm. 3940Sstevel@tonic-gate */ 3950Sstevel@tonic-gate static void 3960Sstevel@tonic-gate conf_scanner(prmup_t *pref) 3970Sstevel@tonic-gate { 3980Sstevel@tonic-gate mesg(MDEBUG, "\nscanning set is %s\n", pref ? pref->set : "both"); 3990Sstevel@tonic-gate checkup = pref; 4000Sstevel@tonic-gate parse_conf_file((pref == NULL || pref->perm) 4019057SSeth.Goldberg@Sun.COM ? power_conf : default_conf, filter, B_FALSE); 4020Sstevel@tonic-gate } 4030Sstevel@tonic-gate 4040Sstevel@tonic-gate 4050Sstevel@tonic-gate /* 4060Sstevel@tonic-gate * Search for any non-alt entries, call the handler routine, 4070Sstevel@tonic-gate * and write entries to the tmp file. 4080Sstevel@tonic-gate */ 4090Sstevel@tonic-gate static void 4100Sstevel@tonic-gate search(char *line, size_t len, cinfo_t *cip) 4110Sstevel@tonic-gate { 4120Sstevel@tonic-gate int skip; 4130Sstevel@tonic-gate 4140Sstevel@tonic-gate skip = (cip == NULL || cip->alt); 4150Sstevel@tonic-gate mesg(MDEBUG, "search: %s\n", skip ? "skipped" : "retained"); 4160Sstevel@tonic-gate if (skip) 4170Sstevel@tonic-gate return; 4180Sstevel@tonic-gate if (cip->status->perm) 4190Sstevel@tonic-gate (void) (*cip->handler)(); 4200Sstevel@tonic-gate tmp_save_line(line, len, cip); 4210Sstevel@tonic-gate } 4220Sstevel@tonic-gate 4230Sstevel@tonic-gate 4240Sstevel@tonic-gate /* 4250Sstevel@tonic-gate * When perm and update status are OK, write a new conf file 4260Sstevel@tonic-gate * and rename to default_conf with the original attributes; 4270Sstevel@tonic-gate * returns 1 if any error, otherwise 0. 4280Sstevel@tonic-gate */ 4290Sstevel@tonic-gate static int 4300Sstevel@tonic-gate write_conf(void) 4310Sstevel@tonic-gate { 4320Sstevel@tonic-gate char *name, *err_str = NULL; 4330Sstevel@tonic-gate struct stat stbuf; 4340Sstevel@tonic-gate 4350Sstevel@tonic-gate if ((cpr_status.perm && cpr_status.update != OKUP) || 4360Sstevel@tonic-gate (pm_status.perm && pm_status.update != OKUP)) { 4370Sstevel@tonic-gate mesg(MDEBUG, "\nconf not written, " 4380Sstevel@tonic-gate "(cpr perm %d update %d), (pm perm %d update %d)\n", 4390Sstevel@tonic-gate cpr_status.perm, cpr_status.update, 4400Sstevel@tonic-gate pm_status.perm, pm_status.update); 4410Sstevel@tonic-gate return (1); 4420Sstevel@tonic-gate } 4430Sstevel@tonic-gate 4440Sstevel@tonic-gate save_orig(); 4450Sstevel@tonic-gate if ((tmp_fd = mkstemp(tmp_conf)) == -1) { 4460Sstevel@tonic-gate mesg(MERR, "cannot open/create tmp file \"%s\"\n", tmp_conf); 4470Sstevel@tonic-gate return (1); 4480Sstevel@tonic-gate } 4490Sstevel@tonic-gate tmp_write(conf_header, sizeof (conf_header) - 1); 4500Sstevel@tonic-gate 4510Sstevel@tonic-gate /* 4520Sstevel@tonic-gate * When both perms are set, save selected lines from the new file; 4530Sstevel@tonic-gate * otherwise save selected subsets from the new and default files. 4540Sstevel@tonic-gate */ 4550Sstevel@tonic-gate if (cpr_status.perm && pm_status.perm) 4560Sstevel@tonic-gate conf_scanner(NULL); 4570Sstevel@tonic-gate else { 4580Sstevel@tonic-gate conf_scanner(&cpr_status); 4590Sstevel@tonic-gate conf_scanner(&pm_status); 4600Sstevel@tonic-gate } 4610Sstevel@tonic-gate 4620Sstevel@tonic-gate /* 4630Sstevel@tonic-gate * "dtpower" will craft an alt conf file with modified content from 4640Sstevel@tonic-gate * /etc/power.conf, but any alt conf file is not a trusted source; 4650Sstevel@tonic-gate * since some alt conf lines may be skipped, the trusted source is 4660Sstevel@tonic-gate * searched for those lines to retain their functionality. 4670Sstevel@tonic-gate */ 4689057SSeth.Goldberg@Sun.COM parse_conf_file(default_conf, search, B_FALSE); 4690Sstevel@tonic-gate 4700Sstevel@tonic-gate (void) close(tmp_fd); 4710Sstevel@tonic-gate 4720Sstevel@tonic-gate if (stat(name = default_conf, &stbuf) == -1) 4730Sstevel@tonic-gate err_str = "stat"; 4740Sstevel@tonic-gate else if (chmod(name = tmp_conf, stbuf.st_mode) == -1) 4750Sstevel@tonic-gate err_str = "chmod"; 4760Sstevel@tonic-gate else if (chown(tmp_conf, stbuf.st_uid, stbuf.st_gid) == -1) 4770Sstevel@tonic-gate err_str = "chown"; 4780Sstevel@tonic-gate else if (rename(tmp_conf, default_conf) == -1) 4790Sstevel@tonic-gate err_str = "rename"; 4800Sstevel@tonic-gate else 4810Sstevel@tonic-gate mesg(MDEBUG, "\n\"%s\" renamed to \"%s\"\n", 4820Sstevel@tonic-gate tmp_conf, default_conf); 4830Sstevel@tonic-gate if (err_str) 4840Sstevel@tonic-gate mesg(MERR, "cannot %s \"%s\", %s\n", 4850Sstevel@tonic-gate err_str, name, strerror(errno)); 4860Sstevel@tonic-gate 4870Sstevel@tonic-gate return (err_str != NULL); 4880Sstevel@tonic-gate } 4890Sstevel@tonic-gate 4900Sstevel@tonic-gate 4910Sstevel@tonic-gate /* ARGSUSED */ 4920Sstevel@tonic-gate int 4930Sstevel@tonic-gate main(int cnt, char **vec) 4940Sstevel@tonic-gate { 4950Sstevel@tonic-gate int rval = 0; 4960Sstevel@tonic-gate 4970Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 4980Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 4990Sstevel@tonic-gate 5000Sstevel@tonic-gate for (prog = *vec++; *vec && **vec == '-'; vec++) { 5010Sstevel@tonic-gate if (strlen(*vec) > 2) 5020Sstevel@tonic-gate usage(); 5030Sstevel@tonic-gate switch (*(*vec + 1)) { 5040Sstevel@tonic-gate case 'd': 5050Sstevel@tonic-gate debug = 1; 5060Sstevel@tonic-gate break; 5070Sstevel@tonic-gate case 'f': 5080Sstevel@tonic-gate fflag = 1; 5090Sstevel@tonic-gate if ((power_conf = *++vec) == NULL) 5100Sstevel@tonic-gate usage(); 5110Sstevel@tonic-gate break; 5120Sstevel@tonic-gate case 'r': 5130Sstevel@tonic-gate rflag = 1; 5140Sstevel@tonic-gate break; 5155295Srandyf case 'W': 5165295Srandyf whitelist_only = 0; 5175295Srandyf break; 5185295Srandyf case 'v': 5195295Srandyf verify = 1; 5205295Srandyf break; 5210Sstevel@tonic-gate default: 5220Sstevel@tonic-gate usage(); 5230Sstevel@tonic-gate break; 5240Sstevel@tonic-gate } 5250Sstevel@tonic-gate } 5260Sstevel@tonic-gate if (rflag && fflag) 5270Sstevel@tonic-gate usage(); 5280Sstevel@tonic-gate 5290Sstevel@tonic-gate lookup_perms(); 5300Sstevel@tonic-gate mesg(MDEBUG, "ruid %d, perms: cpr %d, pm %d\n", 5310Sstevel@tonic-gate ruid, cpr_status.perm, pm_status.perm); 5320Sstevel@tonic-gate 5330Sstevel@tonic-gate if ((!cpr_status.perm && !pm_status.perm) || 5340Sstevel@tonic-gate (rflag && !(cpr_status.perm && pm_status.perm))) 5350Sstevel@tonic-gate mesg(MEXIT, "%s\n", strerror(EACCES)); 5360Sstevel@tonic-gate if (rflag == 0 && access(power_conf, R_OK)) 5370Sstevel@tonic-gate mesg(MEXIT, "\"%s\" is not readable\n", power_conf); 5380Sstevel@tonic-gate 5390Sstevel@tonic-gate get_cpr_info(); 5400Sstevel@tonic-gate 5410Sstevel@tonic-gate if (pm_status.perm) 5420Sstevel@tonic-gate pm_rem_reset(); 5430Sstevel@tonic-gate get_powerd_pid(); 5440Sstevel@tonic-gate (void) umask(022); 5450Sstevel@tonic-gate if (rflag) 5460Sstevel@tonic-gate return (update_cprconfig() || restart_powerd()); 5470Sstevel@tonic-gate if (stat(default_conf, &def_info) == -1) 5480Sstevel@tonic-gate mesg(MEXIT, "cannot stat %s, %s\n", default_conf, 5490Sstevel@tonic-gate strerror(errno)); 5500Sstevel@tonic-gate new_cc.loadaverage_thold = DFLT_THOLD; 5519057SSeth.Goldberg@Sun.COM parse_conf_file(power_conf, NULL, B_TRUE); 5520Sstevel@tonic-gate if (fflag) 5530Sstevel@tonic-gate rval = write_conf(); 5540Sstevel@tonic-gate cleanup(); 5558702SBick.Torrejon@Sun.COM if (pm_status.perm) 5568702SBick.Torrejon@Sun.COM (void) close(pm_fd); 5570Sstevel@tonic-gate if (rval == 0) 5580Sstevel@tonic-gate rval = (update_cprconfig() || restart_powerd()); 5590Sstevel@tonic-gate 5600Sstevel@tonic-gate return (rval); 5610Sstevel@tonic-gate } 562