Beispiel #1
0
/*
 * PM service for other drivers.
 */
int
pm_set_power(int state)
{
    int error;

    switch (state) {
    case PWR_ON:
        error = pm_resume();
        break;
    case PWR_SUSPEND:
        error = pm_suspend();
        break;
    case PWR_OFF:
        error = pm_poweroff();
        break;
    case PWR_REBOOT:
        error = pm_reboot();
        break;
    default:
        error = EINVAL;
    }
    return error;
}
Beispiel #2
0
/*
 * PM event notification.
 */
void
pm_notify(int event)
{
    struct pm_softc *sc = pm_softc;
    int s;

    if (event == PME_USER_ACTIVITY) {
        /*
         * Reload suspend timer for user activity.
         */
        s = splhigh();
        sc->idlecnt = 0;
        splx(s);

        if (!sc->lcd_on)
            pm_lcd_on();
        return;
    }

    DPRINTF(("pm: notify %d\n", event));

    if (sc->powtask != TASK_NULL) {
        /*
         * Power server exists.
         */
        switch (event) {
        case PME_PWRBTN_PRESS:
        case PME_SLPBTN_PRESS:
        case PME_LOW_BATTERY:
        case PME_LCD_CLOSE:
            /*
             * Post an exception to the power server.
             * Then, the power server will query PM event.
             */
            sc->lastevt = event;
            DPRINTF(("pm: post %d\n", event));
            exception_post(sc->powtask, SIGPWR);
            break;
        case PME_LCD_OPEN:
            sc->lastevt = PME_NO_EVENT;
            pm_lcd_on();
            break;
        }
    } else {
        /*
         * No power server.
         * Map power event to default action.
         */
        switch (event) {
        case PME_PWRBTN_PRESS:
            pm_poweroff();
            break;
        case PME_SLPBTN_PRESS:
        case PME_LOW_BATTERY:
            pm_suspend();
            break;
        case PME_LCD_OPEN:
            pm_lcd_on();
            break;
        case PME_LCD_CLOSE:
            pm_lcd_off();
            break;
        }
    }
}
int
main(int argc, char **argv)
{
	int		c;
	char		display_name[MAXNAMELEN + 9] = "DISPLAY=";
	char		xauthority[MAXPATHLEN + 12] = "XAUTHORITY=";
	struct passwd 	*pw;

	(void) signal(SIGHUP, SIG_IGN);
	(void) signal(SIGINT, SIG_IGN);
	(void) signal(SIGQUIT, SIG_IGN);
	(void) signal(SIGTSTP, SIG_IGN);
	(void) signal(SIGTTIN, SIG_IGN);
	(void) signal(SIGTTOU, SIG_IGN);

	/*
	 * If suspend is invoked from a daemon (case 1 above), it
	 * will not have a working stdin, stdout and stderr. We need
	 * these to print proper error messages and possibly get user
	 * input. We attach them to console and hope that attachment
	 * works.
	 */
	if (ttyname(0) == NULL) {
		no_tty = 1;
		(void) dup2(open("/dev/console", O_RDONLY), 0);
		(void) dup2(open("/dev/console", O_WRONLY), 1);
		(void) dup2(open("/dev/console", O_WRONLY), 2);
	}

	while ((c = getopt(argc, argv, "fnxhtd:")) != EOF) {
		switch (c) {
			case 'f':
				/*
				 * Force machine to poweroff if
				 * suspend fails
				 */
				flags |= FORCE;
				break;
			case 'n':
				/* No warning popups - Obsolete */
				flags |= NO_WARN;
				break;
			case 'x':
				/* Don't try to screenlock */
				flags |= NO_XLOCK;
				break;
			case 'h':
				/* Do a shutdown instead of suspend */
				flags |= SHUTDOWN;
				break;
			case 'd':
				/* Needswork */
				/* Set the DISPLAY value in the environment */
				if (strlen(optarg) >= MAXNAMELEN) {
					(void) printf(gettext("Error: "
					    "display name is too long.\n"));
					return (1);
				}
				(void) strcat(display_name, optarg);
				if (putenv(display_name) != 0) {
					(void) printf(gettext("Error: "
					    "unable to set DISPLAY "
					    "environment variable.\n"));
					return (1);
				}
				break;
			case 't':
				/* Test, don't actually do any operation */
				flags |= TEST;
				break;
			default:
				(void) printf(gettext("USAGE: suspend "
				    "[-fnxh] [-d <display>]\n"));
				return (1);
		}
	}

	/*
	 * The action of pressing power key and power button on a MOU-3 machine
	 * causes suspend being invoked with SYSSUSPENDDODEFAULT
	 * enviromental variable set - indicating the default action is machine
	 * dependent: for MOU-3 type machine, "LowPower" mode is the default,
	 * for all the rest, "Suspend" is the default.  Existing suspend
	 * flags works the same.
	 */
	if (getenv("SYSSUSPENDDODEFAULT"))
		if (is_mou3())
			flags |= LOWPOWER;

	if ((flags & FORCE) && (flags & LOWPOWER))
		flags &= ~LOWPOWER;

	/*
	 * Flag "-h" overrides flag "-f".
	 */
	if ((flags & SHUTDOWN) && (flags & FORCE))
		flags &= ~(FORCE | LOWPOWER);

	if (flags & FORCE)
		flags |= NO_WARN;

	/*
	 * Check initally if the user has the authorizations to
	 * do either a suspend or shutdown.  pm_suspend() will also
	 * make this test, so we could defer till then, but if we
	 * do it now, we at least prevent a lot of unneeded setup.
	 */
	pw = getpwuid(getuid());
	(void) strncpy(user, pw->pw_name, NMAX);

	if ((flags & (FORCE|SHUTDOWN)) &&
	    (chkauthattr(AUTHNAME_SHUTDOWN, pw->pw_name) != 1)) {
		(void) printf(gettext("User does not have correct "
		    "authorizations to shutdown the machine.\n"));
		exit(1);
	}
	if (!(flags & SHUTDOWN) &&
	    (chkauthattr(AUTHNAME_SUSPEND, pw->pw_name) != 1)) {
		(void) printf(gettext("User does not have correct "
		    "authorizations to suspend.\n"));
		exit(1);
	}

	/*
	 * If we are only shutting down, there isn't much to do, just
	 * call pm_poweroff(), and let it do all the work.
	 */
	if (flags & SHUTDOWN) {
		/*
		 * pm_poweroff either powers off or exits,
		 * so there is no return.
		 */
		if (flags & TEST) {
			(void) printf("TEST: This machine would have "
			    "powered off\n");
			exit(1);
		} else {
			pm_poweroff();
		}
		/* NOTREACHED */
	}

	/*
	 * If XAUTHORITY environment variable is not set, try to set
	 * one up.
	 */
	if (getenv("XAUTHORITY") == NULL)
		(void) putenv(get_xauthority(xauthority));

	/*
	 * In case of "suspend" being called from daemon "powerd",
	 * signal SIGALRM is blocked so use "sigset()" instead of "signal()".
	 */
	(void) sigset(SIGALRM, alarm_handler);

	/* Call the "suspend" function to do the last of the work */
	pm_suspend();

	if (refresh_dt() == -1) {
		(void) printf("%s: Failed to refresh screen.\n", argv[0]);
		return (1);
	}
	return (0);
}
/*
 * This entry point _should_ be the common entry to suspend.  It is in
 * it's entirety here, but would be best moved to libpower when that
 * is available.
 */
static void
pm_suspend(void)
{
	int			cprarg = AD_SUSPEND;
	enum adt_uadmin_fcn	fcn_id = ADT_FCN;
	au_event_t		event_id = ADT_uadmin_freeze;
	adt_event_data_t	*event = NULL; /* event to be generated */
	adt_session_data_t	*ah = NULL;  /* audit session handle */

	/*
	 * Does the user have permission to use this command?
	 */
	if (chkauthattr(AUTHNAME_SUSPEND, user) != 1) {
		(void) printf(gettext("User %s does not have correct "
		    "authorizations to suspend this machine.\n"), user);
		exit(1);
	}

	if (flags & LOWPOWER) {
		if (bringto_lowpower() == -1) {
			(void) printf(gettext("LowPower Failed\n"));
			exit(1);
		}
	} else if (flags & TEST) {
		/*
		 * Test mode, do checks as if a real suspend, but
		 * don't actually do the suspend.
		 */
		/* Check if suspend is supported */
		if (pm_check_suspend() == -1) {
			suspend_error(errno);
		}

		(void) printf(gettext("TEST: Suspend would have been"
		    " performed\n"));

	} else {
		/* Check if suspend is supported */
		if (pm_check_suspend() == -1) {
			suspend_error(errno);
		}

		/*
		 * We are about to suspend this machine, try and
		 * lock the screen.  We don't really care if this
		 * succeeds or not, but that we actually tried. We
		 * also know that we have sufficient privileges to
		 * be here, so we lock the screen now, even if
		 * suspend actually fails.
		 * Note that garbage is sometimes displayed, and
		 * we don't really care about it, so we toss all
		 * text response.
		 * it would also be good if there were another option
		 * instead of launcing a file, as the disk might be
		 * spun down if we are suspending due to idle.
		 */
		if (!(flags & NO_XLOCK)) {
			(void) system("/usr/bin/xdg-screensaver lock "
			    " >/dev/null 2>&1");
		}

		/* Time to do the actual deed!  */
		/*
		 * Before we actually suspend, we need to audit and
		 * "suspend" the audit files.
		 */
		/* set up audit session and event */
		if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) == 0) {
			if ((event = adt_alloc_event(ah, event_id)) != NULL) {
				event->adt_uadmin_freeze.fcn = fcn_id;
				event->adt_uadmin_freeze.mdep = NULL;
				if (adt_put_event(event, ADT_SUCCESS, 0) != 0) {
					(void) fprintf(stderr, gettext(
					    "%s: can't put audit event\n"),
					    argvl[0]);
				} else {
					wait_for_auqueue();
				}
			}
			(void) change_audit_file();
		} else {
			(void) fprintf(stderr, gettext(
			    "%s: can't start audit session\n"), argvl[0]);
		}

		if (uadmin(A_FREEZE, cprarg, 0) != 0) {
			(void) printf(gettext("Suspend Failed\n"));
			if (flags & FORCE) {
				/*
				 * Note, that if we actually poweroff,
				 * that the poweroff function will handle
				 * that audit trail, and the resume
				 * trail is effectively done.
				 */
				pm_poweroff();
			} else {
				/* suspend_error() will exit. */
				suspend_error(errno);
				/*
				 * Audit the suspend failure and
				 * reuse the event, but don't create one
				 * if we don't already have one.
				 */
				if (event != NULL) {
					(void) adt_put_event(event,
					    ADT_FAILURE, 0);
				}
			}
		}

		/*
		 * Write the thaw event.
		 */
		if (ah != NULL) {
			if ((event == NULL) &&
			    ((event = adt_alloc_event(ah, ADT_uadmin_thaw))
			    == NULL)) {
				(void) fprintf(stderr, gettext(
				    "%s: can't allocate thaw audit event\n"),
				    argvl[0]);
			} else {
				event->adt_uadmin_thaw.fcn = fcn_id;
				if (adt_put_event(event, ADT_SUCCESS, 0) != 0) {
					(void) fprintf(stderr, gettext(
					    "%s: can't put thaw audit event\n"),
					    argvl[0]);
				}
				(void) adt_free_event(event);
			}
		}
	}
	if ((no_tty ? 0 : 1) && !(flags & NO_XLOCK)) {
		pm_do_auth(ah);
	}

	(void) adt_end_session(ah);
}