xref: /onnv-gate/usr/src/cmd/power/sys-suspend.c (revision 11053:f33a1c7f3155)
18940SRandy.Fishel@Sun.COM /*
28940SRandy.Fishel@Sun.COM  * CDDL HEADER START
38940SRandy.Fishel@Sun.COM  *
48940SRandy.Fishel@Sun.COM  * The contents of this file are subject to the terms of the
58940SRandy.Fishel@Sun.COM  * Common Development and Distribution License (the "License").
68940SRandy.Fishel@Sun.COM  * You may not use this file except in compliance with the License.
78940SRandy.Fishel@Sun.COM  *
88940SRandy.Fishel@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
98940SRandy.Fishel@Sun.COM  * or http://www.opensolaris.org/os/licensing.
108940SRandy.Fishel@Sun.COM  * See the License for the specific language governing permissions
118940SRandy.Fishel@Sun.COM  * and limitations under the License.
128940SRandy.Fishel@Sun.COM  *
138940SRandy.Fishel@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
148940SRandy.Fishel@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
158940SRandy.Fishel@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
168940SRandy.Fishel@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
178940SRandy.Fishel@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
188940SRandy.Fishel@Sun.COM  *
198940SRandy.Fishel@Sun.COM  * CDDL HEADER END
208940SRandy.Fishel@Sun.COM  */
218940SRandy.Fishel@Sun.COM /*
228940SRandy.Fishel@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
238940SRandy.Fishel@Sun.COM  * Use is subject to license terms.
248940SRandy.Fishel@Sun.COM  */
258940SRandy.Fishel@Sun.COM 
268940SRandy.Fishel@Sun.COM /*
278940SRandy.Fishel@Sun.COM  * This code has a lot in common with the original sys-suspend
288940SRandy.Fishel@Sun.COM  * code.  Windowing facilities have been removed, and it has been
298940SRandy.Fishel@Sun.COM  * updated to use more recent API's.
308940SRandy.Fishel@Sun.COM  */
318940SRandy.Fishel@Sun.COM #include <stdio.h>
328940SRandy.Fishel@Sun.COM #include <fcntl.h>
338940SRandy.Fishel@Sun.COM #include <stdlib.h>
348940SRandy.Fishel@Sun.COM #include <string.h>
358940SRandy.Fishel@Sun.COM #include <strings.h>
368940SRandy.Fishel@Sun.COM #include <unistd.h>
378940SRandy.Fishel@Sun.COM #include <libintl.h>
388940SRandy.Fishel@Sun.COM #include <locale.h>
398940SRandy.Fishel@Sun.COM #include <utility.h>
408940SRandy.Fishel@Sun.COM #include <signal.h>
418940SRandy.Fishel@Sun.COM #include <errno.h>
428940SRandy.Fishel@Sun.COM #include <setjmp.h>
438940SRandy.Fishel@Sun.COM #include <pwd.h>
448940SRandy.Fishel@Sun.COM #include <syslog.h>
458940SRandy.Fishel@Sun.COM #include <sys/types.h>
468940SRandy.Fishel@Sun.COM #include <sys/param.h>
478940SRandy.Fishel@Sun.COM #include <sys/utsname.h>
488940SRandy.Fishel@Sun.COM #include <sys/uadmin.h>
498940SRandy.Fishel@Sun.COM #include <auth_attr.h>
508940SRandy.Fishel@Sun.COM #include <auth_list.h>
518940SRandy.Fishel@Sun.COM #include <secdb.h>
528940SRandy.Fishel@Sun.COM #include <security/pam_appl.h>
538940SRandy.Fishel@Sun.COM #include <utmpx.h>
548940SRandy.Fishel@Sun.COM 
558940SRandy.Fishel@Sun.COM /* For audit */
568940SRandy.Fishel@Sun.COM #include <bsm/adt.h>
578940SRandy.Fishel@Sun.COM #include <bsm/adt_event.h>
588940SRandy.Fishel@Sun.COM 
598940SRandy.Fishel@Sun.COM #include <sys/wait.h>
608940SRandy.Fishel@Sun.COM #include <sys/stat.h>
618940SRandy.Fishel@Sun.COM #include <sys/pm.h>
628940SRandy.Fishel@Sun.COM #include <dirent.h>
638940SRandy.Fishel@Sun.COM #include <sys/cpr.h>
648940SRandy.Fishel@Sun.COM 
658940SRandy.Fishel@Sun.COM /* STATICUSED */
668940SRandy.Fishel@Sun.COM struct utmpx 	utmp;
678940SRandy.Fishel@Sun.COM #define	NMAX		(sizeof (utmp.ut_name))
688940SRandy.Fishel@Sun.COM 
698940SRandy.Fishel@Sun.COM /*
708940SRandy.Fishel@Sun.COM  * Authorizations used by Power Management
718940SRandy.Fishel@Sun.COM  */
728940SRandy.Fishel@Sun.COM #define	AUTHNAME_SHUTDOWN	"solaris.system.shutdown"
738940SRandy.Fishel@Sun.COM #define	AUTHNAME_SUSPEND_RAM	"solaris.system.power.suspend.ram"
748940SRandy.Fishel@Sun.COM #define	AUTHNAME_SUSPEND_DISK	"solaris.system.power.suspend.disk"
758940SRandy.Fishel@Sun.COM 
768940SRandy.Fishel@Sun.COM /* Platform specific definitions */
778940SRandy.Fishel@Sun.COM #ifdef i386
788940SRandy.Fishel@Sun.COM #define	AD_CHECK_SUSPEND	AD_CHECK_SUSPEND_TO_RAM
798940SRandy.Fishel@Sun.COM #define	AD_SUSPEND		AD_SUSPEND_TO_RAM
808940SRandy.Fishel@Sun.COM #define	ADT_FCN			ADT_UADMIN_FCN_AD_SUSPEND_TO_RAM
818940SRandy.Fishel@Sun.COM #define	AUTHNAME_SUSPEND	AUTHNAME_SUSPEND_RAM
828940SRandy.Fishel@Sun.COM #else
838940SRandy.Fishel@Sun.COM #define	AD_CHECK_SUSPEND	AD_CHECK_SUSPEND_TO_DISK
848940SRandy.Fishel@Sun.COM #define	AD_SUSPEND		AD_SUSPEND_TO_DISK
858940SRandy.Fishel@Sun.COM #define	ADT_FCN			ADT_UADMIN_FCN_AD_SUSPEND_TO_DISK
868940SRandy.Fishel@Sun.COM #define	AUTHNAME_SUSPEND	AUTHNAME_SUSPEND_DISK
878940SRandy.Fishel@Sun.COM #endif
888940SRandy.Fishel@Sun.COM 
898940SRandy.Fishel@Sun.COM static	int		flags = 0;
908940SRandy.Fishel@Sun.COM static	int		no_tty = 0;
918940SRandy.Fishel@Sun.COM /*
928940SRandy.Fishel@Sun.COM  * Flag definitions - could go in a header file, but there are just a few
938940SRandy.Fishel@Sun.COM  */
948940SRandy.Fishel@Sun.COM #define	FORCE		0x001
958940SRandy.Fishel@Sun.COM #define	NO_WARN		0x002
968940SRandy.Fishel@Sun.COM #define	NO_XLOCK	0x004
978940SRandy.Fishel@Sun.COM #define	SHUTDOWN	0x008
988940SRandy.Fishel@Sun.COM #define	LOWPOWER	0x010
998940SRandy.Fishel@Sun.COM #define	TEST		0x800
1008940SRandy.Fishel@Sun.COM 
1018940SRandy.Fishel@Sun.COM static	sigjmp_buf	jmp_stack;
1028940SRandy.Fishel@Sun.COM static	char	user[NMAX + 1];
1038940SRandy.Fishel@Sun.COM static	char	**argvl;
1048940SRandy.Fishel@Sun.COM 
1058940SRandy.Fishel@Sun.COM 
1068940SRandy.Fishel@Sun.COM 
1078940SRandy.Fishel@Sun.COM /*
1088940SRandy.Fishel@Sun.COM  *  Forward Declarations.
1098940SRandy.Fishel@Sun.COM  */
1108940SRandy.Fishel@Sun.COM static	void	pm_poweroff(void);
1118940SRandy.Fishel@Sun.COM static	int	bringto_lowpower(void);
1128940SRandy.Fishel@Sun.COM static	int	is_mou3(void);
1138940SRandy.Fishel@Sun.COM static	void	suspend_error(int);
1148940SRandy.Fishel@Sun.COM static	int	pm_check_suspend(void);
1158940SRandy.Fishel@Sun.COM static	void	pm_suspend(void);
1168940SRandy.Fishel@Sun.COM static	void	pm_do_auth(adt_session_data_t *);
1178940SRandy.Fishel@Sun.COM 
1188940SRandy.Fishel@Sun.COM /*
1198940SRandy.Fishel@Sun.COM  *  External Declarations.
1208940SRandy.Fishel@Sun.COM  */
1218940SRandy.Fishel@Sun.COM extern	int	pam_tty_conv(int, struct pam_message **,
1228940SRandy.Fishel@Sun.COM     struct pam_response **, void *);
1238940SRandy.Fishel@Sun.COM extern	char	*optarg;
1248940SRandy.Fishel@Sun.COM 
1258940SRandy.Fishel@Sun.COM /*
1268940SRandy.Fishel@Sun.COM  * Audit related code.  I would also think that some of this could be
1278940SRandy.Fishel@Sun.COM  * in external code, as they could be useful of other apps.
1288940SRandy.Fishel@Sun.COM  */
1298940SRandy.Fishel@Sun.COM /*
1308940SRandy.Fishel@Sun.COM  * Write audit event.  Could be useful in the PM library, so it is
1318940SRandy.Fishel@Sun.COM  * included here.  For the most part it is only used by the PAM code.
1328940SRandy.Fishel@Sun.COM  */
1338940SRandy.Fishel@Sun.COM static void
pm_audit_event(adt_session_data_t * ah,au_event_t event_id,int status)1348940SRandy.Fishel@Sun.COM pm_audit_event(adt_session_data_t *ah, au_event_t event_id, int status)
1358940SRandy.Fishel@Sun.COM {
1368940SRandy.Fishel@Sun.COM 	adt_event_data_t	*event;
1378940SRandy.Fishel@Sun.COM 
1388940SRandy.Fishel@Sun.COM 
1398940SRandy.Fishel@Sun.COM 	if ((event = adt_alloc_event(ah, event_id)) == NULL) {
1408940SRandy.Fishel@Sun.COM 		return;
1418940SRandy.Fishel@Sun.COM 	}
1428940SRandy.Fishel@Sun.COM 
1438940SRandy.Fishel@Sun.COM 	(void) adt_put_event(event,
1448940SRandy.Fishel@Sun.COM 	    status == PAM_SUCCESS ? ADT_SUCCESS : ADT_FAILURE,
1458940SRandy.Fishel@Sun.COM 	    status == PAM_SUCCESS ? ADT_SUCCESS : ADT_FAIL_PAM + status);
1468940SRandy.Fishel@Sun.COM 
1478940SRandy.Fishel@Sun.COM 	adt_free_event(event);
1488940SRandy.Fishel@Sun.COM }
1498940SRandy.Fishel@Sun.COM 
1508940SRandy.Fishel@Sun.COM #define	RETRY_COUNT 15
1518940SRandy.Fishel@Sun.COM static int
change_audit_file(void)1528940SRandy.Fishel@Sun.COM change_audit_file(void)
1538940SRandy.Fishel@Sun.COM {
1548940SRandy.Fishel@Sun.COM 	pid_t	pid;
1558940SRandy.Fishel@Sun.COM 
1568940SRandy.Fishel@Sun.COM 	if (!adt_audit_state(AUC_AUDITING)) {
1578940SRandy.Fishel@Sun.COM 		/* auditd not running, just return */
1588940SRandy.Fishel@Sun.COM 		return (0);
1598940SRandy.Fishel@Sun.COM 	}
1608940SRandy.Fishel@Sun.COM 
1618940SRandy.Fishel@Sun.COM 	if ((pid = fork()) == 0) {
1628940SRandy.Fishel@Sun.COM 		(void) execl("/usr/sbin/audit", "audit", "-n", NULL);
1638940SRandy.Fishel@Sun.COM 		(void) fprintf(stderr, gettext("error changing audit files: "
1648940SRandy.Fishel@Sun.COM 		    "%s\n"), strerror(errno));
1658940SRandy.Fishel@Sun.COM 		_exit(-1);
1668940SRandy.Fishel@Sun.COM 	} else if (pid == -1) {
1678940SRandy.Fishel@Sun.COM 		(void) fprintf(stderr, gettext("error changing audit files: "
1688940SRandy.Fishel@Sun.COM 		    "%s\n"), strerror(errno));
1698940SRandy.Fishel@Sun.COM 		return (-1);
1708940SRandy.Fishel@Sun.COM 	} else {
1718940SRandy.Fishel@Sun.COM 		pid_t	rc;
1728940SRandy.Fishel@Sun.COM 		int	retries = RETRY_COUNT;
1738940SRandy.Fishel@Sun.COM 
1748940SRandy.Fishel@Sun.COM 		/*
1758940SRandy.Fishel@Sun.COM 		 * Wait for audit(1M) -n process to complete
1768940SRandy.Fishel@Sun.COM 		 *
1778940SRandy.Fishel@Sun.COM 		 */
1788940SRandy.Fishel@Sun.COM 		do {
1798940SRandy.Fishel@Sun.COM 			if ((rc = waitpid(pid, NULL, WNOHANG)) == pid) {
1808940SRandy.Fishel@Sun.COM 				return (0);
1818940SRandy.Fishel@Sun.COM 			} else if (rc == -1) {
1828940SRandy.Fishel@Sun.COM 				return (-1);
1838940SRandy.Fishel@Sun.COM 			} else {
1848940SRandy.Fishel@Sun.COM 				(void) sleep(1);
1858940SRandy.Fishel@Sun.COM 				retries--;
1868940SRandy.Fishel@Sun.COM 			}
1878940SRandy.Fishel@Sun.COM 
1888940SRandy.Fishel@Sun.COM 		} while (retries != 0);
1898940SRandy.Fishel@Sun.COM 	}
1908940SRandy.Fishel@Sun.COM 	return (-1);
1918940SRandy.Fishel@Sun.COM }
1928940SRandy.Fishel@Sun.COM 
1938940SRandy.Fishel@Sun.COM static void
wait_for_auqueue()1948940SRandy.Fishel@Sun.COM wait_for_auqueue()
1958940SRandy.Fishel@Sun.COM {
1968940SRandy.Fishel@Sun.COM 	au_stat_t	au_stat;
1978940SRandy.Fishel@Sun.COM 	int		retries = 10;
1988940SRandy.Fishel@Sun.COM 
1998940SRandy.Fishel@Sun.COM 	while (retries-- && auditon(A_GETSTAT, (caddr_t)&au_stat, NULL) == 0) {
2008940SRandy.Fishel@Sun.COM 		if (au_stat.as_enqueue == au_stat.as_written) {
2018940SRandy.Fishel@Sun.COM 			break;
2028940SRandy.Fishel@Sun.COM 		}
2038940SRandy.Fishel@Sun.COM 		(void) sleep(1);
2048940SRandy.Fishel@Sun.COM 	}
2058940SRandy.Fishel@Sun.COM }
2068940SRandy.Fishel@Sun.COM 
2078940SRandy.Fishel@Sun.COM /* End of Audit-related code */
2088940SRandy.Fishel@Sun.COM 
2098940SRandy.Fishel@Sun.COM /* ARGSUSED0 */
2108940SRandy.Fishel@Sun.COM static void
alarm_handler(int sig)2118940SRandy.Fishel@Sun.COM alarm_handler(int sig)
2128940SRandy.Fishel@Sun.COM {
2138940SRandy.Fishel@Sun.COM 	siglongjmp(jmp_stack, 1);
2148940SRandy.Fishel@Sun.COM }
2158940SRandy.Fishel@Sun.COM 
2168940SRandy.Fishel@Sun.COM /*
2178940SRandy.Fishel@Sun.COM  * These are functions that would be candidates for moving to a library.
2188940SRandy.Fishel@Sun.COM  */
2198940SRandy.Fishel@Sun.COM 
2208940SRandy.Fishel@Sun.COM /*
2218940SRandy.Fishel@Sun.COM  * pm_poweroff - similar to poweroff(1M)
2228940SRandy.Fishel@Sun.COM  * This should do the same auditing as poweroff(1m) would do when it
2238940SRandy.Fishel@Sun.COM  * becomes a libpower function.  Till then we use poweroff(1m).
2248940SRandy.Fishel@Sun.COM  */
2258940SRandy.Fishel@Sun.COM static void
pm_poweroff(void)2268940SRandy.Fishel@Sun.COM pm_poweroff(void)
2278940SRandy.Fishel@Sun.COM {
2288940SRandy.Fishel@Sun.COM 	if (chkauthattr(AUTHNAME_SHUTDOWN, user) != 1) {
2298940SRandy.Fishel@Sun.COM 		(void) printf(gettext("User %s does not have correct "
2308940SRandy.Fishel@Sun.COM 		    "authorizations to shutdown this machine.\n"), user);
2318940SRandy.Fishel@Sun.COM 		exit(1);
2328940SRandy.Fishel@Sun.COM 	}
2338940SRandy.Fishel@Sun.COM 	openlog("suspend", 0, LOG_DAEMON);
2348940SRandy.Fishel@Sun.COM 	syslog(LOG_NOTICE, "System is being shut down.");
2358940SRandy.Fishel@Sun.COM 	closelog();
2368940SRandy.Fishel@Sun.COM 
2378940SRandy.Fishel@Sun.COM 	/*
2388940SRandy.Fishel@Sun.COM 	 * Call poweroff(1m) to shut down the system.
2398940SRandy.Fishel@Sun.COM 	 */
2408940SRandy.Fishel@Sun.COM 	(void) execl("/usr/sbin/poweroff", "poweroff", NULL);
2418940SRandy.Fishel@Sun.COM 
2428940SRandy.Fishel@Sun.COM }
2438940SRandy.Fishel@Sun.COM 
2448940SRandy.Fishel@Sun.COM /*
2458940SRandy.Fishel@Sun.COM  * pm_check_suspend() - Check to see if suspend is supported/enabled
2468940SRandy.Fishel@Sun.COM  * on this machine.
2478940SRandy.Fishel@Sun.COM  * Ultimately, we would prefer to get the "default" suspend type from
2488940SRandy.Fishel@Sun.COM  * a PM property or some other API, but for now, we know that STR is
2498940SRandy.Fishel@Sun.COM  * only available on x86 and STD is only available on Sparc.  It does
2508940SRandy.Fishel@Sun.COM  * make this function quite easy, though.
2518940SRandy.Fishel@Sun.COM  */
2528940SRandy.Fishel@Sun.COM static int
pm_check_suspend(void)2538940SRandy.Fishel@Sun.COM pm_check_suspend(void) {
2548940SRandy.Fishel@Sun.COM 	/*
2558940SRandy.Fishel@Sun.COM 	 * Use the uadmin(2) "CHECK" command to see if suspend is supported
2568940SRandy.Fishel@Sun.COM 	 */
2578940SRandy.Fishel@Sun.COM 	return (uadmin(A_FREEZE, AD_CHECK_SUSPEND, 0));
2588940SRandy.Fishel@Sun.COM }
2598940SRandy.Fishel@Sun.COM 
2608940SRandy.Fishel@Sun.COM /*
2618940SRandy.Fishel@Sun.COM  * This entry point _should_ be the common entry to suspend.  It is in
2628940SRandy.Fishel@Sun.COM  * it's entirety here, but would be best moved to libpower when that
2638940SRandy.Fishel@Sun.COM  * is available.
2648940SRandy.Fishel@Sun.COM  */
2658940SRandy.Fishel@Sun.COM static void
pm_suspend(void)2668940SRandy.Fishel@Sun.COM pm_suspend(void)
2678940SRandy.Fishel@Sun.COM {
2688940SRandy.Fishel@Sun.COM 	int			cprarg = AD_SUSPEND;
2698940SRandy.Fishel@Sun.COM 	enum adt_uadmin_fcn	fcn_id = ADT_FCN;
2708940SRandy.Fishel@Sun.COM 	au_event_t		event_id = ADT_uadmin_freeze;
2718940SRandy.Fishel@Sun.COM 	adt_event_data_t	*event = NULL; /* event to be generated */
2728940SRandy.Fishel@Sun.COM 	adt_session_data_t	*ah = NULL;  /* audit session handle */
2738940SRandy.Fishel@Sun.COM 
2748940SRandy.Fishel@Sun.COM 	/*
2758940SRandy.Fishel@Sun.COM 	 * Does the user have permission to use this command?
2768940SRandy.Fishel@Sun.COM 	 */
2778940SRandy.Fishel@Sun.COM 	if (chkauthattr(AUTHNAME_SUSPEND, user) != 1) {
2788940SRandy.Fishel@Sun.COM 		(void) printf(gettext("User %s does not have correct "
2798940SRandy.Fishel@Sun.COM 		    "authorizations to suspend this machine.\n"), user);
2808940SRandy.Fishel@Sun.COM 		exit(1);
2818940SRandy.Fishel@Sun.COM 	}
2828940SRandy.Fishel@Sun.COM 
2838940SRandy.Fishel@Sun.COM 	if (flags & LOWPOWER) {
2848940SRandy.Fishel@Sun.COM 		if (bringto_lowpower() == -1) {
2858940SRandy.Fishel@Sun.COM 			(void) printf(gettext("LowPower Failed\n"));
2868940SRandy.Fishel@Sun.COM 			exit(1);
2878940SRandy.Fishel@Sun.COM 		}
2888940SRandy.Fishel@Sun.COM 	} else if (flags & TEST) {
2898940SRandy.Fishel@Sun.COM 		/*
2908940SRandy.Fishel@Sun.COM 		 * Test mode, do checks as if a real suspend, but
2918940SRandy.Fishel@Sun.COM 		 * don't actually do the suspend.
2928940SRandy.Fishel@Sun.COM 		 */
2938940SRandy.Fishel@Sun.COM 		/* Check if suspend is supported */
2948940SRandy.Fishel@Sun.COM 		if (pm_check_suspend() == -1) {
2958940SRandy.Fishel@Sun.COM 			suspend_error(errno);
2968940SRandy.Fishel@Sun.COM 		}
2978940SRandy.Fishel@Sun.COM 
2988940SRandy.Fishel@Sun.COM 		(void) printf(gettext("TEST: Suspend would have been"
2998940SRandy.Fishel@Sun.COM 		    " performed\n"));
3008940SRandy.Fishel@Sun.COM 
3018940SRandy.Fishel@Sun.COM 	} else {
3028940SRandy.Fishel@Sun.COM 		/* Check if suspend is supported */
3038940SRandy.Fishel@Sun.COM 		if (pm_check_suspend() == -1) {
3048940SRandy.Fishel@Sun.COM 			suspend_error(errno);
3058940SRandy.Fishel@Sun.COM 		}
3068940SRandy.Fishel@Sun.COM 
3078940SRandy.Fishel@Sun.COM 		/*
3088940SRandy.Fishel@Sun.COM 		 * We are about to suspend this machine, try and
3098940SRandy.Fishel@Sun.COM 		 * lock the screen.  We don't really care if this
3108940SRandy.Fishel@Sun.COM 		 * succeeds or not, but that we actually tried. We
3118940SRandy.Fishel@Sun.COM 		 * also know that we have sufficient privileges to
3128940SRandy.Fishel@Sun.COM 		 * be here, so we lock the screen now, even if
3138940SRandy.Fishel@Sun.COM 		 * suspend actually fails.
3148940SRandy.Fishel@Sun.COM 		 * Note that garbage is sometimes displayed, and
3158940SRandy.Fishel@Sun.COM 		 * we don't really care about it, so we toss all
3168940SRandy.Fishel@Sun.COM 		 * text response.
3178940SRandy.Fishel@Sun.COM 		 * it would also be good if there were another option
3188940SRandy.Fishel@Sun.COM 		 * instead of launcing a file, as the disk might be
3198940SRandy.Fishel@Sun.COM 		 * spun down if we are suspending due to idle.
3208940SRandy.Fishel@Sun.COM 		 */
3218940SRandy.Fishel@Sun.COM 		if (!(flags & NO_XLOCK)) {
3228940SRandy.Fishel@Sun.COM 			(void) system("/usr/bin/xdg-screensaver lock "
3238940SRandy.Fishel@Sun.COM 			    " >/dev/null 2>&1");
3248940SRandy.Fishel@Sun.COM 		}
3258940SRandy.Fishel@Sun.COM 
3268940SRandy.Fishel@Sun.COM 		/* Time to do the actual deed!  */
3278940SRandy.Fishel@Sun.COM 		/*
3288940SRandy.Fishel@Sun.COM 		 * Before we actually suspend, we need to audit and
3298940SRandy.Fishel@Sun.COM 		 * "suspend" the audit files.
3308940SRandy.Fishel@Sun.COM 		 */
3318940SRandy.Fishel@Sun.COM 		/* set up audit session and event */
3328940SRandy.Fishel@Sun.COM 		if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) == 0) {
3338940SRandy.Fishel@Sun.COM 			if ((event = adt_alloc_event(ah, event_id)) != NULL) {
3348940SRandy.Fishel@Sun.COM 				event->adt_uadmin_freeze.fcn = fcn_id;
3358940SRandy.Fishel@Sun.COM 				event->adt_uadmin_freeze.mdep = NULL;
3368940SRandy.Fishel@Sun.COM 				if (adt_put_event(event, ADT_SUCCESS, 0) != 0) {
3378940SRandy.Fishel@Sun.COM 					(void) fprintf(stderr, gettext(
3388940SRandy.Fishel@Sun.COM 					    "%s: can't put audit event\n"),
3398940SRandy.Fishel@Sun.COM 					    argvl[0]);
3408940SRandy.Fishel@Sun.COM 				} else {
3418940SRandy.Fishel@Sun.COM 					wait_for_auqueue();
3428940SRandy.Fishel@Sun.COM 				}
3438940SRandy.Fishel@Sun.COM 			}
3448940SRandy.Fishel@Sun.COM 			(void) change_audit_file();
3458940SRandy.Fishel@Sun.COM 		} else {
3468940SRandy.Fishel@Sun.COM 			(void) fprintf(stderr, gettext(
3478940SRandy.Fishel@Sun.COM 			    "%s: can't start audit session\n"), argvl[0]);
3488940SRandy.Fishel@Sun.COM 		}
3498940SRandy.Fishel@Sun.COM 
3508940SRandy.Fishel@Sun.COM 		if (uadmin(A_FREEZE, cprarg, 0) != 0) {
3518940SRandy.Fishel@Sun.COM 			(void) printf(gettext("Suspend Failed\n"));
3528940SRandy.Fishel@Sun.COM 			if (flags & FORCE) {
3538940SRandy.Fishel@Sun.COM 				/*
3548940SRandy.Fishel@Sun.COM 				 * Note, that if we actually poweroff,
3558940SRandy.Fishel@Sun.COM 				 * that the poweroff function will handle
3568940SRandy.Fishel@Sun.COM 				 * that audit trail, and the resume
3578940SRandy.Fishel@Sun.COM 				 * trail is effectively done.
3588940SRandy.Fishel@Sun.COM 				 */
3598940SRandy.Fishel@Sun.COM 				pm_poweroff();
3608940SRandy.Fishel@Sun.COM 			} else {
3618940SRandy.Fishel@Sun.COM 				/* suspend_error() will exit. */
3628940SRandy.Fishel@Sun.COM 				suspend_error(errno);
3638940SRandy.Fishel@Sun.COM 				/*
3648940SRandy.Fishel@Sun.COM 				 * Audit the suspend failure and
3658940SRandy.Fishel@Sun.COM 				 * reuse the event, but don't create one
3668940SRandy.Fishel@Sun.COM 				 * if we don't already have one.
3678940SRandy.Fishel@Sun.COM 				 */
3688940SRandy.Fishel@Sun.COM 				if (event != NULL) {
369*11053SSurya.Prakki@Sun.COM 					(void) adt_put_event(event,
370*11053SSurya.Prakki@Sun.COM 					    ADT_FAILURE, 0);
3718940SRandy.Fishel@Sun.COM 				}
3728940SRandy.Fishel@Sun.COM 			}
3738940SRandy.Fishel@Sun.COM 		}
3748940SRandy.Fishel@Sun.COM 
3758940SRandy.Fishel@Sun.COM 		/*
3768940SRandy.Fishel@Sun.COM 		 * Write the thaw event.
3778940SRandy.Fishel@Sun.COM 		 */
3788940SRandy.Fishel@Sun.COM 		if (ah != NULL) {
3798940SRandy.Fishel@Sun.COM 			if ((event == NULL) &&
3808940SRandy.Fishel@Sun.COM 			    ((event = adt_alloc_event(ah, ADT_uadmin_thaw))
3818940SRandy.Fishel@Sun.COM 			    == NULL)) {
3828940SRandy.Fishel@Sun.COM 				(void) fprintf(stderr, gettext(
3838940SRandy.Fishel@Sun.COM 				    "%s: can't allocate thaw audit event\n"),
3848940SRandy.Fishel@Sun.COM 				    argvl[0]);
3858940SRandy.Fishel@Sun.COM 			} else {
3868940SRandy.Fishel@Sun.COM 				event->adt_uadmin_thaw.fcn = fcn_id;
3878940SRandy.Fishel@Sun.COM 				if (adt_put_event(event, ADT_SUCCESS, 0) != 0) {
3888940SRandy.Fishel@Sun.COM 					(void) fprintf(stderr, gettext(
3898940SRandy.Fishel@Sun.COM 					    "%s: can't put thaw audit event\n"),
3908940SRandy.Fishel@Sun.COM 					    argvl[0]);
3918940SRandy.Fishel@Sun.COM 				}
3928940SRandy.Fishel@Sun.COM 				(void) adt_free_event(event);
3938940SRandy.Fishel@Sun.COM 			}
3948940SRandy.Fishel@Sun.COM 		}
3958940SRandy.Fishel@Sun.COM 	}
3968940SRandy.Fishel@Sun.COM 	if ((no_tty ? 0 : 1) && !(flags & NO_XLOCK)) {
3978940SRandy.Fishel@Sun.COM 		pm_do_auth(ah);
3988940SRandy.Fishel@Sun.COM 	}
3998940SRandy.Fishel@Sun.COM 
4008940SRandy.Fishel@Sun.COM 	(void) adt_end_session(ah);
4018940SRandy.Fishel@Sun.COM }
4028940SRandy.Fishel@Sun.COM /* End of "library" functions */
4038940SRandy.Fishel@Sun.COM 
4048940SRandy.Fishel@Sun.COM /*
4058940SRandy.Fishel@Sun.COM  * Print an appropriate error message and exit.
4068940SRandy.Fishel@Sun.COM  */
4078940SRandy.Fishel@Sun.COM 
4088940SRandy.Fishel@Sun.COM static void
suspend_error(int error)4098940SRandy.Fishel@Sun.COM suspend_error(int error) {
4108940SRandy.Fishel@Sun.COM 
4118940SRandy.Fishel@Sun.COM 	switch (error) {
4128940SRandy.Fishel@Sun.COM 	case EBUSY:
4138940SRandy.Fishel@Sun.COM 		(void) printf(gettext("suspend: "
4148940SRandy.Fishel@Sun.COM 		    "Suspend already in progress.\n\n"));
4158940SRandy.Fishel@Sun.COM 		exit(1);
4168940SRandy.Fishel@Sun.COM 		/*NOTREACHED*/
4178940SRandy.Fishel@Sun.COM 	case ENOMEM:
4188940SRandy.Fishel@Sun.COM 		/*FALLTHROUGH*/
4198940SRandy.Fishel@Sun.COM 	case ENOSPC:
4208940SRandy.Fishel@Sun.COM 		(void) printf(gettext("suspend: "
4218940SRandy.Fishel@Sun.COM 		    "Not enough resources to suspend.\n\n"));
4228940SRandy.Fishel@Sun.COM 		exit(1);
4238940SRandy.Fishel@Sun.COM 		/*NOTREACHED*/
4248940SRandy.Fishel@Sun.COM 	case ENOTSUP:
4258940SRandy.Fishel@Sun.COM 		(void) printf(gettext("suspend: "
4268940SRandy.Fishel@Sun.COM 		    "Suspend is not supported.\n\n"));
4278940SRandy.Fishel@Sun.COM 		exit(1);
4288940SRandy.Fishel@Sun.COM 		/*NOTREACHED*/
4298940SRandy.Fishel@Sun.COM 	case EPERM:
4308940SRandy.Fishel@Sun.COM 		(void) printf(gettext("suspend: "
4318940SRandy.Fishel@Sun.COM 		    "Not sufficient privileges.\n\n"));
4328940SRandy.Fishel@Sun.COM 		exit(1);
4338940SRandy.Fishel@Sun.COM 		/*NOTREACHED*/
4348940SRandy.Fishel@Sun.COM 	default:
4358940SRandy.Fishel@Sun.COM 		(void) printf(gettext("suspend: "
4368940SRandy.Fishel@Sun.COM 		    "unknown error.\n\n"));
4378940SRandy.Fishel@Sun.COM 		exit(1);
4388940SRandy.Fishel@Sun.COM 	}
4398940SRandy.Fishel@Sun.COM 
4408940SRandy.Fishel@Sun.COM }
4418940SRandy.Fishel@Sun.COM 
4428940SRandy.Fishel@Sun.COM /*
4438940SRandy.Fishel@Sun.COM  * refresh_dt() - Refresh screen when 'dtgreet' is running.
4448940SRandy.Fishel@Sun.COM  * This is here for compatibility reasons, and could be removed once
4458940SRandy.Fishel@Sun.COM  * dtgreet is no longer part of the system.
4468940SRandy.Fishel@Sun.COM  */
4478940SRandy.Fishel@Sun.COM static int
refresh_dt()4488940SRandy.Fishel@Sun.COM refresh_dt()
4498940SRandy.Fishel@Sun.COM {
4508940SRandy.Fishel@Sun.COM 	int	status;
4518940SRandy.Fishel@Sun.COM 	struct stat	stat_buf;
4528940SRandy.Fishel@Sun.COM 
4538940SRandy.Fishel@Sun.COM 	/*
4548940SRandy.Fishel@Sun.COM 	 * If dtgreet exists, HUP it, otherwise just let screenlock
4558940SRandy.Fishel@Sun.COM 	 * do it's thing.
4568940SRandy.Fishel@Sun.COM 	 */
4578940SRandy.Fishel@Sun.COM 	if ((stat("/usr/dt/bin/dtgreet", &stat_buf) == 0) &&
4588940SRandy.Fishel@Sun.COM 	    (stat_buf.st_mode & S_IXUSR)) {
4598940SRandy.Fishel@Sun.COM 		switch (fork()) {
4608940SRandy.Fishel@Sun.COM 		case -1:
4618940SRandy.Fishel@Sun.COM 			break;
4628940SRandy.Fishel@Sun.COM 		case 0:
4638940SRandy.Fishel@Sun.COM 			(void) close(1);
4648940SRandy.Fishel@Sun.COM 			(void) execl("/usr/bin/pkill", "pkill",
4658940SRandy.Fishel@Sun.COM 			    "-HUP", "-u", "0", "-x", "dtgreet", NULL);
4668940SRandy.Fishel@Sun.COM 			break;
4678940SRandy.Fishel@Sun.COM 		default:
4688940SRandy.Fishel@Sun.COM 			(void) wait(&status);
4698940SRandy.Fishel@Sun.COM 		}
4708940SRandy.Fishel@Sun.COM 	}
4718940SRandy.Fishel@Sun.COM 
4728940SRandy.Fishel@Sun.COM 	return (0);
4738940SRandy.Fishel@Sun.COM }
4748940SRandy.Fishel@Sun.COM 
4758940SRandy.Fishel@Sun.COM #define	DT_TMP	"/var/dt/tmp"
4768940SRandy.Fishel@Sun.COM 
4778940SRandy.Fishel@Sun.COM /*
4788940SRandy.Fishel@Sun.COM  * On enter, the "xauthority" string has the value "XAUTHORITY=".  On
4798940SRandy.Fishel@Sun.COM  * return, if a Xauthority file is found, concatenate it to this string,
4808940SRandy.Fishel@Sun.COM  * otherwise, return "xauthority" as it is.
4818940SRandy.Fishel@Sun.COM  */
4828940SRandy.Fishel@Sun.COM static char *
get_xauthority(char * xauthority)4838940SRandy.Fishel@Sun.COM get_xauthority(char *xauthority)
4848940SRandy.Fishel@Sun.COM {
4858940SRandy.Fishel@Sun.COM 	pid_t uid;
4868940SRandy.Fishel@Sun.COM 	char *home_dir;
4878940SRandy.Fishel@Sun.COM 	struct passwd *pwd;
4888940SRandy.Fishel@Sun.COM 	char filepath[MAXPATHLEN];
4898940SRandy.Fishel@Sun.COM 	struct stat stat_buf;
4908940SRandy.Fishel@Sun.COM 	DIR *dirp;
4918940SRandy.Fishel@Sun.COM 	struct dirent *dp;
4928940SRandy.Fishel@Sun.COM 	char xauth[MAXPATHLEN] = "";
4938940SRandy.Fishel@Sun.COM 	time_t latest = 0;
4948940SRandy.Fishel@Sun.COM 
4958940SRandy.Fishel@Sun.COM 	uid = getuid();
4968940SRandy.Fishel@Sun.COM 
4978940SRandy.Fishel@Sun.COM 	/*
4988940SRandy.Fishel@Sun.COM 	 * Determine home directory of the user.
4998940SRandy.Fishel@Sun.COM 	 */
5008940SRandy.Fishel@Sun.COM 	if ((home_dir = getenv("HOME")) == NULL) {
5018940SRandy.Fishel@Sun.COM 		if ((pwd = getpwuid(uid)) == NULL) {
502*11053SSurya.Prakki@Sun.COM 			(void) printf(gettext("Error: unable to get passwd "
5038940SRandy.Fishel@Sun.COM 			    "entry for user.\n"));
5048940SRandy.Fishel@Sun.COM 			exit(1);
5058940SRandy.Fishel@Sun.COM 		}
5068940SRandy.Fishel@Sun.COM 		home_dir = pwd->pw_dir;
5078940SRandy.Fishel@Sun.COM 	}
5088940SRandy.Fishel@Sun.COM 	if ((strlen(home_dir) + sizeof ("/.Xauthority")) >= MAXPATHLEN) {
509*11053SSurya.Prakki@Sun.COM 		(void) printf(gettext("Error: path to home directory is too "
5108940SRandy.Fishel@Sun.COM 		    "long.\n"));
5118940SRandy.Fishel@Sun.COM 		exit(1);
5128940SRandy.Fishel@Sun.COM 	}
5138940SRandy.Fishel@Sun.COM 
5148940SRandy.Fishel@Sun.COM 	/*
5158940SRandy.Fishel@Sun.COM 	 * If there is a .Xauthority file in home directory, reference it.
5168940SRandy.Fishel@Sun.COM 	 */
5178940SRandy.Fishel@Sun.COM 	/*LINTED*/
5188940SRandy.Fishel@Sun.COM 	(void) sprintf(filepath, "%s/.Xauthority", home_dir);
5198940SRandy.Fishel@Sun.COM 	if (stat(filepath, &stat_buf) == 0)
5208940SRandy.Fishel@Sun.COM 		return (strcat(xauthority, filepath));
5218940SRandy.Fishel@Sun.COM 
5228940SRandy.Fishel@Sun.COM 	/*
5238940SRandy.Fishel@Sun.COM 	 * If Xsession can not access user's home directory, it creates the
5248940SRandy.Fishel@Sun.COM 	 * Xauthority file in "/var/dt/tmp" directory.  Since the exact
5258940SRandy.Fishel@Sun.COM 	 * name of the Xauthority is not known, search the directory and
5268940SRandy.Fishel@Sun.COM 	 * find the last changed file that starts with ".Xauth" and owned
5278940SRandy.Fishel@Sun.COM 	 * by the user.  Hopefully, that is the valid Xauthority file for
5288940SRandy.Fishel@Sun.COM 	 * the current X session.
5298940SRandy.Fishel@Sun.COM 	 */
5308940SRandy.Fishel@Sun.COM 	if ((dirp = opendir(DT_TMP)) == NULL)
5318940SRandy.Fishel@Sun.COM 		return (xauthority);
5328940SRandy.Fishel@Sun.COM 
5338940SRandy.Fishel@Sun.COM 	while ((dp = readdir(dirp)) != NULL) {
5348940SRandy.Fishel@Sun.COM 		if (strstr(dp->d_name, ".Xauth") != NULL) {
5358940SRandy.Fishel@Sun.COM 			/*LINTED*/
5368940SRandy.Fishel@Sun.COM 			(void) sprintf(filepath, "%s/%s", DT_TMP, dp->d_name);
5378940SRandy.Fishel@Sun.COM 			if (stat(filepath, &stat_buf) == -1)
5388940SRandy.Fishel@Sun.COM 				continue;
5398940SRandy.Fishel@Sun.COM 			if (stat_buf.st_uid != uid)
5408940SRandy.Fishel@Sun.COM 				continue;
5418940SRandy.Fishel@Sun.COM 			if (stat_buf.st_ctime > latest) {
5428940SRandy.Fishel@Sun.COM 				(void) strcpy(xauth, filepath);
5438940SRandy.Fishel@Sun.COM 				latest = stat_buf.st_ctime;
5448940SRandy.Fishel@Sun.COM 			}
5458940SRandy.Fishel@Sun.COM 		}
5468940SRandy.Fishel@Sun.COM 	}
5478940SRandy.Fishel@Sun.COM 	(void) closedir(dirp);
5488940SRandy.Fishel@Sun.COM 
5498940SRandy.Fishel@Sun.COM 	return (strcat(xauthority, xauth));
5508940SRandy.Fishel@Sun.COM }
5518940SRandy.Fishel@Sun.COM 
5528940SRandy.Fishel@Sun.COM /*
5538940SRandy.Fishel@Sun.COM  * suspend can be called in following ways:
5548940SRandy.Fishel@Sun.COM  *	1. from daemon (powerd) for auto-shutdown.
5558940SRandy.Fishel@Sun.COM  *		a. there might be a OW/CDE environment
5568940SRandy.Fishel@Sun.COM  *		b. there might not be any windowing environment
5578940SRandy.Fishel@Sun.COM  *      2. by a user entered command.
5588940SRandy.Fishel@Sun.COM  *		a. the command can be entered from a cmdtool type OW/CDE tool
5598940SRandy.Fishel@Sun.COM  *		b. the command can be entered by a user logged in on a dumb
5608940SRandy.Fishel@Sun.COM  *		   terminal.
5618940SRandy.Fishel@Sun.COM  *			i) there might be a OW/CDE running on console
5628940SRandy.Fishel@Sun.COM  *			   and we have permission to talk to it.
5638940SRandy.Fishel@Sun.COM  *			ii) there is no OW/CDE running on console or we
5648940SRandy.Fishel@Sun.COM  *			   don't have permission to talk to it or console
5658940SRandy.Fishel@Sun.COM  *			   itself is the dumb terminal we have logged into.
5668940SRandy.Fishel@Sun.COM  *
5678940SRandy.Fishel@Sun.COM  * In main(), we decide on the correct case and call appropriate functions.
5688940SRandy.Fishel@Sun.COM  */
5698940SRandy.Fishel@Sun.COM 
5708940SRandy.Fishel@Sun.COM int
main(int argc,char ** argv)5718940SRandy.Fishel@Sun.COM main(int argc, char **argv)
5728940SRandy.Fishel@Sun.COM {
5738940SRandy.Fishel@Sun.COM 	int		c;
5748940SRandy.Fishel@Sun.COM 	char		display_name[MAXNAMELEN + 9] = "DISPLAY=";
5758940SRandy.Fishel@Sun.COM 	char		xauthority[MAXPATHLEN + 12] = "XAUTHORITY=";
5768940SRandy.Fishel@Sun.COM 	struct passwd 	*pw;
5778940SRandy.Fishel@Sun.COM 
5788940SRandy.Fishel@Sun.COM 	(void *) signal(SIGHUP, SIG_IGN);
5798940SRandy.Fishel@Sun.COM 	(void *) signal(SIGINT, SIG_IGN);
5808940SRandy.Fishel@Sun.COM 	(void *) signal(SIGQUIT, SIG_IGN);
5818940SRandy.Fishel@Sun.COM 	(void *) signal(SIGTSTP, SIG_IGN);
5828940SRandy.Fishel@Sun.COM 	(void *) signal(SIGTTIN, SIG_IGN);
5838940SRandy.Fishel@Sun.COM 	(void *) signal(SIGTTOU, SIG_IGN);
5848940SRandy.Fishel@Sun.COM 
5858940SRandy.Fishel@Sun.COM 	/*
5868940SRandy.Fishel@Sun.COM 	 * If suspend is invoked from a daemon (case 1 above), it
5878940SRandy.Fishel@Sun.COM 	 * will not have a working stdin, stdout and stderr. We need
5888940SRandy.Fishel@Sun.COM 	 * these to print proper error messages and possibly get user
5898940SRandy.Fishel@Sun.COM 	 * input. We attach them to console and hope that attachment
5908940SRandy.Fishel@Sun.COM 	 * works.
5918940SRandy.Fishel@Sun.COM 	 */
5928940SRandy.Fishel@Sun.COM 	if (ttyname(0) == NULL) {
5938940SRandy.Fishel@Sun.COM 		no_tty = 1;
594*11053SSurya.Prakki@Sun.COM 		(void) dup2(open("/dev/console", O_RDONLY), 0);
595*11053SSurya.Prakki@Sun.COM 		(void) dup2(open("/dev/console", O_WRONLY), 1);
596*11053SSurya.Prakki@Sun.COM 		(void) dup2(open("/dev/console", O_WRONLY), 2);
5978940SRandy.Fishel@Sun.COM 	}
5988940SRandy.Fishel@Sun.COM 
5998940SRandy.Fishel@Sun.COM 	while ((c = getopt(argc, argv, "fnxhtd:")) != EOF) {
6008940SRandy.Fishel@Sun.COM 		switch (c) {
6018940SRandy.Fishel@Sun.COM 			case 'f':
6028940SRandy.Fishel@Sun.COM 				/*
6038940SRandy.Fishel@Sun.COM 				 * Force machine to poweroff if
6048940SRandy.Fishel@Sun.COM 				 * suspend fails
6058940SRandy.Fishel@Sun.COM 				 */
6068940SRandy.Fishel@Sun.COM 				flags |= FORCE;
6078940SRandy.Fishel@Sun.COM 				break;
6088940SRandy.Fishel@Sun.COM 			case 'n':
6098940SRandy.Fishel@Sun.COM 				/* No warning popups - Obsolete */
6108940SRandy.Fishel@Sun.COM 				flags |= NO_WARN;
6118940SRandy.Fishel@Sun.COM 				break;
6128940SRandy.Fishel@Sun.COM 			case 'x':
6138940SRandy.Fishel@Sun.COM 				/* Don't try to screenlock */
6148940SRandy.Fishel@Sun.COM 				flags |= NO_XLOCK;
6158940SRandy.Fishel@Sun.COM 				break;
6168940SRandy.Fishel@Sun.COM 			case 'h':
6178940SRandy.Fishel@Sun.COM 				/* Do a shutdown instead of suspend */
6188940SRandy.Fishel@Sun.COM 				flags |= SHUTDOWN;
6198940SRandy.Fishel@Sun.COM 				break;
6208940SRandy.Fishel@Sun.COM 			case 'd':
6218940SRandy.Fishel@Sun.COM 				/* Needswork */
6228940SRandy.Fishel@Sun.COM 				/* Set the DISPLAY value in the environment */
6238940SRandy.Fishel@Sun.COM 				if (strlen(optarg) >= MAXNAMELEN) {
6248940SRandy.Fishel@Sun.COM 					(void) printf(gettext("Error: "
6258940SRandy.Fishel@Sun.COM 					    "display name is too long.\n"));
6268940SRandy.Fishel@Sun.COM 					return (1);
6278940SRandy.Fishel@Sun.COM 				}
6288940SRandy.Fishel@Sun.COM 				(void) strcat(display_name, optarg);
6298940SRandy.Fishel@Sun.COM 				if (putenv(display_name) != 0) {
6308940SRandy.Fishel@Sun.COM 					(void) printf(gettext("Error: "
6318940SRandy.Fishel@Sun.COM 					    "unable to set DISPLAY "
6328940SRandy.Fishel@Sun.COM 					    "environment variable.\n"));
6338940SRandy.Fishel@Sun.COM 					return (1);
6348940SRandy.Fishel@Sun.COM 				}
6358940SRandy.Fishel@Sun.COM 				break;
6368940SRandy.Fishel@Sun.COM 			case 't':
6378940SRandy.Fishel@Sun.COM 				/* Test, don't actually do any operation */
6388940SRandy.Fishel@Sun.COM 				flags |= TEST;
6398940SRandy.Fishel@Sun.COM 				break;
6408940SRandy.Fishel@Sun.COM 			default:
6418940SRandy.Fishel@Sun.COM 				(void) printf(gettext("USAGE: suspend "
6428940SRandy.Fishel@Sun.COM 				    "[-fnxh] [-d <display>]\n"));
6438940SRandy.Fishel@Sun.COM 				return (1);
6448940SRandy.Fishel@Sun.COM 				break;
6458940SRandy.Fishel@Sun.COM 		}
6468940SRandy.Fishel@Sun.COM 	}
6478940SRandy.Fishel@Sun.COM 
6488940SRandy.Fishel@Sun.COM 	/*
6498940SRandy.Fishel@Sun.COM 	 * The action of pressing power key and power button on a MOU-3 machine
6508940SRandy.Fishel@Sun.COM 	 * causes suspend being invoked with SYSSUSPENDDODEFAULT
6518940SRandy.Fishel@Sun.COM 	 * enviromental variable set - indicating the default action is machine
6528940SRandy.Fishel@Sun.COM 	 * dependent: for MOU-3 type machine, "LowPower" mode is the default,
6538940SRandy.Fishel@Sun.COM 	 * for all the rest, "Suspend" is the default.  Existing suspend
6548940SRandy.Fishel@Sun.COM 	 * flags works the same.
6558940SRandy.Fishel@Sun.COM 	 */
6568940SRandy.Fishel@Sun.COM 	if (getenv("SYSSUSPENDDODEFAULT"))
6578940SRandy.Fishel@Sun.COM 		if (is_mou3())
6588940SRandy.Fishel@Sun.COM 			flags |= LOWPOWER;
6598940SRandy.Fishel@Sun.COM 
6608940SRandy.Fishel@Sun.COM 	if ((flags & FORCE) && (flags & LOWPOWER))
6618940SRandy.Fishel@Sun.COM 		flags &= ~LOWPOWER;
6628940SRandy.Fishel@Sun.COM 
6638940SRandy.Fishel@Sun.COM 	/*
6648940SRandy.Fishel@Sun.COM 	 * Flag "-h" overrides flag "-f".
6658940SRandy.Fishel@Sun.COM 	 */
6668940SRandy.Fishel@Sun.COM 	if ((flags & SHUTDOWN) && (flags & FORCE))
6678940SRandy.Fishel@Sun.COM 		flags &= ~(FORCE | LOWPOWER);
6688940SRandy.Fishel@Sun.COM 
6698940SRandy.Fishel@Sun.COM 	if (flags & FORCE)
6708940SRandy.Fishel@Sun.COM 		flags |= NO_WARN;
6718940SRandy.Fishel@Sun.COM 
6728940SRandy.Fishel@Sun.COM 	/*
6738940SRandy.Fishel@Sun.COM 	 * Check initally if the user has the authorizations to
6748940SRandy.Fishel@Sun.COM 	 * do either a suspend or shutdown.  pm_suspend() will also
6758940SRandy.Fishel@Sun.COM 	 * make this test, so we could defer till then, but if we
6768940SRandy.Fishel@Sun.COM 	 * do it now, we at least prevent a lot of unneeded setup.
6778940SRandy.Fishel@Sun.COM 	 */
6788940SRandy.Fishel@Sun.COM 	pw = getpwuid(getuid());
679*11053SSurya.Prakki@Sun.COM 	(void) strncpy(user, pw->pw_name, NMAX);
6808940SRandy.Fishel@Sun.COM 
6818940SRandy.Fishel@Sun.COM 	if ((flags & (FORCE|SHUTDOWN)) &&
6828940SRandy.Fishel@Sun.COM 	    (chkauthattr(AUTHNAME_SHUTDOWN, pw->pw_name) != 1)) {
6838940SRandy.Fishel@Sun.COM 		(void) printf(gettext("User does not have correct "
6848940SRandy.Fishel@Sun.COM 		    "authorizations to shutdown the machine.\n"));
6858940SRandy.Fishel@Sun.COM 		exit(1);
6868940SRandy.Fishel@Sun.COM 	}
6878940SRandy.Fishel@Sun.COM 	if (!(flags & SHUTDOWN) &&
6888940SRandy.Fishel@Sun.COM 	    (chkauthattr(AUTHNAME_SUSPEND, pw->pw_name) != 1)) {
6898940SRandy.Fishel@Sun.COM 		(void) printf(gettext("User does not have correct "
6908940SRandy.Fishel@Sun.COM 		    "authorizations to suspend.\n"));
6918940SRandy.Fishel@Sun.COM 		exit(1);
6928940SRandy.Fishel@Sun.COM 	}
6938940SRandy.Fishel@Sun.COM 
6948940SRandy.Fishel@Sun.COM 	/*
6958940SRandy.Fishel@Sun.COM 	 * If we are only shutting down, there isn't much to do, just
6968940SRandy.Fishel@Sun.COM 	 * call pm_poweroff(), and let it do all the work.
6978940SRandy.Fishel@Sun.COM 	 */
6988940SRandy.Fishel@Sun.COM 	if (flags & SHUTDOWN) {
6998940SRandy.Fishel@Sun.COM 		/*
7008940SRandy.Fishel@Sun.COM 		 * pm_poweroff either powers off or exits,
7018940SRandy.Fishel@Sun.COM 		 * so there is no return.
7028940SRandy.Fishel@Sun.COM 		 */
7038940SRandy.Fishel@Sun.COM 		if (flags & TEST) {
7048940SRandy.Fishel@Sun.COM 			(void) printf("TEST: This machine would have "
7058940SRandy.Fishel@Sun.COM 			    "powered off\n");
7068940SRandy.Fishel@Sun.COM 			exit(1);
7078940SRandy.Fishel@Sun.COM 		} else {
7088940SRandy.Fishel@Sun.COM 			pm_poweroff();
7098940SRandy.Fishel@Sun.COM 		}
7108940SRandy.Fishel@Sun.COM 		/* NOTREACHED */
7118940SRandy.Fishel@Sun.COM 	}
7128940SRandy.Fishel@Sun.COM 
7138940SRandy.Fishel@Sun.COM 	/*
7148940SRandy.Fishel@Sun.COM 	 * If XAUTHORITY environment variable is not set, try to set
7158940SRandy.Fishel@Sun.COM 	 * one up.
7168940SRandy.Fishel@Sun.COM 	 */
7178940SRandy.Fishel@Sun.COM 	if (getenv("XAUTHORITY") == NULL)
7188940SRandy.Fishel@Sun.COM 		(void) putenv(get_xauthority(xauthority));
7198940SRandy.Fishel@Sun.COM 
7208940SRandy.Fishel@Sun.COM 	/*
7218940SRandy.Fishel@Sun.COM 	 * In case of "suspend" being called from daemon "powerd",
7228940SRandy.Fishel@Sun.COM 	 * signal SIGALRM is blocked so use "sigset()" instead of "signal()".
7238940SRandy.Fishel@Sun.COM 	 */
7248940SRandy.Fishel@Sun.COM 	(void *) sigset(SIGALRM, alarm_handler);
7258940SRandy.Fishel@Sun.COM 
7268940SRandy.Fishel@Sun.COM 	/* Call the "suspend" function to do the last of the work */
7278940SRandy.Fishel@Sun.COM 	pm_suspend();
7288940SRandy.Fishel@Sun.COM 
7298940SRandy.Fishel@Sun.COM 	if (refresh_dt() == -1) {
730*11053SSurya.Prakki@Sun.COM 		(void) printf("%s: Failed to refresh screen.\n", argv[0]);
7318940SRandy.Fishel@Sun.COM 		return (1);
7328940SRandy.Fishel@Sun.COM 	}
7338940SRandy.Fishel@Sun.COM 	return (0);
7348940SRandy.Fishel@Sun.COM }
7358940SRandy.Fishel@Sun.COM 
7368940SRandy.Fishel@Sun.COM #include <sys/pm.h>
7378940SRandy.Fishel@Sun.COM 
7388940SRandy.Fishel@Sun.COM /*
7398940SRandy.Fishel@Sun.COM  * Note that some of these functions are more relevant to Sparc platforms,
7408940SRandy.Fishel@Sun.COM  * but they do function properly on other platforms, they just don't do
7418940SRandy.Fishel@Sun.COM  * as much.
7428940SRandy.Fishel@Sun.COM  */
7438940SRandy.Fishel@Sun.COM /*
7448940SRandy.Fishel@Sun.COM  * bringto_lowpower()
7458940SRandy.Fishel@Sun.COM  * This tells the PM framework to put the devices it controls in an idle
7468940SRandy.Fishel@Sun.COM  * state.  The framework only complains if a device that *must* be idle
7478940SRandy.Fishel@Sun.COM  * doesn't succeed in getting there.
7488940SRandy.Fishel@Sun.COM  */
7498940SRandy.Fishel@Sun.COM static int
bringto_lowpower()7508940SRandy.Fishel@Sun.COM bringto_lowpower()
7518940SRandy.Fishel@Sun.COM {
7528940SRandy.Fishel@Sun.COM 	int	fd;
7538940SRandy.Fishel@Sun.COM 
7548940SRandy.Fishel@Sun.COM 	if ((fd = open("/dev/pm", O_RDWR)) < 0) {
755*11053SSurya.Prakki@Sun.COM 		(void) printf(gettext("Can't open /dev/pm\n"));
7568940SRandy.Fishel@Sun.COM 		return (-1);
7578940SRandy.Fishel@Sun.COM 	}
7588940SRandy.Fishel@Sun.COM 
7598940SRandy.Fishel@Sun.COM 	if (ioctl(fd, PM_IDLE_DOWN, NULL) < 0) {
760*11053SSurya.Prakki@Sun.COM 		(void) printf(gettext("Failed to bring system "
761*11053SSurya.Prakki@Sun.COM 		    "to low power mode.\n"));
762*11053SSurya.Prakki@Sun.COM 		(void) close(fd);
7638940SRandy.Fishel@Sun.COM 		return (-1);
7648940SRandy.Fishel@Sun.COM 	}
765*11053SSurya.Prakki@Sun.COM 	(void) close(fd);
7668940SRandy.Fishel@Sun.COM 	return (0);
7678940SRandy.Fishel@Sun.COM }
7688940SRandy.Fishel@Sun.COM 
7698940SRandy.Fishel@Sun.COM #include <sys/cpr.h>
7708940SRandy.Fishel@Sun.COM 
7718940SRandy.Fishel@Sun.COM /*
7728940SRandy.Fishel@Sun.COM  * Though this test is predominantly used on Sparc, it will run on other
7738940SRandy.Fishel@Sun.COM  * platforms, and might be usefull one day on those.
7748940SRandy.Fishel@Sun.COM  */
7758940SRandy.Fishel@Sun.COM static int
is_mou3()7768940SRandy.Fishel@Sun.COM is_mou3()
7778940SRandy.Fishel@Sun.COM {
7788940SRandy.Fishel@Sun.COM 	struct cprconfig	cf;
7798940SRandy.Fishel@Sun.COM 	int			fd;
7808940SRandy.Fishel@Sun.COM 	int			found = 0;
7818940SRandy.Fishel@Sun.COM 
7828940SRandy.Fishel@Sun.COM 	if ((fd = open(CPR_CONFIG, O_RDONLY)) < 0) {
783*11053SSurya.Prakki@Sun.COM 		(void) printf(gettext("Can't open /etc/.cpr_config file."));
7848940SRandy.Fishel@Sun.COM 		return (found);
7858940SRandy.Fishel@Sun.COM 	}
7868940SRandy.Fishel@Sun.COM 
7878940SRandy.Fishel@Sun.COM 	if (read(fd, (void *) &cf, sizeof (cf)) != sizeof (cf)) {
788*11053SSurya.Prakki@Sun.COM 		(void) printf(gettext("Can't read /etc/.cpr_config file."));
7898940SRandy.Fishel@Sun.COM 	} else {
7908940SRandy.Fishel@Sun.COM 		found = cf.is_autopm_default;
7918940SRandy.Fishel@Sun.COM 	}
7928940SRandy.Fishel@Sun.COM 
793*11053SSurya.Prakki@Sun.COM 	(void) close(fd);
7948940SRandy.Fishel@Sun.COM 	return (found);
7958940SRandy.Fishel@Sun.COM }
7968940SRandy.Fishel@Sun.COM 
7978940SRandy.Fishel@Sun.COM /*
7988940SRandy.Fishel@Sun.COM  * Reauthenticate the user on return from suspend.
7998940SRandy.Fishel@Sun.COM  * This is here and not in the PAM-specific file, as there are
8008940SRandy.Fishel@Sun.COM  * items specific to sys-suspend, and not generic to PAM.  This may
8018940SRandy.Fishel@Sun.COM  * become part of a future PM library.  The audit handle is passed,
8028940SRandy.Fishel@Sun.COM  * as the pm_suspend code actually starts an audit session, so it
8038940SRandy.Fishel@Sun.COM  * makes sense to just continue to use it.  If it were separated
8048940SRandy.Fishel@Sun.COM  * from the pm_suspend code, it will need to open a new session.
8058940SRandy.Fishel@Sun.COM  */
8068940SRandy.Fishel@Sun.COM #define	DEF_ATTEMPTS	3
8078940SRandy.Fishel@Sun.COM static void
pm_do_auth(adt_session_data_t * ah)8088940SRandy.Fishel@Sun.COM pm_do_auth(adt_session_data_t *ah)
8098940SRandy.Fishel@Sun.COM {
8108940SRandy.Fishel@Sun.COM 	pam_handle_t	*pm_pamh;
8118940SRandy.Fishel@Sun.COM 	int		err;
8128940SRandy.Fishel@Sun.COM 	int		pam_flag = 0;
8138940SRandy.Fishel@Sun.COM 	int		chpasswd_tries;
8148940SRandy.Fishel@Sun.COM 	struct pam_conv pam_conv = {pam_tty_conv, NULL};
8158940SRandy.Fishel@Sun.COM 
8168940SRandy.Fishel@Sun.COM 	if (user[0] == '\0')
8178940SRandy.Fishel@Sun.COM 		return;
8188940SRandy.Fishel@Sun.COM 
8198940SRandy.Fishel@Sun.COM 	if ((err = pam_start("sys-suspend", user, &pam_conv,
8208940SRandy.Fishel@Sun.COM 	    &pm_pamh)) != PAM_SUCCESS)
8218940SRandy.Fishel@Sun.COM 		return;
8228940SRandy.Fishel@Sun.COM 
8238940SRandy.Fishel@Sun.COM 	pam_flag = PAM_DISALLOW_NULL_AUTHTOK;
8248940SRandy.Fishel@Sun.COM 
8258940SRandy.Fishel@Sun.COM 	do {
8268940SRandy.Fishel@Sun.COM 		err = pam_authenticate(pm_pamh, pam_flag);
8278940SRandy.Fishel@Sun.COM 
8288940SRandy.Fishel@Sun.COM 		if (err == PAM_SUCCESS) {
8298940SRandy.Fishel@Sun.COM 			err = pam_acct_mgmt(pm_pamh, pam_flag);
8308940SRandy.Fishel@Sun.COM 
8318940SRandy.Fishel@Sun.COM 			if (err == PAM_NEW_AUTHTOK_REQD) {
8328940SRandy.Fishel@Sun.COM 				chpasswd_tries = 0;
8338940SRandy.Fishel@Sun.COM 
8348940SRandy.Fishel@Sun.COM 				do {
8358940SRandy.Fishel@Sun.COM 					err = pam_chauthtok(pm_pamh,
8368940SRandy.Fishel@Sun.COM 					    PAM_CHANGE_EXPIRED_AUTHTOK);
8378940SRandy.Fishel@Sun.COM 					chpasswd_tries++;
8388940SRandy.Fishel@Sun.COM 
8398940SRandy.Fishel@Sun.COM 				} while ((err == PAM_AUTHTOK_ERR ||
8408940SRandy.Fishel@Sun.COM 				    err == PAM_TRY_AGAIN) &&
8418940SRandy.Fishel@Sun.COM 				    chpasswd_tries < DEF_ATTEMPTS);
8428940SRandy.Fishel@Sun.COM 				pm_audit_event(ah, ADT_passwd, err);
8438940SRandy.Fishel@Sun.COM 			}
8448940SRandy.Fishel@Sun.COM 			err = pam_setcred(pm_pamh, PAM_REFRESH_CRED);
8458940SRandy.Fishel@Sun.COM 		}
8468940SRandy.Fishel@Sun.COM 		if (err != PAM_SUCCESS) {
8478940SRandy.Fishel@Sun.COM 			(void) fprintf(stdout, "%s\n",
8488940SRandy.Fishel@Sun.COM 			    pam_strerror(pm_pamh, err));
8498940SRandy.Fishel@Sun.COM 			pm_audit_event(ah, ADT_screenunlock, err);
8508940SRandy.Fishel@Sun.COM 		}
8518940SRandy.Fishel@Sun.COM 	} while (err != PAM_SUCCESS);
8528940SRandy.Fishel@Sun.COM 	pm_audit_event(ah, ADT_passwd, 0);
8538940SRandy.Fishel@Sun.COM 
8548940SRandy.Fishel@Sun.COM 	(void) pam_end(pm_pamh, err);
8558940SRandy.Fishel@Sun.COM }
856