1/*
2 * Copyright (c) 2010 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24#include <CoreFoundation/CoreFoundation.h>
25#include <CoreFoundation/CFDateFormatter.h>
26
27#include <SystemConfiguration/SystemConfiguration.h>
28#include <SystemConfiguration/SCValidation.h>
29
30#include <IOKit/IOMessage.h>
31#include <IOKit/pwr_mgt/IOPM.h>
32#include <IOKit/pwr_mgt/IOPMLib.h>
33#include <IOKit/pwr_mgt/IOPMLibPrivate.h>
34#include <IOKit/pwr_mgt/IOPMUPSPrivate.h>
35#include <IOKit/ps/IOPSKeys.h>
36#include <IOKit/ps/IOPowerSources.h>
37#include <IOKit/ps/IOPowerSourcesPrivate.h>
38#include <IOKit/IOCFSerialize.h>
39
40#if TARGET_OS_EMBEDDED
41    #define PLATFORM_HAS_DISPLAYSERVICES    0
42#else
43    #define PLATFORM_HAS_DISPLAYSERVICES    1
44    // ResentAmbientLightAll is defined in <DisplayServices/DisplayServices.h>
45    // and implemented by DisplayServices.framework
46    IOReturn DisplayServicesResetAmbientLightAll( void );
47#endif
48
49#include "../pmconfigd/PrivateLib.h"
50
51// dynamically mig generated
52#include "powermanagement.h"
53
54#include <IOKit/IOHibernatePrivate.h>
55#include <IOKit/IOReportTypes.h>
56#include <IOReport.h>
57
58#include <servers/bootstrap.h>
59#include <bootstrap_priv.h>
60#include <mach/mach_port.h>
61#include <string.h>
62#include <ctype.h>
63#include <unistd.h>
64#include <notify.h>
65#include <asl.h>
66#include <asl_private.h>
67#include <asl_core.h>
68#include <asl_file.h>
69#include <asl_store.h>
70#include <dirent.h>
71#include <sysexits.h>
72
73/*
74 * This is the command line interface to Energy Saver Preferences in
75 * /Library/Preferences/SystemConfiguration/com.apple.PowerManagement.plist
76 *
77 * pmset does many things, but here are a few of them:
78 *
79 Usage: pmset [-b | -c | -a] <action> <minutes> [[<opts>] <action> <minutes> ...]
80       -c adjust settings used while connected to a charger
81       -b adjust settings used when running off a battery
82       -a (default) adjust settings for both
83       <action> is one of: dim, sleep, spindown, slower, womp* (* flag = 1/0)
84       eg. pmset womp 1 -c dim 5 sleep 15 -b dim 3 spindown 5 sleep 8
85 */
86
87// Settings options
88#define ARG_DIM             "dim"
89#define ARG_DISPLAYSLEEP    "displaysleep"
90#define ARG_SLEEP           "sleep"
91#define ARG_SPINDOWN        "spindown"
92#define ARG_DISKSLEEP       "disksleep"
93#define ARG_WOMP            "womp"
94#define ARG_LIDWAKE         "lidwake"
95
96#define ARG_HIBERNATEMODE      "hibernatemode"
97#define ARG_HIBERNATEFILE      "hibernatefile"
98#define ARG_HIBERNATEFREERATIO "hibernatefreeratio"
99#define ARG_HIBERNATEFREETIME  "hibernatefreetime"
100#define ARG_AUTOPOWEROFF       "autopoweroff"
101#define ARG_AUTOPOWEROFFDELAY  "autopoweroffdelay"
102
103#define ARG_RING            "ring"
104#define ARG_AUTORESTART     "autorestart"
105#define ARG_WAKEONACCHANGE  "acwake"
106#define ARG_REDUCEBRIGHT    "lessbright"
107#define ARG_SLEEPUSESDIM    "halfdim"
108#define ARG_MOTIONSENSOR    "sms"
109#define ARG_MOTIONSENSOR2   "ams"
110#define ARG_TTYKEEPAWAKE    "ttyskeepawake"
111#define ARG_GPU             "gpuswitch"
112#define ARG_NETAVAILABLE    "networkoversleep"
113#define ARG_DEEPSLEEP       "standby"
114#define ARG_DEEPSLEEPDELAY  "standbydelay"
115#define ARG_DARKWAKES       "darkwakes"
116
117// Scheduling options
118#define ARG_SCHEDULE        "schedule"
119#define ARG_SCHED           "sched"
120#define ARG_REPEAT          "repeat"
121#define ARG_CANCEL          "cancel"
122#define ARG_RELATIVE        "relative"
123//#define ARG_SLEEP         "sleep"
124#define ARG_SHUTDOWN        "shutdown"
125#define ARG_RESTART         "restart"
126#define ARG_WAKE            "wake"
127#define ARG_POWERON         "poweron"
128#define ARG_WAKEORPOWERON   "wakeorpoweron"
129
130// UPS options
131#define ARG_HALTLEVEL       "haltlevel"
132#define ARG_HALTAFTER       "haltafter"
133#define ARG_HALTREMAIN      "haltremain"
134
135// get options
136#define ARG_CAP             "cap"
137#define ARG_DISK            "disk"
138#define ARG_CUSTOM          "custom"
139#define ARG_LIVE            "live"
140#define ARG_SCHED           "sched"
141#define ARG_UPS             "ups"
142#define ARG_SYS_PROFILES    "profiles"
143#define ARG_ADAPTER_AC      "ac"
144#define ARG_ADAPTER         "adapter"
145#define ARG_BATT            "batt"
146#define ARG_PS              "ps"
147#define ARG_PSLOG           "pslog"
148#define ARG_TRCOLUMNS       "trcolumns"
149#define ARG_BATTRAW         "rawbatt"
150#define ARG_PSRAW           "rawlog"
151#define ARG_THERM           "therm"
152#define ARG_THERMLOG        "thermlog"
153#define ARG_ASSERTIONS      "assertions"
154#define ARG_ASSERTIONSLOG   "assertionslog"
155#define ARG_SYSLOAD         "sysload"
156#define ARG_SYSLOADLOG      "sysloadlog"
157#define ARG_USERACTIVITYLOG "useractivitylog"
158#define ARG_USERACTIVITY    "useractivity"
159#define ARG_LOG             "log"
160#define ARG_LISTEN          "listen"
161#define ARG_HISTORY         "history"
162#define ARG_HISTORY_DETAILED "historydetailed"
163#define ARG_HID_NULL        "hidnull"
164#define ARG_BOOKMARK        "bookmark"
165#define ARG_CLEAR_HISTORY   "clearpmhistory"
166#define ARG_SEARCH          "searchforuuid"
167#define ARG_USERCLIENTS     "userclients"
168#define ARG_UUID            "uuid"
169#define ARG_UUID_LOG        "uuidlog"
170#define ARG_EVERYTHING      "everything"
171#define ARG_PRINT_GETTERS   "getters"
172#define ARG_POWERSTATE      "powerstate"
173#define ARG_POWERSTATELOG   "powerstatelog"
174#define ARG_RDSTATS         "stats"
175#define ARG_SYSSTATE        "systemstate"
176
177// special
178#define ARG_BOOT            "boot"
179#define ARG_UNBOOT          "unboot"
180#define ARG_POLLBOOT        "readboot"
181#define ARG_POLLALL         "readall"
182#define ARG_POLLUSER        "readuser"
183#define ARG_FORCE           "force"
184#define ARG_TOUCH           "touch"
185#define ARG_NOIDLE          "noidle"
186#define ARG_SLEEPNOW        "sleepnow"
187#define ARG_DISPLAYSLEEPNOW "displaysleepnow"
188#define ARG_DEBUGTRIG       "debugTrig"
189#define ARG_RESETDISPLAYAMBIENTPARAMS       "resetdisplayambientparams"
190#define ARG_DISABLEASSERTION                "disableassertion"
191#define ARG_ENABLEASSERTION                 "enableassertion"
192#define ARG_RDAP            "rdap"
193#define ARG_DEBUGFLAGS      "debugflags"
194#define ARG_BTINTERVAL      "btinterval"
195#define ARG_DWLINTERVAL     "dwlinterval"
196#define ARG_MT2BOOK         "mt2book"
197#define ARG_SETSAAFLAGS     "saaflags"
198#define ARG_NOPOLL          "nopoll"
199
200// special system
201#define ARG_DISABLESLEEP    "disablesleep"
202#define ARG_DISABLEFDEKEYSTORE  "destroyfvkeyonstandby"
203
204// return values for parseArgs
205#define kParseSuccess                   0       // success
206#define kParseBadArgs                   -1      // error
207#define kParseInternalError             -2      // error
208
209// bitfield for tracking what's been modified in parseArgs()
210#define kModSettings                    (1<<0)
211#define kModProfiles                    (1<<1)
212#define kModUPSThresholds               (1<<2)
213#define kModSched                       (1<<3)
214#define kModRepeat                      (1<<4)
215#define kModSystemSettings              (1<<5)
216
217// return values for idleSettingsNotConsistent
218#define kInconsistentDisplaySetting     1
219#define kInconsistentDiskSetting        2
220#define kConsistentSleepSettings        0
221
222// day-of-week constants for repeating power events
223#define daily_mask      ( kIOPMMonday | kIOPMTuesday | kIOPMWednesday \
224                        | kIOPMThursday | kIOPMFriday | kIOPMSaturday \
225                        | kIOPMSunday)
226#define weekday_mask    ( kIOPMMonday | kIOPMTuesday | kIOPMWednesday \
227                        | kIOPMThursday | kIOPMFriday )
228#define weekend_mask    ( kIOPMSaturday | kIOPMSunday )
229
230#define kDateAndTimeFormat      "MM/dd/yy HH:mm:ss"
231#define kTimeFormat             "HH:mm:ss"
232
233#define kMaxLongStringLength        255
234
235static const size_t kMaxArgStringLength = 49;
236
237#define kUSecPerSec 1000000.0
238
239
240#ifndef kPMPowerStatesChID
241#define kPMPowerStatesChID  IOREPORT_MAKEID('P','M','S','t','H','i','s','t')
242#endif
243
244#ifndef kPMCurrStateChID
245#define kPMCurrStateChID  IOREPORT_MAKEID('P','M','C','u','r','S','t','\0' )
246#endif
247
248/* RootDomain IOReporting channels */
249#define kSleepCntChID IOREPORT_MAKEID('S','l','e','e','p','C','n','t')
250#define kDarkWkCntChID IOREPORT_MAKEID('G','U','I','W','k','C','n','t')
251#define kUserWkCntChID IOREPORT_MAKEID('D','r','k','W','k','C','n','t')
252
253typedef struct {
254    const char *name;
255    const char *displayAs;
256} PMFeature;
257
258/* list of all features */
259PMFeature all_features[] =
260{
261    { kIOPMDisplaySleepKey,         ARG_DISPLAYSLEEP },
262    { kIOPMDiskSleepKey,            ARG_DISKSLEEP },
263    { kIOPMSystemSleepKey,          ARG_SLEEP },
264    { kIOPMWakeOnLANKey,            ARG_WOMP },
265    { kIOPMWakeOnRingKey,           ARG_RING },
266    { kIOPMWakeOnACChangeKey,       ARG_WAKEONACCHANGE },
267    { kIOPMRestartOnPowerLossKey,   ARG_AUTORESTART },
268    { kIOPMWakeOnClamshellKey,      ARG_LIDWAKE },
269    { kIOPMReduceBrightnessKey,     ARG_REDUCEBRIGHT },
270    { kIOPMDisplaySleepUsesDimKey,  ARG_SLEEPUSESDIM },
271    { kIOPMMobileMotionModuleKey,   ARG_MOTIONSENSOR },
272    { kIOPMGPUSwitchKey,            ARG_GPU },
273    { kIOPMDeepSleepEnabledKey,     ARG_DEEPSLEEP },
274    { kIOPMDeepSleepDelayKey,       ARG_DEEPSLEEPDELAY },
275    { kIOPMDarkWakeBackgroundTaskKey, ARG_DARKWAKES },
276    { kIOPMTTYSPreventSleepKey,     ARG_TTYKEEPAWAKE },
277    { kIOHibernateModeKey,          ARG_HIBERNATEMODE },
278    { kIOHibernateFileKey,          ARG_HIBERNATEFILE },
279    { kIOPMAutoPowerOffEnabledKey,  ARG_AUTOPOWEROFF },
280    { kIOPMAutoPowerOffDelayKey,    ARG_AUTOPOWEROFFDELAY }
281};
282
283#define kNUM_PM_FEATURES    (sizeof(all_features)/sizeof(PMFeature))
284
285enum ArgumentType {
286    kApplyToBattery = 1,
287    kApplyToCharger = 2,
288    kApplyToUPS     = 4,
289    kShowColumns    = 8
290};
291
292enum AssertionBitField {
293    kAssertionCPU = 1,
294    kAssertionInflow = 2,
295    kAssertionCharge = 4,
296    kAssertionIdle = 8
297};
298
299// ack port for sleep/wake callback
300static io_connect_t gPMAckPort = MACH_PORT_NULL;
301
302
303enum SleepCallbackBehavior {
304    kLogSleepEvents = (1<<0),
305    kCancelSleepEvents = (1<<1)
306};
307
308/* pmset commands */
309enum PMCommandType {
310    kPMCommandSleepNow = 1,
311    kPMCommandTouch,
312    kPMCommandNoIdle,
313    kPMCommandDisplaySleepNow,
314    kPMCommandDebugTrig
315};
316
317/* check and set int value multiplier */
318enum {
319    kNoMultiplier = 0,
320    kMillisecondsMultiplier = 1000
321};
322
323typedef struct {
324    CFStringRef         who;
325    CFDateRef           when;
326    CFStringRef         which;
327} ScheduledEventReturnType;
328
329
330#define RING_SIZE 100
331typedef struct {
332   aslmsg msgRing[RING_SIZE];
333   uint32_t readIdx;
334   uint32_t writeIdx;
335} MsgCache;
336
337MsgCache *msgCache = NULL;
338
339// function declarations
340static void usage(void);
341static IOReturn setRootDomainProperty(CFStringRef key, CFTypeRef val);
342static io_registry_entry_t copyRootDomainRef(void);
343static IOReturn _pm_connect(mach_port_t *newConnection);
344static IOReturn _pm_disconnect(mach_port_t connection);
345
346static void show_pm_settings_dict(
347        CFDictionaryRef d,
348        int indent,
349        bool log_overrides,
350        bool prune_unsupported);
351static void show_system_power_settings(void);
352static void show_supported_pm_features(void);
353static void show_custom_pm_settings(void);
354static void show_live_pm_settings(void);
355static void show_ups_settings(void);
356static void show_active_profiles(void);
357static void show_system_profiles(void);
358static void show_scheduled_events(void);
359static void show_active_assertions(uint32_t which);
360static void show_power_sources(int which);
361static bool prevent_idle_sleep(void);
362static void show_assertions(const char *);
363static void log_assertions(void);
364static void show_systemload(void);
365static void log_systemload(void);
366static void log_useractivitylog(void);
367static void log_useractivity(void);
368static void show_log(void);
369static void show_uuid(bool keep_running);
370static void listen_for_everything(void);
371static bool is_display_dim_captured(void);
372static void show_power_adapter(void);
373static void show_getters(void);
374static void show_power_state(char **argv);
375static void show_power_statelog(char **argv);
376static void show_rdStats(char **argv);
377static void show_sysstate(char **argv);
378static void show_everything(char **);
379
380static void show_power_event_history(void);
381static void show_power_event_history_detailed(void);
382static void set_new_power_bookmark(void);
383static void set_debugFlags(char **argv);
384static void set_btInterval(char **argv);
385static void set_dwlInterval(char **argv);
386static void set_saaFlags(char **argv);
387static void show_details_for_UUID(char **UUID_string);
388static void show_NULL_HID_events(void);
389static void show_root_domain_user_clients(void);
390static void mt2bookmark(void);
391static bool isBatteryPollingStopped(void);
392static void set_nopoll(void);
393
394static void print_pretty_date(CFAbsoluteTime t, bool newline);
395static void print_short_date(CFAbsoluteTime t, bool newline);
396static void print_date_with_style(const char *, CFDateFormatterStyle dayStyle, CFDateFormatterStyle timeStyle, CFAbsoluteTime t, bool newline);
397
398static void sleepWakeCallback(
399        void *refcon,
400        io_service_t y __unused,
401        natural_t messageType,
402        void * messageArgument);
403
404static void install_listen_for_notify_system_power(void);
405static void install_listen_PM_connection(void);
406static void install_listen_IORegisterForSystemPower(void);
407static void install_listen_com_apple_powermanagement_sleepservices_notify(void);
408
409static void log_ps_change_handler(void *);
410static int install_listen_for_power_sources(uintptr_t which);
411static int log_raw_power_source_changes(void);
412static void log_raw_battery_interest(
413        void *refcon,
414        io_service_t batt,
415        natural_t messageType,
416        void *messageArgument);
417static void log_raw_battery_match(
418        void *refcon,
419        io_iterator_t b_iter);
420
421static void log_thermal_events(void);
422static void show_systempower_notify(void);
423static void show_thermal_warning_level(void);
424static void show_thermal_cpu_power_level(void);
425
426static void print_raw_battery_state(io_registry_entry_t b_reg);
427static void print_setting_value(CFTypeRef a, int divider);
428static void print_override_pids(int assertion_type);
429static void print_time_of_day_to_buf(int m, char *buf, int buflen);
430static void print_days_to_buf(int d, char *buf, int buflen);
431static void print_repeating_report(CFDictionaryRef repeat);
432static void print_scheduled_report(CFArrayRef events);
433
434static CFDictionaryRef getPowerEvent(int type, CFDictionaryRef events);
435static int getRepeatingDictionaryMinutes(CFDictionaryRef event);
436static int getRepeatingDictionaryDayMask(CFDictionaryRef event);
437static CFStringRef getRepeatingDictionaryType(CFDictionaryRef event);
438static int arePowerSourceSettingsInconsistent(CFDictionaryRef set);
439static void checkSettingConsistency(CFDictionaryRef profiles);
440static ScheduledEventReturnType *scheduled_event_struct_create(void);
441static void scheduled_event_struct_destroy(ScheduledEventReturnType *);
442static void string_tolower(char *lower_me, char *dst);
443static void string_toupper(char *upper_me, char *dst);
444static int checkAndSetIntValue(
445        char *valstr,
446        CFStringRef settingKey,
447        int apply,
448        int isOnOffSetting,
449        int multiplier,
450        CFMutableDictionaryRef ac,
451        CFMutableDictionaryRef batt,
452        CFMutableDictionaryRef ups);
453static int setUPSValue(
454        char *valstr,
455        CFStringRef    whichUPS,
456        CFStringRef settingKey,
457        int apply,
458        CFMutableDictionaryRef thresholds);
459static int parseScheduledEvent(
460        char                        **argv,
461        int                         *num_args_parsed,
462        ScheduledEventReturnType    *local_scheduled_event,
463        bool                        *cancel_scheduled_event,
464        bool                        is_relative_event);
465static int parseRepeatingEvent(
466        char                        **argv,
467        int                         *num_args_parsed,
468        CFMutableDictionaryRef      local_repeating_event,
469        bool                        *local_cancel_repeating);
470static int parseArgs(
471        int argc,
472        char* argv[],
473        CFDictionaryRef             *settings,
474        int                         *modified_power_sources,
475        bool                        *force_activate_settings,
476        CFDictionaryRef             *active_profiles,
477        CFDictionaryRef             *system_power_settings,
478        CFDictionaryRef             *ups_thresholds,
479        ScheduledEventReturnType    **scheduled_event,
480        bool                        *cancel_scheduled_event,
481        CFDictionaryRef             *repeating_event,
482        bool                        *cancel_repeating_event,
483        uint32_t                    *pmCmd);
484static void displaySleepNow();
485static void swd_debugTrig();
486
487static const char *getCanonicalArgForSynonym(char *pass)
488{
489    if (!pass || 0 == strlen(pass))
490        return ARG_LIVE;
491    if (!strncmp(ARG_DISK, pass, kMaxArgStringLength))
492        return ARG_CUSTOM;
493    if (!strncmp(ARG_ADAPTER_AC, pass, kMaxArgStringLength))
494        return ARG_ADAPTER;
495    if (!strncmp(ARG_BATT, pass, kMaxArgStringLength))
496        return ARG_PS;
497    return pass;
498}
499
500typedef enum {
501    kActionGetOnceNoArgs,
502    kActionGetLog,
503    kActionRecursiveBeCareful
504} CommandActionType;
505
506typedef struct {
507    CommandActionType       actionType;
508	const char              *arg;
509	void                    (^action)(char **);
510} CommandAndAction;
511
512static CommandAndAction the_getters[] =
513	{
514		{kActionGetOnceNoArgs,  ARG_LIVE,           ^(char **arg){ show_system_power_settings(); show_active_profiles(); show_live_pm_settings();}},
515		{kActionGetOnceNoArgs,  ARG_CUSTOM,         ^(char **arg){ show_custom_pm_settings(); }},
516        {kActionGetOnceNoArgs,  ARG_CAP,            ^(char **arg){ show_supported_pm_features(); }},
517        {kActionGetOnceNoArgs,  ARG_SCHED,          ^(char **arg){ show_scheduled_events(); }},
518        {kActionGetOnceNoArgs,  ARG_UPS,            ^(char **arg){ show_ups_settings(); }},
519        {kActionGetOnceNoArgs,  ARG_SYS_PROFILES,   ^(char **arg){ show_active_profiles(); show_system_profiles(); }},
520    	{kActionGetOnceNoArgs,  ARG_ADAPTER,        ^(char **arg){ show_power_adapter(); }},
521    	{kActionGetOnceNoArgs,  ARG_PS,             ^(char **arg){ show_power_sources(kApplyToBattery | kApplyToUPS); }},
522    	{kActionGetLog,         ARG_PSLOG,          ^(char **arg){ install_listen_IORegisterForSystemPower();
523                                                        install_listen_for_power_sources(kApplyToBattery | kApplyToUPS);
524                                                        CFRunLoopRun(); }},
525    	{kActionGetLog,         ARG_TRCOLUMNS,      ^(char **arg){ install_listen_IORegisterForSystemPower();
526                                                        install_listen_for_power_sources(kShowColumns);
527                                                        CFRunLoopRun(); }},
528    	{kActionGetLog,         ARG_PSRAW,          ^(char **arg){ log_raw_power_source_changes(); }},
529        {kActionGetOnceNoArgs,  ARG_BATTRAW,        ^(char **arg){ print_raw_battery_state(IO_OBJECT_NULL); }},
530        {kActionGetOnceNoArgs,  ARG_THERM,          ^(char **arg){ show_thermal_warning_level(); show_thermal_cpu_power_level(); }},
531    	{kActionGetLog,         ARG_THERMLOG,       ^(char **arg){ log_thermal_events(); }},
532    	{kActionGetOnceNoArgs,  ARG_ASSERTIONS,     ^(char **arg){ show_assertions(NULL); }},
533    	{kActionGetLog,         ARG_ASSERTIONSLOG,  ^(char **arg){ log_assertions(); }},
534    	{kActionGetOnceNoArgs,  ARG_SYSLOAD,        ^(char **arg){ show_systemload(); }},
535    	{kActionGetLog,         ARG_SYSLOADLOG,     ^(char **arg){ log_systemload(); }},
536    	{kActionGetLog,         ARG_USERACTIVITYLOG,^(char **arg){ log_useractivitylog(); }},
537    	{kActionGetOnceNoArgs,  ARG_USERACTIVITY   ,^(char **arg){ log_useractivity(); }},
538    	{kActionGetOnceNoArgs,  ARG_LOG,            ^(char **arg){ show_log(); }},
539    	{kActionGetLog,         ARG_LISTEN,         ^(char **arg){ listen_for_everything(); }},
540    	{kActionGetOnceNoArgs,  ARG_HISTORY,        ^(char **arg){ show_power_event_history(); }},
541    	{kActionGetOnceNoArgs,  ARG_HISTORY_DETAILED, ^(char **arg){ show_power_event_history_detailed(); }},
542    	{kActionGetOnceNoArgs,  ARG_HID_NULL,       ^(char **arg){ show_NULL_HID_events(); }},
543    	{kActionGetOnceNoArgs,  ARG_USERCLIENTS,    ^(char **arg){ show_root_domain_user_clients(); }},
544        {kActionGetOnceNoArgs,  ARG_UUID,           ^(char **arg){ show_uuid(kActionGetOnceNoArgs); }},
545    	{kActionGetLog,         ARG_UUID_LOG,       ^(char **arg){ show_uuid(kActionGetLog); }},
546        {kActionGetOnceNoArgs,  ARG_PRINT_GETTERS,  ^(char **arg){ show_getters(); }},
547        {kActionGetLog,         ARG_SEARCH,         ^(char **arg){show_details_for_UUID(arg); }},
548        {kActionGetOnceNoArgs,  ARG_POWERSTATE,     ^(char **arg){show_power_state(arg); }},
549        {kActionGetLog,         ARG_POWERSTATELOG,  ^(char **arg){show_power_statelog(arg); }},
550        {kActionGetOnceNoArgs,  ARG_RDSTATS,        ^(char **arg){show_rdStats(arg); }},
551        {kActionGetOnceNoArgs,  ARG_SYSSTATE,       ^(char **arg){show_sysstate(arg); }},
552        {kActionRecursiveBeCareful, ARG_EVERYTHING, ^(char **arg){ show_everything(arg); }}
553	};
554
555
556static const int the_getters_count = (sizeof(the_getters) / sizeof(CommandAndAction));
557
558
559//****************************
560//****************************
561//****************************
562
563static void usage(void)
564{
565    printf("Usage: pmset <options>\n");
566    printf("See pmset(1) for details: \'man pmset\'\n");
567}
568
569
570
571int main(int argc, char *argv[]) {
572    IOReturn                        ret, ret1, err;
573    io_connect_t                    fb;
574    CFDictionaryRef                 es_custom_settings = 0;
575    int                             modified_power_sources = 0;
576    bool                            force_it = 0;
577    CFDictionaryRef                 ups_thresholds = 0;
578    CFDictionaryRef                 system_power_settings = 0;
579    CFDictionaryRef                 active_profiles = 0;
580    ScheduledEventReturnType        *scheduled_event_return = 0;
581    bool                            cancel_scheduled_event = 0;
582    CFDictionaryRef                 repeating_event_return = 0;
583    bool                            cancel_repeating_event = 0;
584    uint32_t                        pmCommand = 0;
585
586    ret = parseArgs(argc, argv,
587        &es_custom_settings, &modified_power_sources, &force_it,
588        &active_profiles,
589        &system_power_settings,
590        &ups_thresholds,
591        &scheduled_event_return, &cancel_scheduled_event,
592        &repeating_event_return, &cancel_repeating_event,
593        &pmCommand);
594
595    if(ret == kParseBadArgs)
596    {
597        //printf("pmset: error in parseArgs!\n");
598        usage();
599        exit(1);
600    }
601
602    if(ret == kParseInternalError)
603    {
604        fprintf(stderr, "%s: internal error!\n", argv[0]); fflush(stdout);
605        exit(1);
606    }
607
608    switch ( pmCommand )
609    {
610        /*************** Sleep now *************************************/
611        case kPMCommandSleepNow:
612            fb = IOPMFindPowerManagement(MACH_PORT_NULL);
613            if ( MACH_PORT_NULL != fb ) {
614                err = IOPMSleepSystem ( fb );
615
616                if( kIOReturnNotPrivileged == err )
617                {
618                    printf("Sleep error 0x%08x; You must run this as root.\n", err);
619                    exit(EX_NOPERM);
620                } else if ( (MACH_PORT_NULL == fb) || (kIOReturnSuccess != err) )
621                {
622                    printf("Unable to sleep system: error 0x%08x\n", err);
623                    exit(EX_OSERR);
624                } else {
625                    printf("Sleeping now...\n");
626                }
627            }
628
629            return 0;
630
631        /*************** Display Sleep now *************************************/
632        case kPMCommandDisplaySleepNow:
633            displaySleepNow();
634            break;
635
636        case kPMCommandDebugTrig:
637            swd_debugTrig();
638            break;
639
640        /*************** Touch settings *************************************/
641        case kPMCommandTouch:
642            printf("touching prefs file on disk...\n");
643
644            ret = IOPMSetPMPreferences(NULL);
645            if(kIOReturnSuccess != ret)
646            {
647                printf("\'%s\' must be run as root...\n", argv[0]);
648            }
649
650            return 0;
651
652        /*************** Prevent idle sleep **********************************/
653        case kPMCommandNoIdle:
654            if(!prevent_idle_sleep())
655            {
656                printf("Error preventing idle sleep\n");
657            }
658            return 1;
659
660        default:
661            // If no command is specified, execution continues with processing
662            // other command-line arguments
663            break;
664    }
665
666    if(force_it && es_custom_settings)
667    {
668
669        mach_port_t             pm_server = MACH_PORT_NULL;
670        CFDataRef               settings_data;
671        int32_t                 return_code;
672        kern_return_t           kern_result;
673
674        /*
675         * Step 1 - send these forced settings over to powerd.
676         *
677         */
678        err = _pm_connect(&pm_server);
679        if (kIOReturnSuccess == err) {
680            settings_data = IOCFSerialize(es_custom_settings, 0);
681
682            if (settings_data)
683            {
684                kern_result = io_pm_force_active_settings(
685                        pm_server,
686                        (vm_offset_t)CFDataGetBytePtr(settings_data),
687                        CFDataGetLength(settings_data),
688                        &return_code);
689
690                if( KERN_SUCCESS != kern_result ) {
691                    printf("exit kern_result = 0x%08x\n", kern_result);
692                }
693                if( kIOReturnSuccess != return_code ) {
694                    printf("exit return_code = 0x%08x\n", return_code);
695                }
696
697                CFRelease(settings_data);
698
699                if (KERN_SUCCESS != kern_result || kIOReturnSuccess != return_code) {
700                    exit(1);
701                }
702            }
703            _pm_disconnect(pm_server);
704        }
705
706        /*
707         * Step 2 - this code might be running in a partilially uninitialized OS,
708         * and powerd might not be running. e.g. at Installer context.
709         * Since powerd may not be running, we also activate these settings directly
710         * to the controlling drivers in the kernel.
711         *
712         */
713        CFTypeRef       powersources = IOPSCopyPowerSourcesInfo();
714        CFStringRef     activePowerSource = NULL;
715        CFDictionaryRef useSettings = NULL;
716        if (powersources) {
717            activePowerSource = IOPSGetProvidingPowerSourceType(powersources);
718            if (!activePowerSource) {
719                activePowerSource = CFSTR(kIOPMACPowerKey);
720            }
721            useSettings = CFDictionaryGetValue(es_custom_settings, activePowerSource);
722            if (useSettings) {
723                ActivatePMSettings(useSettings, true);
724            }
725            CFRelease(powersources);
726        }
727
728        // Return here. If this is a 'force' call we do _not_ want
729        // to attempt to write any settings to the disk, or to try anything
730        // else at all, as our environment may be unwritable / diskless
731        // (booted from install CD)
732        return 0;
733    }
734
735    if(es_custom_settings)
736    {
737        CFNumberRef             neg1 = NULL;
738        int                     tmp_int = -1;
739        CFDictionaryRef         tmp_dict = NULL;
740        CFMutableDictionaryRef  customize_active_profiles = NULL;
741
742        // Send pmset changes out to disk
743        if(kIOReturnSuccess != (ret1 = IOPMSetPMPreferences(es_custom_settings)))
744        {
745            if(ret1 == kIOReturnNotPrivileged)
746            {
747                printf("\'%s\' must be run as root...\n", argv[0]);
748            } else {
749                printf("Error 0x%08x writing Energy Saver preferences to disk\n", ret1);
750            }
751            exit(1);
752        }
753
754        // Also need to change the active profile to -1 (Custom)
755        // We assume the user intended to activate these new custom settings.
756        neg1 = CFNumberCreate(0, kCFNumberIntType, &tmp_int);
757        tmp_dict = IOPMCopyActivePowerProfiles();
758        if(!tmp_dict) {
759            printf("Custom profile set; unable to update active profile to -1.\n");
760            exit(1);
761        }
762        customize_active_profiles = CFDictionaryCreateMutableCopy(0, 0, tmp_dict);
763        if(!customize_active_profiles) {
764            printf("Internal error\n");
765            exit(1);
766        }
767        // For each power source we modified settings for, flip that
768        // source's profile to -1
769        if(modified_power_sources & kApplyToCharger) {
770            CFDictionarySetValue( customize_active_profiles,
771                                    CFSTR(kIOPMACPowerKey), neg1);
772        }
773        if(modified_power_sources & kApplyToBattery) {
774            CFDictionarySetValue( customize_active_profiles,
775                                    CFSTR(kIOPMBatteryPowerKey), neg1);
776        }
777        if(modified_power_sources & kApplyToUPS) {
778            CFDictionarySetValue( customize_active_profiles,
779                                    CFSTR(kIOPMUPSPowerKey), neg1);
780        }
781
782        ret = IOPMSetActivePowerProfiles(customize_active_profiles);
783        if(kIOReturnSuccess != ret) {
784            printf("Error 0x%08x writing customized power profiles to disk\n", ret);
785            exit(1);
786        }
787        CFRelease(neg1);
788        CFRelease(tmp_dict);
789        CFRelease(customize_active_profiles);
790
791
792        // Print a warning to stderr if idle sleep settings won't
793        // produce expected result; i.e. sleep < (display | dim)
794        checkSettingConsistency(es_custom_settings);
795        CFRelease(es_custom_settings);
796    }
797
798    if(active_profiles)
799    {
800        ret = IOPMSetActivePowerProfiles(active_profiles);
801        if(kIOReturnSuccess != ret) {
802            printf("Error 0x%08x writing active power profiles to disk\n", ret);
803            exit(1);
804        }
805
806        CFRelease(active_profiles);
807    }
808
809    if(system_power_settings)
810    {
811        int             iii;
812        int             sys_setting_count = 0;
813
814        if( isA_CFDictionary(system_power_settings)) {
815            sys_setting_count = CFDictionaryGetCount(system_power_settings);
816        }
817
818        if (0 != sys_setting_count)
819        {
820            CFStringRef     *keys = malloc(sizeof(CFStringRef) * sys_setting_count);
821            CFTypeRef       *vals = malloc(sizeof(CFTypeRef) * sys_setting_count);
822
823            if(keys && vals)
824            {
825                CFDictionaryGetKeysAndValues( system_power_settings,
826                                          (const void **)keys, (const void **)vals);
827
828                for(iii=0; iii<sys_setting_count; iii++)
829                {
830                    // We write the settings to disk here; PM configd picks them up and
831                    // sends them to xnu from configd space.
832                    ret = IOPMSetSystemPowerSetting(keys[iii], vals[iii]);
833                    if(kIOReturnNotPrivileged == ret)
834                    {
835                        printf("\'%s\' must be run as root...\n", argv[0]);
836                    }
837                    else if (kIOReturnSuccess != ret)
838                    {
839                        printf("\'%s\' failed to set the value.\n", argv[0]);
840                    }
841                }
842            }
843
844            if (keys) free (keys);
845            if (vals) free (vals);
846        }
847
848        CFRelease(system_power_settings);
849    }
850
851    // Did the user change UPS settings too?
852    if(ups_thresholds)
853    {
854        // Only write out UPS settings if thresholds were changed.
855        //      * UPS sleep timers & energy settings have already been
856        //        written with IOPMSetPMPreferences() regardless.
857        ret1 = IOPMSetUPSShutdownLevels(
858                            CFSTR(kIOPMDefaultUPSThresholds),
859                            ups_thresholds);
860        if(kIOReturnSuccess != ret1)
861        {
862            if(ret1 == kIOReturnNotPrivileged)
863                printf("\'%s\' must be run as root...\n", argv[0]);
864            if(ret1 == kIOReturnError
865                || ret1 == kIOReturnBadArgument)
866                printf("Error writing UPS preferences to disk\n");
867            exit(1);
868        }
869        CFRelease(ups_thresholds);
870    }
871
872
873    if(scheduled_event_return)
874    {
875        if(cancel_scheduled_event)
876        {
877            // cancel the event described by scheduled_event_return
878            ret = IOPMCancelScheduledPowerEvent(
879                    scheduled_event_return->when,
880                    scheduled_event_return->who,
881                    scheduled_event_return->which);
882        } else {
883            ret = IOPMSchedulePowerEvent(
884                    scheduled_event_return->when,
885                    scheduled_event_return->who,
886                    scheduled_event_return->which);
887        }
888
889        if(kIOReturnNotPrivileged == ret) {
890            fprintf(stderr, "%s: This operation must be run as root\n", argv[0]);
891            fflush(stderr);
892            exit(1);
893        }
894        if(kIOReturnSuccess != ret) {
895            fprintf(stderr, "%s: Error in scheduling operation\n", argv[0]);
896            fflush(stderr);
897            exit(1);
898        }
899
900        // free individual members
901        scheduled_event_struct_destroy(scheduled_event_return);
902    }
903
904    if(cancel_repeating_event)
905    {
906        ret = IOPMCancelAllRepeatingPowerEvents();
907        if(kIOReturnSuccess != ret) {
908            if(kIOReturnNotPrivileged == ret) {
909                fprintf(stderr, "pmset: Must be run as root to modify settings\n");
910            } else {
911                fprintf(stderr, "pmset: Error 0x%08x cancelling repeating events\n", ret);
912            }
913            fflush(stderr);
914            exit(1);
915        }
916    }
917
918    if(repeating_event_return)
919    {
920        ret = IOPMScheduleRepeatingPowerEvent(repeating_event_return);
921        if(kIOReturnSuccess != ret) {
922            if(kIOReturnNotPrivileged == ret) {
923                fprintf(stderr, "pmset: Must be run as root to modify settings\n");
924            } else {
925                fprintf(stderr, "pmset: Error 0x%08x scheduling repeating events\n", ret);
926            }
927            fflush(stderr);
928            exit(1);
929        }
930        CFRelease(repeating_event_return);
931    }
932
933
934    return 0;
935}
936
937//****************************
938//****************************
939//****************************
940
941
942io_registry_entry_t _getRootDomain(void)
943{
944    static io_registry_entry_t gRoot = MACH_PORT_NULL;
945
946    if (MACH_PORT_NULL == gRoot)
947        gRoot = IORegistryEntryFromPath( kIOMasterPortDefault,
948                kIOPowerPlane ":/IOPowerConnection/IOPMrootDomain");
949
950    return gRoot;
951}
952
953
954static void swd_debugTrig()
955{
956    io_service_t                rootDomainService = IO_OBJECT_NULL;
957    io_connect_t                gRootDomainConnect = IO_OBJECT_NULL;
958    kern_return_t               kr = 0;
959    IOReturn                    ret;
960
961    // Find it
962    rootDomainService = _getRootDomain();
963    if (IO_OBJECT_NULL == rootDomainService) {
964        goto exit;
965    }
966
967    // Open it
968    kr = IOServiceOpen(rootDomainService, mach_task_self(), 0, &gRootDomainConnect);
969    if (KERN_SUCCESS != kr) {
970        printf("Failed to connect to rootDomain. rc=0x%x\n", kr);
971        goto exit;
972    }
973
974    ret = IOConnectCallMethod(gRootDomainConnect, kPMSleepWakeDebugTrig,
975                    NULL, 0,
976                    NULL, 0, NULL,
977                    NULL, NULL, NULL);
978
979    if (kIOReturnSuccess != ret)
980    {
981        printf("Failed to trigger a sleep wake kernel log collection. rc=0x%x\n", ret);
982        goto exit;
983    }
984
985exit:
986    if (IO_OBJECT_NULL != gRootDomainConnect)
987        IOServiceClose(gRootDomainConnect);
988    return;
989
990}
991
992
993static void displaySleepNow()
994{
995    io_registry_entry_t disp_wrangler = IO_OBJECT_NULL;
996    kern_return_t kr;
997
998    disp_wrangler = IORegistryEntryFromPath(
999                            kIOMasterPortDefault,
1000                            kIOServicePlane ":/IOResources/IODisplayWrangler");
1001    if(disp_wrangler == IO_OBJECT_NULL)
1002        return ;
1003
1004    kr = IORegistryEntrySetCFProperty( disp_wrangler, CFSTR("IORequestIdle"),kCFBooleanTrue);
1005
1006    if(kr)
1007        fprintf(stderr, "pmset: Failed to set the display to sleep(err:0x%x)\n", kr);
1008
1009    IOObjectRelease(disp_wrangler);
1010
1011    return ;
1012
1013}
1014
1015static CFTypeRef copyRootDomainProperty(CFStringRef key)
1016{
1017    static io_object_t      rd = IO_OBJECT_NULL;
1018
1019    if (IO_OBJECT_NULL == rd) {
1020        rd = copyRootDomainRef();
1021    }
1022
1023    return IORegistryEntryCreateCFProperty(rd, key, 0, 0);
1024}
1025
1026static IOReturn setRootDomainProperty(CFStringRef key, CFTypeRef val)
1027{
1028    io_registry_entry_t         root_domain = copyRootDomainRef();
1029    IOReturn                    ret;
1030
1031    if(!root_domain) return kIOReturnError;
1032
1033    ret = IORegistryEntrySetCFProperty(root_domain, key, val);
1034
1035    IOObjectRelease(root_domain);
1036    return ret;
1037}
1038
1039static io_registry_entry_t copyRootDomainRef(void)
1040{
1041    return (io_registry_entry_t)IOServiceGetMatchingService(
1042                    MACH_PORT_NULL, IOServiceNameMatching("IOPMrootDomain"));
1043 }
1044
1045static void print_setting_value(CFTypeRef a, int divider)
1046{
1047    int n;
1048
1049    if(isA_CFNumber(a))
1050    {
1051        CFNumberGetValue(a, kCFNumberIntType, (void *)&n);
1052
1053        if( 0 != divider ) n/=divider;
1054
1055        printf("%d", n);
1056    } else if(isA_CFBoolean(a))
1057    {
1058        printf("%d", CFBooleanGetValue(a));
1059    } else if(isA_CFString(a))
1060    {
1061        char buf[100];
1062        if(CFStringGetCString(a, buf, 100, kCFStringEncodingUTF8))
1063        {
1064            printf("%s", buf);
1065        }
1066    } else printf("oops - print_setting_value unknown data type\n");
1067}
1068
1069// Arguments to print_override_pids
1070enum {
1071    _kIOPMAssertionDisplayOn = 5,
1072    _kIOPMAssertionSystemOn = 6
1073};
1074
1075static void show_pm_settings_dict(
1076    CFDictionaryRef d,
1077    int indent,
1078    bool show_overrides,
1079    bool prune_unsupported)
1080{
1081    int                     count;
1082    int                     i;
1083    int                     j;
1084    int                     divider = 0;
1085    char                    ps[kMaxArgStringLength];
1086    CFStringRef             *keys;
1087    CFTypeRef               *vals;
1088    CFTypeRef               ps_blob;
1089    CFStringRef             activeps = NULL;
1090    int                     show_override_type = 0;
1091    bool                    show_display_dim = false;
1092
1093    ps_blob = IOPSCopyPowerSourcesInfo();
1094    if(ps_blob) {
1095        activeps = IOPSGetProvidingPowerSourceType(ps_blob);
1096    }
1097    if(!activeps) activeps = CFSTR(kIOPMACPowerKey);
1098    if(activeps) CFRetain(activeps);
1099
1100    count = CFDictionaryGetCount(d);
1101    keys = (CFStringRef *)malloc(count * sizeof(CFStringRef));
1102    vals = (CFTypeRef *)malloc(count * sizeof(CFTypeRef));
1103    if(!keys || !vals)
1104        goto exit;
1105    CFDictionaryGetKeysAndValues(d, (const void **)keys, (const void **)vals);
1106
1107    for(i=0; i<count; i++)
1108    {
1109        show_override_type = 0;
1110
1111        if (!CFStringGetCString(keys[i], ps, sizeof(ps), kCFStringEncodingMacRoman))
1112            continue;
1113
1114        if( prune_unsupported
1115            && !IOPMFeatureIsAvailable(keys[i], CFSTR(kIOPMACPowerKey)) )
1116        {
1117            // unsupported setting for the current power source!
1118            // do not show it!
1119            continue;
1120        }
1121
1122        for(j=0; j<indent;j++) printf(" ");
1123
1124        divider = 0;
1125
1126		if (strcmp(ps, kIOPMPrioritizeNetworkReachabilityOverSleepKey) == 0)
1127		{
1128            printf(" %-20s ", ARG_NETAVAILABLE);
1129		} else if (strcmp(ps, kIOPMDisplaySleepKey) == 0) {
1130	        printf(" %-20s ", "displaysleep");
1131	        if(show_overrides) {
1132	            show_override_type = _kIOPMAssertionDisplayOn;
1133		}
1134	        show_display_dim = true;
1135		} else if (strcmp(ps, kIOPMSystemSleepKey) == 0) {
1136			printf(" %-20s ", "sleep");
1137            if(show_overrides) {
1138                show_override_type = _kIOPMAssertionSystemOn;
1139			}
1140  		} else {
1141	        for(j=0; j<kNUM_PM_FEATURES; j++) {
1142	            if (!strncmp(ps, all_features[j].name, kMaxArgStringLength)) {
1143	                printf(" %-20s ", all_features[j].displayAs);
1144                    break;
1145	            }
1146	        }
1147            if (j==kNUM_PM_FEATURES)
1148                printf(" %-20s ",ps);
1149		}
1150
1151        print_setting_value(vals[i], divider);
1152
1153        if(show_override_type)
1154            print_override_pids(show_override_type);
1155        if(show_display_dim) {
1156            if( is_display_dim_captured() )
1157                printf(" (Graphics dim captured)");
1158            show_display_dim = false;
1159        }
1160        printf("\n");
1161    }
1162
1163exit:
1164    if (ps_blob) CFRelease(ps_blob);
1165    if (activeps) CFRelease(activeps);
1166    free(keys);
1167    free(vals);
1168}
1169
1170static void show_system_power_settings(void)
1171{
1172    CFDictionaryRef     system_power_settings = NULL;
1173    CFBooleanRef        b;
1174
1175    system_power_settings = IOPMCopySystemPowerSettings();
1176    if(!isA_CFDictionary(system_power_settings)) {
1177        goto exit;
1178    }
1179
1180    printf("System-wide power settings:\n");
1181
1182    if((b = CFDictionaryGetValue(system_power_settings, kIOPMSleepDisabledKey)))
1183    {
1184        printf(" SleepDisabled\t\t%d\n", (b==kCFBooleanTrue) ? 1:0);
1185    }
1186
1187    if((b = CFDictionaryGetValue(system_power_settings, CFSTR(kIOPMDestroyFVKeyOnStandbyKey))))
1188    {
1189        printf(" DestroyFVKeyOnStandby\t\t%d\n", (b==kCFBooleanTrue) ? 1:0);
1190    }
1191exit:
1192    if (system_power_settings)
1193        CFRelease(system_power_settings);
1194}
1195
1196
1197
1198static void print_override_pids(int assertionType)
1199{
1200    CFDictionaryRef         assertions_pids = NULL;
1201    CFDictionaryRef         assertions_state = NULL;
1202    CFNumberRef             assertion_value;
1203    IOReturn                ret;
1204    char                    display_string[kMaxLongStringLength] = "\0";
1205    int                     length = 0;
1206    int                     bgTaskLevel = 0, pushTaskLevel = 0, preventSleepLevel = 0;
1207    int                     proxyLevel = 0;
1208
1209    /*
1210     * Early pre-screening - don't dive into the assertions data
1211     * unless we know that there's an active assertion somewhere in there.
1212     */
1213
1214    ret = IOPMCopyAssertionsStatus(&assertions_state);
1215    if( (kIOReturnSuccess != ret) || !isA_CFDictionary(assertions_state)) {
1216        goto bail;
1217    }
1218
1219    if (_kIOPMAssertionDisplayOn == assertionType)
1220    {
1221        int userIdleLevel = 0;
1222        int noDisplayLevel = 0;
1223        int displayWake = 0;
1224
1225        assertion_value = CFDictionaryGetValue(assertions_state, kIOPMAssertionTypePreventUserIdleDisplaySleep);
1226        if(assertion_value)
1227            CFNumberGetValue(assertion_value, kCFNumberIntType, &userIdleLevel);
1228
1229        assertion_value = CFDictionaryGetValue(assertions_state, kIOPMAssertionTypeNoDisplaySleep);
1230        if(assertion_value)
1231            CFNumberGetValue(assertion_value, kCFNumberIntType, &noDisplayLevel);
1232
1233        assertion_value = CFDictionaryGetValue(assertions_state, kIOPMAssertDisplayWake);
1234        if(assertion_value)
1235            CFNumberGetValue(assertion_value, kCFNumberIntType, &displayWake);
1236
1237        if ((kIOPMAssertionLevelOff == userIdleLevel)
1238            && (kIOPMAssertionLevelOff == noDisplayLevel)
1239            && (kIOPMAssertionLevelOff == displayWake))
1240        {
1241            goto bail;
1242        }
1243       snprintf(display_string, kMaxLongStringLength, " (display sleep prevented by ");
1244       length = strlen(display_string);
1245    }
1246
1247
1248    if (_kIOPMAssertionSystemOn == assertionType)
1249    {
1250        int noIdleLevel = 0;
1251        int userIdleLevel = 0;
1252
1253        assertion_value = CFDictionaryGetValue(assertions_state, kIOPMAssertionTypeNoIdleSleep);
1254        if(assertion_value)
1255            CFNumberGetValue(assertion_value, kCFNumberIntType, &noIdleLevel);
1256
1257        assertion_value = CFDictionaryGetValue(assertions_state, kIOPMAssertionTypePreventSystemSleep);
1258        if(assertion_value)
1259            CFNumberGetValue(assertion_value, kCFNumberIntType, &preventSleepLevel);
1260
1261        assertion_value = CFDictionaryGetValue(assertions_state, kIOPMAssertionTypePreventUserIdleSystemSleep);
1262        if(assertion_value)
1263            CFNumberGetValue(assertion_value, kCFNumberIntType, &userIdleLevel);
1264
1265        assertion_value = CFDictionaryGetValue(assertions_state, kIOPMAssertionTypeBackgroundTask);
1266        if(assertion_value)
1267            CFNumberGetValue(assertion_value, kCFNumberIntType, &bgTaskLevel);
1268
1269        assertion_value = CFDictionaryGetValue(assertions_state, kIOPMAssertInternalPreventSleep);
1270        if(assertion_value)
1271            CFNumberGetValue(assertion_value, kCFNumberIntType, &proxyLevel);
1272
1273        assertion_value = CFDictionaryGetValue(assertions_state, kIOPMAssertionTypeApplePushServiceTask);
1274        if(assertion_value)
1275            CFNumberGetValue(assertion_value, kCFNumberIntType, &pushTaskLevel);
1276        if ((kIOPMAssertionLevelOff == noIdleLevel)
1277            && (kIOPMAssertionLevelOff == preventSleepLevel)
1278            && (kIOPMAssertionLevelOff == bgTaskLevel)
1279            && (kIOPMAssertionLevelOff == pushTaskLevel)
1280            && (kIOPMAssertionLevelOff == userIdleLevel))
1281        {
1282            goto bail;
1283        }
1284
1285       snprintf(display_string, kMaxLongStringLength, " (sleep prevented by ");
1286       length = strlen(display_string);
1287    }
1288
1289
1290    /*
1291     * Find out which pids have asserted this and print 'em out
1292     * We conclude that at least one pid is forcing a relevant assertion.
1293     */
1294    CFNumberRef             *pids = NULL;
1295    CFArrayRef              *assertions = NULL;
1296    int                     process_count;
1297    int                     this_is_the_first = 1;
1298    int                     i;
1299
1300
1301    ret = IOPMCopyAssertionsByProcess(&assertions_pids);
1302    if( (kIOReturnSuccess != ret) || !isA_CFDictionary(assertions_pids) ) {
1303        goto bail;
1304    }
1305
1306
1307    process_count = CFDictionaryGetCount(assertions_pids);
1308    pids = malloc(sizeof(CFNumberRef)*process_count);
1309    assertions = malloc(sizeof(CFArrayRef)*process_count);
1310    CFDictionaryGetKeysAndValues(assertions_pids,
1311                        (const void **)pids,
1312                        (const void **)assertions);
1313    for(i=0; i<process_count; i++)
1314    {
1315        int         j;
1316
1317        for(j=0; j<CFArrayGetCount(assertions[i]); j++)
1318        {
1319            CFDictionaryRef     tmp_assertion = NULL;
1320            CFNumberRef         tmp_level = NULL;
1321            CFStringRef         tmp_type = NULL;
1322            CFStringRef         process_name = NULL;
1323            char                pnameBuf[kProcNameBufLen];
1324            int                 level = kIOPMAssertionLevelOff;
1325            bool                print_this_pid = false;
1326
1327            tmp_assertion = CFArrayGetValueAtIndex(assertions[i], j);
1328
1329            if (!tmp_assertion || (kCFBooleanFalse == (CFBooleanRef)tmp_assertion))
1330            {
1331                continue;
1332            }
1333
1334            if ( (tmp_type = CFDictionaryGetValue(tmp_assertion, kIOPMAssertionTrueTypeKey)) == NULL)
1335                tmp_type = CFDictionaryGetValue(tmp_assertion, kIOPMAssertionTypeKey);
1336            tmp_level = CFDictionaryGetValue(tmp_assertion, kIOPMAssertionLevelKey);
1337            process_name = CFDictionaryGetValue(tmp_assertion, CFSTR("Process Name"));
1338
1339            level = kIOPMAssertionLevelOff;
1340            if (tmp_level) {
1341                CFNumberGetValue(tmp_level, kCFNumberIntType, &level);
1342            }
1343
1344            if (level != kIOPMAssertionLevelOn) continue;
1345
1346            if (_kIOPMAssertionSystemOn == assertionType) {
1347                if (CFEqual(tmp_type, kIOPMAssertionTypePreventUserIdleSystemSleep)) {
1348                    /* Found an assertion that keeps the system on */
1349                    print_this_pid = true;
1350                }
1351                else if ( (preventSleepLevel) &&
1352                          (CFEqual(tmp_type, kIOPMAssertionTypePreventSystemSleep)) ) {
1353                    print_this_pid = true;
1354                }
1355                else if ( (bgTaskLevel) &&
1356                          (CFEqual(tmp_type, kIOPMAssertionTypeBackgroundTask)) )
1357                {
1358                    print_this_pid = true;
1359                }
1360                else if ( (pushTaskLevel) &&
1361                          (CFEqual(tmp_type, kIOPMAssertionTypeApplePushServiceTask)) )
1362                {
1363                    print_this_pid = true;
1364                }
1365                else if ( (proxyLevel) &&
1366                          (CFEqual(tmp_type, kIOPMAssertInternalPreventSleep )) )
1367                {
1368                    print_this_pid = true;
1369                }
1370            }
1371            else if ((_kIOPMAssertionDisplayOn == assertionType)
1372                    && CFEqual(tmp_type, kIOPMAssertionTypePreventUserIdleDisplaySleep) )
1373            {
1374                /* Found an assertion that keeps the display on */
1375                print_this_pid = true;
1376            }
1377            else if ((_kIOPMAssertionDisplayOn == assertionType)
1378                    && CFEqual(tmp_type, kIOPMAssertDisplayWake) )
1379            {
1380                /* Found an assertion that keeps the display on */
1381                print_this_pid = true;
1382            }
1383            if (print_this_pid)
1384            {
1385                if (this_is_the_first) {
1386                    this_is_the_first = 0;
1387                } else {
1388                    strncat(display_string, ", ", kMaxLongStringLength-length-1);
1389                    length = strlen(display_string);
1390                }
1391
1392                if (process_name && CFStringGetCString(process_name, pnameBuf, sizeof(pnameBuf), kCFStringEncodingUTF8))
1393                {
1394                    strncat(display_string, pnameBuf, kMaxLongStringLength-length-1);
1395                    length = strlen(display_string);
1396                }
1397            }
1398        }
1399    }
1400
1401    strncat(display_string, ")", sizeof(display_string)-strlen(display_string)-1);
1402
1403    printf("%s", display_string);
1404
1405    free(pids);
1406    free(assertions);
1407
1408bail:
1409    if(assertions_state) CFRelease(assertions_state);
1410    if(assertions_pids) CFRelease(assertions_pids);
1411    return;
1412}
1413
1414static void show_supported_pm_features(void)
1415{
1416    CFStringRef 		feature;
1417    CFTypeRef           ps_info = IOPSCopyPowerSourcesInfo();
1418    CFStringRef 		source;
1419    char         	    ps_buf[40];
1420    int 				i;
1421
1422    if(!ps_info) {
1423        source = CFSTR(kIOPMACPowerKey);
1424    } else {
1425        source = IOPSGetProvidingPowerSourceType(ps_info);
1426    }
1427    if(!isA_CFString(source) ||
1428       !CFStringGetCString(source, ps_buf, 40, kCFStringEncodingMacRoman)) {
1429        printf("internal supported features string error!\n");
1430    }
1431
1432    printf("Capabilities for %s:\n", ps_buf);
1433    // iterate the list of all features
1434    for(i=0; i<kNUM_PM_FEATURES; i++)
1435    {
1436        feature = CFStringCreateWithCStringNoCopy(NULL, all_features[i].name,
1437                                                  kCFStringEncodingMacRoman, kCFAllocatorNull);
1438        if (feature)
1439 		{
1440	        if (IOPMFeatureIsAvailable(feature, source))
1441			{
1442                printf(" %s\n", all_features[i].displayAs);
1443	        }
1444	        CFRelease(feature);
1445		}
1446    }
1447    if(ps_info) {
1448		CFRelease(ps_info);
1449	}
1450}
1451
1452static void show_power_profile(
1453    CFDictionaryRef     es,
1454    int                 indent)
1455{
1456    int                 num_profiles;
1457    int                 i, j;
1458    char                ps[kMaxArgStringLength];
1459    CFStringRef         *keys;
1460    CFDictionaryRef     *values;
1461
1462    if(indent<0 || indent>30) indent=0;
1463
1464    num_profiles = CFDictionaryGetCount(es);
1465    keys = (CFStringRef *)malloc(num_profiles * sizeof(CFStringRef));
1466    values = (CFDictionaryRef *)malloc(num_profiles * sizeof(CFDictionaryRef));
1467    if(keys && values)
1468    {
1469        CFDictionaryGetKeysAndValues(es, (const void **)keys, (const void **)values);
1470
1471        for(i=0; i<num_profiles; i++)
1472        {
1473            if(!isA_CFDictionary(values[i]))
1474                continue;
1475
1476            if(!CFStringGetCString(keys[i], ps, sizeof(ps), kCFStringEncodingMacRoman))
1477                continue; // with for loop
1478
1479            for(j=0; j<indent; j++) {
1480                printf(" ");
1481            }
1482            printf("%s:\n", ps);
1483            show_pm_settings_dict(values[i], indent, 0, false);
1484        }
1485    }
1486    if (keys) free(keys);
1487    if (values) free(values);
1488}
1489
1490static void show_custom_pm_settings(void)
1491{
1492    CFDictionaryRef     es = NULL;
1493
1494    // read settings file from /Library/Preferences/SystemConfiguration/com.apple.PowerManagement.plist
1495    es = IOPMCopyPMPreferences();
1496    if(!es)
1497        return;
1498    show_power_profile(es, 0);
1499    CFRelease(es);
1500}
1501
1502static void show_live_pm_settings(void)
1503{
1504    SCDynamicStoreRef        ds;
1505    CFDictionaryRef        live;
1506
1507    ds = SCDynamicStoreCreate(NULL, CFSTR("pmset"), NULL, NULL);
1508
1509    // read current settings from SCDynamicStore key
1510    live = SCDynamicStoreCopyValue(ds, CFSTR(kIOPMDynamicStoreSettingsKey));
1511    if(!live)
1512        return;
1513    printf("Currently in use:\n");
1514    show_pm_settings_dict(live, 0, true, true);
1515
1516    CFRelease(live);
1517    CFRelease(ds);
1518}
1519
1520static void show_ups_settings(void)
1521{
1522    CFDictionaryRef     thresholds;
1523    CFDictionaryRef     d;
1524    CFNumberRef         n_val;
1525    int                 val;
1526    CFBooleanRef        b;
1527
1528    thresholds = IOPMCopyUPSShutdownLevels(CFSTR(kIOPMDefaultUPSThresholds));
1529    if(!thresholds)
1530        return;
1531
1532    printf("UPS settings:\n");
1533
1534    if((d = CFDictionaryGetValue(thresholds, CFSTR(kIOUPSShutdownAtLevelKey))))
1535    {
1536        b = CFDictionaryGetValue(d, CFSTR(kIOUPSShutdownLevelEnabledKey));
1537        n_val = CFDictionaryGetValue(d, CFSTR(kIOUPSShutdownLevelValueKey));
1538        CFNumberGetValue(n_val, kCFNumberIntType, &val);
1539        printf("  %s\t%s\t%d\n", ARG_HALTLEVEL, (kCFBooleanTrue==b)?"on":"off", val);
1540    }
1541    if((d = CFDictionaryGetValue(thresholds, CFSTR(kIOUPSShutdownAfterMinutesOn))))
1542    {
1543        b = CFDictionaryGetValue(d, CFSTR(kIOUPSShutdownLevelEnabledKey));
1544        n_val = CFDictionaryGetValue(d, CFSTR(kIOUPSShutdownLevelValueKey));
1545        CFNumberGetValue(n_val, kCFNumberIntType, &val);
1546        printf("  %s\t%s\t%d\n", ARG_HALTAFTER, (kCFBooleanTrue==b)?"on":"off", val);
1547    }
1548    if((d = CFDictionaryGetValue(thresholds, CFSTR(kIOUPSShutdownAtMinutesLeft))))
1549    {
1550        b = CFDictionaryGetValue(d, CFSTR(kIOUPSShutdownLevelEnabledKey));
1551        n_val = CFDictionaryGetValue(d, CFSTR(kIOUPSShutdownLevelValueKey));
1552        CFNumberGetValue(n_val, kCFNumberIntType, &val);
1553        printf("  %s\t%s\t%d\n", ARG_HALTREMAIN, (kCFBooleanTrue==b)?"on":"off", val);
1554    }
1555    CFRelease(thresholds);
1556}
1557
1558static void
1559show_active_profiles(void)
1560{
1561    CFDictionaryRef             active_prof = 0;
1562    int                         i;
1563    int                         count;
1564    int                         val;
1565    CFNumberRef                 *prof_val = 0;
1566    CFStringRef                 *ps = NULL;
1567    char                        ps_str[40];
1568
1569    CFTypeRef                   ps_info = 0;
1570    CFStringRef                 current_ps = 0;
1571
1572    ps_info = IOPSCopyPowerSourcesInfo();
1573    if(ps_info) current_ps = IOPSGetProvidingPowerSourceType(ps_info);
1574    if(!ps_info || !current_ps) current_ps = CFSTR(kIOPMACPowerKey);
1575
1576    active_prof = IOPMCopyActivePowerProfiles();
1577    if(!active_prof) {
1578        printf("PM system error - no active profiles found\n");
1579        goto exit;
1580    }
1581
1582    count = CFDictionaryGetCount(active_prof);
1583    prof_val = (CFNumberRef *)malloc(sizeof(CFNumberRef)*count);
1584    ps = (CFStringRef *)malloc(sizeof(CFStringRef)*count);
1585    if(!prof_val || !ps) goto exit;
1586
1587    printf("Active Profiles:\n");
1588
1589    CFDictionaryGetKeysAndValues(active_prof, (const void **)ps, (const void **)prof_val);
1590    for(i=0; i<count; i++)
1591    {
1592        if( CFStringGetCString(ps[i], ps_str, 40, kCFStringEncodingMacRoman)
1593          && CFNumberGetValue(prof_val[i], kCFNumberIntType, &val)) {
1594            printf("%s\t\t%d", ps_str, val);
1595
1596            // Put a * next to the currently active power supply
1597            if( current_ps && (kCFCompareEqualTo == CFStringCompare(ps[i], current_ps, 0))) {
1598                printf("*");
1599            }
1600
1601            printf("\n");
1602        }
1603    }
1604
1605exit:
1606    if(active_prof) CFRelease(active_prof);
1607    if(ps_info) CFRelease(ps_info);
1608    if(prof_val) free(prof_val);
1609    if(ps) free(ps);
1610}
1611
1612static void
1613show_system_profiles(void)
1614{
1615    CFArrayRef                  sys_prof;
1616    int                         prof_count;
1617    int                         i;
1618
1619    sys_prof = IOPMCopyPowerProfiles();
1620    if(!sys_prof) {
1621        printf("No system profiles found\n");
1622        return;
1623    }
1624
1625    prof_count = CFArrayGetCount(sys_prof);
1626    for(i=0; i<prof_count;i++)
1627    {
1628        printf("=== Profile %d ===\n", i);
1629        show_power_profile( CFArrayGetValueAtIndex(sys_prof, i), 0 );
1630        if(i!=(prof_count-1)) printf("\n");
1631    }
1632
1633    CFRelease(sys_prof);
1634}
1635
1636static CFDictionaryRef
1637getPowerEvent(int type, CFDictionaryRef     events)
1638{
1639    if(type)
1640        return (CFDictionaryRef)isA_CFDictionary(CFDictionaryGetValue(events, CFSTR(kIOPMRepeatingPowerOnKey)));
1641    else
1642        return (CFDictionaryRef)isA_CFDictionary(CFDictionaryGetValue(events, CFSTR(kIOPMRepeatingPowerOffKey)));
1643}
1644static int
1645getRepeatingDictionaryMinutes(CFDictionaryRef event)
1646{
1647    int val;
1648    CFNumberRef tmp_num;
1649    tmp_num = (CFNumberRef)CFDictionaryGetValue(event, CFSTR(kIOPMPowerEventTimeKey));
1650    CFNumberGetValue(tmp_num, kCFNumberIntType, &val);
1651    return val;
1652}
1653static int
1654getRepeatingDictionaryDayMask(CFDictionaryRef event)
1655{
1656    int val;
1657    CFNumberRef tmp_num;
1658    tmp_num = (CFNumberRef)CFDictionaryGetValue(event, CFSTR(kIOPMDaysOfWeekKey));
1659    CFNumberGetValue(tmp_num, kCFNumberIntType, &val);
1660    return val;
1661}
1662static CFStringRef
1663getRepeatingDictionaryType(CFDictionaryRef event)
1664{
1665    return (CFStringRef)CFDictionaryGetValue(event, CFSTR(kIOPMPowerEventTypeKey));
1666}
1667
1668static void
1669print_time_of_day_to_buf(int m, char *buf, int buflen)
1670{
1671    int hours, minutes, afternoon;
1672
1673    hours = m/60;
1674    minutes = m%60;
1675    afternoon = 0;
1676    if(hours >= 12) afternoon = 1;
1677    if(hours > 12) hours-=12;
1678
1679    snprintf(buf, buflen, "%d:%d%d%cM", hours,
1680            minutes/10, minutes%10,
1681            (afternoon? 'P':'A'));
1682}
1683
1684static void
1685print_days_to_buf(int d, char *buf, int buflen)
1686{
1687    switch(d) {
1688        case daily_mask:
1689            snprintf(buf, buflen, "every day");
1690            break;
1691
1692        case weekday_mask:
1693            snprintf(buf, buflen, "weekdays only");
1694            break;
1695
1696        case weekend_mask:
1697            snprintf(buf, buflen, "weekends only");
1698            break;
1699
1700        case  0x01 :
1701            snprintf(buf, buflen, "Monday");
1702            break;
1703
1704        case  0x02 :
1705            snprintf(buf, buflen, "Tuesday");
1706            break;
1707
1708        case 0x04 :
1709            snprintf(buf, buflen, "Wednesday");
1710            break;
1711
1712        case  0x08 :
1713            snprintf(buf, buflen, "Thursday");
1714            break;
1715
1716        case 0x10 :
1717            snprintf(buf, buflen, "Friday");
1718            break;
1719
1720        case 0x20 :
1721            snprintf(buf, buflen, "Saturday");
1722            break;
1723
1724        case  0x40 :
1725            snprintf(buf, buflen, "Sunday");
1726            break;
1727
1728        default:
1729            snprintf(buf, buflen, "Some days");
1730            break;
1731    }
1732}
1733
1734#define kMaxDaysOfWeekLength     20
1735static void print_repeating_report(CFDictionaryRef repeat)
1736{
1737    CFDictionaryRef     on, off;
1738    char                time_buf[kMaxDaysOfWeekLength];
1739    char                day_buf[kMaxDaysOfWeekLength];
1740    CFStringRef         type_str = NULL;
1741    char                type_buf[kMaxArgStringLength];
1742
1743    // assumes validly formatted dictionary - doesn't do any error checking
1744    on = getPowerEvent(1, repeat);
1745    off = getPowerEvent(0, repeat);
1746
1747    if(on || off)
1748    {
1749        printf("Repeating power events:\n");
1750        if(on)
1751        {
1752            print_time_of_day_to_buf(getRepeatingDictionaryMinutes(on), time_buf, kMaxDaysOfWeekLength);
1753            print_days_to_buf(getRepeatingDictionaryDayMask(on), day_buf, kMaxDaysOfWeekLength);
1754
1755            type_str = getRepeatingDictionaryType(on);
1756            if (type_str) {
1757                CFStringGetCString(type_str, type_buf, sizeof(type_buf),  kCFStringEncodingMacRoman);
1758            } else {
1759                snprintf(type_buf, sizeof(type_buf), "?type?");
1760            }
1761
1762            printf("  %s at %s %s\n", type_buf, time_buf, day_buf);
1763        }
1764
1765        if(off)
1766        {
1767            print_time_of_day_to_buf(getRepeatingDictionaryMinutes(off), time_buf, kMaxDaysOfWeekLength);
1768            print_days_to_buf(getRepeatingDictionaryDayMask(off), day_buf, kMaxDaysOfWeekLength);
1769
1770            type_str = getRepeatingDictionaryType(off);
1771            if (type_str) {
1772                CFStringGetCString(type_str, type_buf, sizeof(type_buf),  kCFStringEncodingMacRoman);
1773            } else {
1774                snprintf(type_buf, sizeof(type_buf), "?type?");
1775            }
1776
1777            printf("  %s at %s %s\n", type_buf, time_buf, day_buf);
1778        }
1779        fflush(stdout);
1780    }
1781}
1782
1783static void
1784print_scheduled_report(CFArrayRef events)
1785{
1786    CFDictionaryRef     ev;
1787    int                 count, i;
1788    char                date_buf[40];
1789    char                name_buf[255];
1790    char                type_buf[40];
1791    char                *type_ptr = NULL;
1792    CFStringRef         type = NULL;
1793    CFStringRef         author = NULL;
1794    CFDateFormatterRef  formatter = NULL;
1795    CFStringRef         cf_str_date = NULL;
1796
1797    if(!events || !(count = CFArrayGetCount(events))) return;
1798
1799    formatter = CFDateFormatterCreate(kCFAllocatorDefault, CFLocaleGetSystem(),
1800                                      kCFDateFormatterShortStyle, kCFDateFormatterMediumStyle);
1801    CFDateFormatterSetFormat(formatter, CFSTR(kDateAndTimeFormat));
1802
1803    printf("Scheduled power events:\n");
1804    for(i=0; i<count; i++)
1805    {
1806        ev = (CFDictionaryRef)CFArrayGetValueAtIndex(events, i);
1807
1808        cf_str_date = CFDateFormatterCreateStringWithDate(kCFAllocatorDefault,
1809                formatter, CFDictionaryGetValue(ev, CFSTR(kIOPMPowerEventTimeKey)));
1810        date_buf[0] = 0;
1811        if(cf_str_date) {
1812            CFStringGetCString(cf_str_date, date_buf, 40, kCFStringEncodingMacRoman);
1813            CFRelease(cf_str_date);
1814        }
1815
1816        author = CFDictionaryGetValue(ev, CFSTR(kIOPMPowerEventAppNameKey));
1817        name_buf[0] = 0;
1818        if(isA_CFString(author))
1819            CFStringGetCString(author, name_buf, 255, kCFStringEncodingMacRoman);
1820
1821        type = CFDictionaryGetValue(ev, CFSTR(kIOPMPowerEventTypeKey));
1822        type_buf[0] = 0;
1823        if(isA_CFString(type))
1824            CFStringGetCString(type, type_buf, 40, kCFStringEncodingMacRoman);
1825
1826        // rename "wakepoweron" to "wakeorpoweron" to make things consistent between
1827        // "pmset -g" and "pmset sched"
1828        if(!strcmp(type_buf, kIOPMAutoWakeOrPowerOn))
1829            type_ptr = ARG_WAKEORPOWERON;
1830        else
1831            type_ptr = type_buf;
1832
1833        printf(" [%d]  %s at %s", i, type_ptr, date_buf);
1834        if(name_buf[0]) printf(" by %s", name_buf);
1835        printf("\n");
1836    }
1837
1838    if (formatter)
1839        CFRelease(formatter);
1840}
1841
1842static void show_scheduled_events(void)
1843{
1844    CFDictionaryRef     repeatingEvents;
1845    CFArrayRef          scheduledEvents;
1846
1847    repeatingEvents = IOPMCopyRepeatingPowerEvents();
1848    scheduledEvents = IOPMCopyScheduledPowerEvents();
1849
1850    if(!repeatingEvents && !scheduledEvents) {
1851        printf("No scheduled events.\n"); fflush(stdout);
1852        return;
1853    }
1854
1855    if(repeatingEvents) {
1856        print_repeating_report(repeatingEvents);
1857        CFRelease(repeatingEvents);
1858    }
1859
1860    if(scheduledEvents) {
1861        print_scheduled_report(scheduledEvents);
1862        CFRelease(scheduledEvents);
1863    }
1864}
1865
1866static bool matchingAssertion(CFDictionaryRef asst_dict, CFStringRef asst)
1867{
1868    if(!asst_dict || (kCFBooleanFalse == (CFTypeRef)asst_dict)) return false;
1869
1870    return CFEqual(asst,
1871                   CFDictionaryGetValue(asst_dict, kIOPMAssertionTypeKey));
1872}
1873
1874
1875static void show_active_assertions(uint32_t which)
1876{
1877    // Print active DisableInflow or ChargeInhibit assertions on the
1878    // following line
1879    CFDictionaryRef         assertions_status = NULL;
1880    CFDictionaryRef         assertions_by_pid = NULL;
1881    CFStringRef             *assertionNames = NULL;
1882    CFNumberRef             *assertionValues = NULL;
1883    CFNumberRef             *pids = NULL;
1884    CFArrayRef              *pidAssertions = NULL;
1885    char                    name[50];
1886    int                     val;
1887    int                     total_assertion_count;
1888    int                     pid_count;
1889    IOReturn                ret;
1890    int                     i, j, k;
1891
1892    if(0 == which) return;
1893
1894    ret = IOPMCopyAssertionsStatus(&assertions_status);
1895    if(kIOReturnSuccess != ret || !assertions_status)
1896        return;
1897
1898    ret = IOPMCopyAssertionsByProcess(&assertions_by_pid);
1899    if(kIOReturnSuccess != ret || !assertions_by_pid)
1900        return;
1901
1902    // Grab out the total/aggregate sate of the assertions
1903    total_assertion_count = CFDictionaryGetCount(assertions_status);
1904    if(0 == total_assertion_count)
1905        return;
1906
1907    assertionNames = (CFStringRef *)malloc(
1908                                sizeof(CFStringRef) * total_assertion_count);
1909    assertionValues = (CFNumberRef *)malloc(
1910                                sizeof(CFNumberRef) * total_assertion_count);
1911    CFDictionaryGetKeysAndValues(assertions_status,
1912                                (const void **)assertionNames,
1913                                (const void **)assertionValues);
1914
1915    // Grab the list of activated assertions per-process
1916    pid_count = CFDictionaryGetCount(assertions_by_pid);
1917    if(0 == pid_count)
1918        return;
1919
1920    pids = malloc(sizeof(CFNumberRef) * pid_count);
1921    pidAssertions = malloc(sizeof(CFArrayRef) * pid_count);
1922
1923    CFDictionaryGetKeysAndValues(assertions_by_pid,
1924                                (const void **)pids,
1925                                (const void **)pidAssertions);
1926
1927    if ( assertionNames && assertionValues && pidAssertions && pids)
1928    {
1929
1930        for(i=0; i<total_assertion_count; i++)
1931        {
1932            CFStringGetCString(assertionNames[i], name, 50, kCFStringEncodingMacRoman);
1933            CFNumberGetValue(assertionValues[i], kCFNumberIntType, &val);
1934
1935            // Determine if we want to display this assertion
1936            if( !( ( (which & kAssertionCPU) &&
1937                    CFEqual(assertionNames[i], kIOPMCPUBoundAssertion))
1938                || ( (which & kAssertionInflow) &&
1939                    CFEqual(assertionNames[i], kIOPMInflowDisableAssertion))
1940                || ( (which & kAssertionCharge) &&
1941                    CFEqual(assertionNames[i], kIOPMChargeInhibitAssertion))
1942                || ( (which & kAssertionIdle) &&
1943                    CFEqual(assertionNames[i], kIOPMAssertionTypeNoIdleSleep)) ) )
1944            {
1945                // If the caller wasn't interested is this assertion, we pass
1946                continue;
1947            }
1948
1949            if(val)
1950            {
1951                printf("\t'%s':\t", name);
1952                for(j=0; j<pid_count; j++)
1953                {
1954                    for(k=0; k<CFArrayGetCount(pidAssertions[j]); k++)
1955                    {
1956                        CFDictionaryRef     obj;
1957                        if( (obj = (CFDictionaryRef)CFArrayGetValueAtIndex(
1958                                            pidAssertions[j], k)))
1959                        {
1960                            if(matchingAssertion(obj, assertionNames[i]))
1961                            {
1962                                int pid_num = 0;
1963                                CFNumberGetValue(pids[j], kCFNumberIntType, &pid_num);
1964                                printf("%d ", pid_num);
1965                            }
1966                       }
1967                    }
1968                }
1969                printf("\n"); fflush(stdout);
1970            }
1971        }
1972    }
1973    if (assertionNames) free(assertionNames);
1974    if (assertionValues) free(assertionValues);
1975    if (pidAssertions) free(pidAssertions);
1976    if (pids) free(pids);
1977    if (assertions_status) CFRelease(assertions_status);
1978    if (assertions_by_pid) CFRelease(assertions_by_pid);
1979
1980    return;
1981}
1982
1983/******************************************************************************/
1984/*                                                                            */
1985/*      BLOCK IDLE SLEEP                                                      */
1986/*                                                                            */
1987/******************************************************************************/
1988
1989static bool prevent_idle_sleep(void)
1990{
1991    IOPMAssertionID         neverSleep;
1992
1993    if (kIOReturnSuccess !=
1994        IOPMAssertionCreateWithName(kIOPMAssertionTypeNoIdleSleep,
1995                            kIOPMAssertionLevelOn,
1996                            CFSTR("pmset prevent sleep"),
1997                            &neverSleep))
1998    {
1999        // Failure
2000        return false;
2001    }
2002
2003    printf("Preventing idle sleep (^C to exit)...\n");
2004
2005    // ctrl-c at command-line exits
2006    while(1) {
2007        sleep(100);
2008    }
2009
2010    return true;
2011}
2012enum {
2013    kPrintLotsOfThings  = 0,
2014    kJustPrintSleep     = 1,
2015    kJustPrintWake      = 2
2016};
2017
2018static void printSleepAndWakeReasons(int just_do_it)
2019{
2020    CFStringRef lastSleepReason     = copyRootDomainProperty(CFSTR("Last Sleep Reason"));
2021    CFStringRef wakeReason          = copyRootDomainProperty(CFSTR("Wake Reason"));
2022    CFStringRef wakeType            = copyRootDomainProperty(CFSTR("Wake Type"));
2023    char buf[100];
2024
2025    if (just_do_it != kJustPrintWake)
2026    {
2027        if (lastSleepReason) {
2028            CFStringGetCString(lastSleepReason, buf, sizeof(buf), kCFStringEncodingUTF8);
2029            printf("  Last Sleep Reason = %s\n", buf);
2030        }
2031    }
2032
2033    if (just_do_it != kJustPrintSleep)
2034    {
2035        if (wakeReason) {
2036            CFStringGetCString(wakeReason, buf, sizeof(buf), kCFStringEncodingUTF8);
2037            printf("  Wake Reason = %s\n", buf);
2038        }
2039        if (wakeType) {
2040            CFStringGetCString(wakeType, buf, sizeof(buf), kCFStringEncodingUTF8);
2041            printf("  wakeType = %s\n", buf);
2042        }
2043    }
2044
2045    if (lastSleepReason)        { CFRelease(lastSleepReason); }
2046    if (wakeReason)             { CFRelease(wakeReason); }
2047    if (wakeType)               { CFRelease(wakeType); }
2048
2049    return;
2050}
2051
2052
2053/* sleepWakeCallback
2054 *
2055 * Receives notifications on system sleep and system wake.
2056 */
2057static void
2058sleepWakeCallback(
2059    void *refcon,
2060    io_service_t y __unused,
2061    natural_t messageType,
2062    void * messageArgument)
2063{
2064    uint32_t behavior = (uintptr_t)refcon;
2065
2066    switch ( messageType ) {
2067    case kIOMessageSystemWillSleep:
2068        if ( behavior & kLogSleepEvents )
2069        {
2070            printf("\n");
2071            print_pretty_date(CFAbsoluteTimeGetCurrent(), false);
2072            printf("IORegisterForSystemPower: ...Sleeping...\n");
2073//            printSleepAndWakeReasons(kJustPrintSleep);
2074            fflush(stdout);
2075        }
2076
2077        IOAllowPowerChange(gPMAckPort, (long)messageArgument);
2078        break;
2079
2080    case kIOMessageCanSystemSleep:
2081        if( behavior & kCancelSleepEvents )
2082        {
2083            IOCancelPowerChange(gPMAckPort, (long)messageArgument);
2084            printf("\n");
2085            print_pretty_date(CFAbsoluteTimeGetCurrent(), false);
2086            printf("IORegisterForSystemPower: ...Cancelling...\n");
2087//            printSleepAndWakeReasons(kJustPrintSleep);
2088        } else {
2089            IOAllowPowerChange(gPMAckPort, (long)messageArgument);
2090        }
2091        break;
2092
2093    case kIOMessageSystemHasPoweredOn:
2094        if ( behavior & kLogSleepEvents )
2095        {
2096            printf("\n");
2097            print_pretty_date(CFAbsoluteTimeGetCurrent(), false);   // false == no newline
2098            printf("IORegisterForSystemPower: ...HasPoweredOn...\n");
2099            printSleepAndWakeReasons(kJustPrintWake);
2100            fflush(stdout);
2101        }
2102        break;
2103    }
2104
2105    return;
2106}
2107
2108
2109
2110/******************************************************************************/
2111/*                                                                            */
2112/*     PS LOGGING                                                             */
2113/*                                                                            */
2114/******************************************************************************/
2115
2116#define kMaxHealthLength            10
2117#define kMaxNameLength              60
2118
2119static void show_power_sources(int which)
2120{
2121    CFTypeRef           ps_info = IOPSCopyPowerSourcesInfo();
2122    CFArrayRef          list = NULL;
2123    CFStringRef         ps_name = NULL;
2124    static CFStringRef  last_ps = NULL;
2125    static CFAbsoluteTime   invocationTime = 0.0;
2126    CFDictionaryRef     one_ps = NULL;
2127    char                strbuf[kMaxLongStringLength];
2128    int                 count;
2129    int                 i;
2130    int                 show_time_estimate;
2131    CFNumberRef         remaining, charge, capacity;
2132    CFBooleanRef        charging;
2133    CFBooleanRef        charged;
2134    CFBooleanRef        finishingCharge;
2135    CFBooleanRef        present;
2136    CFStringRef         name;
2137    CFStringRef         state;
2138    CFStringRef         transport;
2139    CFStringRef         health;
2140    CFStringRef         confidence;
2141    CFStringRef         failure;
2142    char                _health[kMaxHealthLength];
2143    char                _confidence[kMaxHealthLength];
2144    char                _name[kMaxNameLength];
2145    char                _failure[kMaxLongStringLength];
2146    int                 _hours = 0;
2147    int                 _minutes = 0;
2148    int                 _charge = 0;
2149    int                 _FCCap = 0;
2150    bool                _charging = false;
2151    bool                _charged = false;
2152    bool                _finishingCharge = false;
2153    int                 _warningLevel = 0;
2154    CFArrayRef          permFailuresArray = NULL;
2155    CFStringRef         pfString = NULL;
2156
2157    if(!ps_info) {
2158        printf("No power source info available\n");
2159        return;
2160    }
2161
2162    if (isBatteryPollingStopped()) {
2163        printf("* Battery Polling is Stopped by \"pmset nopoll\" *\n");
2164    }
2165
2166    /* Output path for Time Remaining Columns
2167     *  - Only displays battery
2168     */
2169    if (kShowColumns & which)
2170    {
2171        CFTypeRef               one_ps_descriptor = NULL;
2172        CFAbsoluteTime          nowTime = CFAbsoluteTimeGetCurrent();
2173        uint32_t                minutesSinceInvocation = 0;
2174        int32_t                 estimatedMinutesRemaining = 0;
2175
2176        if (invocationTime == 0.0) {
2177            invocationTime = nowTime;
2178        }
2179
2180        // Note: We assume a one-battery system.
2181        one_ps_descriptor = IOPSGetActiveBattery(ps_info);
2182        if (one_ps_descriptor) {
2183            one_ps = IOPSGetPowerSourceDescription(ps_info, one_ps_descriptor);
2184        }
2185        if(!one_ps) {
2186            printf("Logging power sources: unable to locate battery.\n");
2187            goto exit;
2188        };
2189
2190        charging = CFDictionaryGetValue(one_ps, CFSTR(kIOPSIsChargingKey));
2191        state = CFDictionaryGetValue(one_ps, CFSTR(kIOPSPowerSourceStateKey));
2192        if (CFEqual(state, CFSTR(kIOPSBatteryPowerValue)))
2193        {
2194            remaining = CFDictionaryGetValue(one_ps, CFSTR(kIOPSTimeToEmptyKey));
2195        } else {
2196            remaining = CFDictionaryGetValue(one_ps, CFSTR(kIOPSTimeToFullChargeKey));
2197        }
2198
2199        if (remaining) {
2200            CFNumberGetValue(remaining, kCFNumberIntType, &estimatedMinutesRemaining);
2201        } else {
2202            estimatedMinutesRemaining = -1;
2203        }
2204
2205        minutesSinceInvocation = (nowTime - invocationTime)/60;
2206
2207        charge = CFDictionaryGetValue(one_ps, CFSTR(kIOPSCurrentCapacityKey));
2208        if(charge) CFNumberGetValue(charge, kCFNumberIntType, &_charge);
2209
2210        //  "Elapsed", "TimeRemaining", "Percent""Charge", "Timestamp");
2211        printf("%10d\t%15d\t%10d%%\t%10s\t", minutesSinceInvocation, estimatedMinutesRemaining,
2212                    _charge, (kCFBooleanTrue == charging) ? "charge" : "discharge");
2213        print_pretty_date(CFAbsoluteTimeGetCurrent(), true);
2214
2215        goto exit;
2216    }
2217    /* Completed output path
2218     */
2219
2220    ps_name = IOPSGetProvidingPowerSourceType(ps_info);
2221    if(!ps_name || !CFStringGetCString(ps_name, strbuf, kMaxLongStringLength, kCFStringEncodingUTF8))
2222    {
2223        goto exit;
2224    }
2225    if(!last_ps || kCFCompareEqualTo != CFStringCompare(last_ps, ps_name, 0))
2226    {
2227        printf("Now drawing from '%s'\n", strbuf);
2228    }
2229    if(last_ps) CFRelease(last_ps);
2230    last_ps = CFStringCreateCopy(kCFAllocatorDefault, ps_name);
2231
2232    list = IOPSCopyPowerSourcesList(ps_info);
2233    if(!list) goto exit;
2234    count = CFArrayGetCount(list);
2235    for(i=0; i<count; i++)
2236    {
2237        bzero(_health, sizeof(_health));
2238        bzero(_confidence, sizeof(_confidence));
2239        bzero(_name, sizeof(_name));
2240        bzero(_failure, sizeof(_failure));
2241        _hours = _minutes = _charge = _FCCap = 0;
2242        _charging = _charged = _finishingCharge = false;
2243
2244        one_ps = IOPSGetPowerSourceDescription(ps_info, CFArrayGetValueAtIndex(list, i));
2245        if(!one_ps) break;
2246
2247        // Only display settings for power sources we want to show
2248        transport = CFDictionaryGetValue(one_ps, CFSTR(kIOPSTransportTypeKey));
2249        if(!transport) continue;
2250        if(kCFCompareEqualTo != CFStringCompare(transport, CFSTR(kIOPSInternalType), 0))
2251        {
2252            // Internal transport means internal battery
2253            if(!(which & kApplyToBattery)) continue;
2254        } else {
2255            // Any specified non-Internal transport is a UPS
2256            if(!(which & kApplyToUPS)) continue;
2257        }
2258
2259        charging = CFDictionaryGetValue(one_ps, CFSTR(kIOPSIsChargingKey));
2260        state = CFDictionaryGetValue(one_ps, CFSTR(kIOPSPowerSourceStateKey));
2261        if(kCFCompareEqualTo == CFStringCompare(state, CFSTR(kIOPSBatteryPowerValue), 0))
2262        {
2263            remaining = CFDictionaryGetValue(one_ps, CFSTR(kIOPSTimeToEmptyKey));
2264        } else {
2265            remaining = CFDictionaryGetValue(one_ps, CFSTR(kIOPSTimeToFullChargeKey));
2266        }
2267        name = CFDictionaryGetValue(one_ps, CFSTR(kIOPSNameKey));
2268        charge = CFDictionaryGetValue(one_ps, CFSTR(kIOPSCurrentCapacityKey));
2269        capacity = CFDictionaryGetValue(one_ps, CFSTR(kIOPSMaxCapacityKey));
2270        present = CFDictionaryGetValue(one_ps, CFSTR(kIOPSIsPresentKey));
2271        health = CFDictionaryGetValue(one_ps, CFSTR(kIOPSBatteryHealthKey));
2272        confidence = CFDictionaryGetValue(one_ps, CFSTR(kIOPSHealthConfidenceKey));
2273        failure = CFDictionaryGetValue(one_ps, CFSTR("Failure"));
2274        charged = CFDictionaryGetValue(one_ps, CFSTR(kIOPSIsChargedKey));
2275        finishingCharge = CFDictionaryGetValue(one_ps, CFSTR(kIOPSIsFinishingChargeKey));
2276
2277        permFailuresArray = CFDictionaryGetValue(one_ps, CFSTR(kIOPSBatteryFailureModesKey));
2278
2279        if(name) CFStringGetCString(name, _name,
2280                                kMaxNameLength, kCFStringEncodingMacRoman);
2281        if(health) CFStringGetCString(health, _health,
2282                                kMaxHealthLength, kCFStringEncodingMacRoman);
2283        if(confidence) CFStringGetCString(confidence, _confidence,
2284                                kMaxHealthLength, kCFStringEncodingMacRoman);
2285        if(failure) CFStringGetCString(failure, _failure,
2286                                kMaxLongStringLength, kCFStringEncodingMacRoman);
2287        if(charge) CFNumberGetValue(charge, kCFNumberIntType, &_charge);
2288        if(capacity) CFNumberGetValue(capacity, kCFNumberIntType, &_FCCap);
2289        if(remaining)
2290        {
2291            CFNumberGetValue(remaining, kCFNumberIntType, &_minutes);
2292            if(-1 != _minutes) {
2293                _hours = _minutes/60;
2294                _minutes = _minutes%60;
2295            }
2296        }
2297        if(charging) _charging = (kCFBooleanTrue == charging);
2298        if (charged) _charged = (kCFBooleanTrue == charged);
2299        if (finishingCharge) _finishingCharge = (kCFBooleanTrue == finishingCharge);
2300
2301        _warningLevel = IOPSGetBatteryWarningLevel();
2302
2303        show_time_estimate = 1;
2304
2305        printf(" -");
2306        if(name) printf("%s\t", _name);
2307        if(present && (kCFBooleanTrue == present))
2308        {
2309            if(charge && _FCCap) printf("%d%%; ", _charge*100/_FCCap);
2310            if(charging) {
2311                if (_finishingCharge) {
2312                    printf("finishing charge");
2313                } else if (_charged) {
2314                    printf("charged");
2315                } else if(_charging) {
2316                    printf("charging");
2317                } else {
2318                    if(kCFCompareEqualTo == CFStringCompare(state, CFSTR(kIOPSACPowerValue), 0)) {
2319                        printf("AC attached; not charging");
2320                        show_time_estimate = 0;
2321                    } else {
2322                        printf("discharging");
2323                    }
2324                }
2325            }
2326            if(show_time_estimate && remaining) {
2327                if(-1 != _minutes) {
2328                    printf("; %d:%d%d remaining", _hours, _minutes/10, _minutes%10);
2329                } else {
2330                    printf("; (no estimate)");
2331                }
2332            }
2333            if (health && confidence
2334                && !CFEqual(CFSTR("Good"), health)) {
2335                printf(" (%s/%s)", _health, _confidence);
2336            }
2337            if(failure) {
2338                printf("\n\tfailure: \"%s\"", _failure);
2339            }
2340            if (permFailuresArray) {
2341                int failure_count = CFArrayGetCount(permFailuresArray);
2342                int m = 0;
2343
2344                printf("\n\tDetailed failures:");
2345
2346                for(m=0; m<failure_count; m++) {
2347                    pfString = CFArrayGetValueAtIndex(permFailuresArray, m);
2348                    if (pfString)
2349                    {
2350                        CFStringGetCString(pfString, strbuf, kMaxLongStringLength, kCFStringEncodingMacRoman);
2351                        printf(" \"%s\"", strbuf);
2352                    }
2353                    if (m != failure_count - 1)
2354                        printf(",");
2355                }
2356            }
2357            printf("\n"); fflush(stdout);
2358
2359            // Show batery warnings on a new line:
2360            if (kIOPSLowBatteryWarningEarly == _warningLevel) {
2361                printf("\tBattery Warning: Early\n");
2362            } else if (kIOPSLowBatteryWarningFinal == _warningLevel) {
2363                printf("\tBattery Warning: Final\n");
2364            }
2365        } else {
2366            printf(" (removed)\n");
2367        }
2368
2369
2370    }
2371
2372    // Display the battery-specific assertions that are affecting the system
2373    show_active_assertions( kAssertionInflow | kAssertionCharge );
2374
2375exit:
2376    if(ps_info) CFRelease(ps_info);
2377    if(list) CFRelease(list);
2378    return;
2379}
2380
2381static void print_pretty_date(CFAbsoluteTime t, bool newline)
2382{
2383    print_date_with_style("%-24.24s ", kCFDateFormatterShortStyle, kCFDateFormatterLongStyle, t, newline);
2384}
2385
2386static void print_short_date(CFAbsoluteTime t, bool newline)
2387{
2388    print_date_with_style("%s ", kCFDateFormatterShortStyle, kCFDateFormatterShortStyle, t, newline);
2389}
2390
2391
2392static void print_date_with_style(const char *dsf, CFDateFormatterStyle dayStyle, CFDateFormatterStyle timeStyle, CFAbsoluteTime t, bool newline)
2393{
2394    CFDateFormatterRef  date_format;
2395    CFTimeZoneRef       tz;
2396    CFStringRef         time_date;
2397    CFLocaleRef         loc;
2398    char                _date[60];
2399
2400    loc = CFLocaleCopyCurrent();
2401    date_format = CFDateFormatterCreate(kCFAllocatorDefault, loc,
2402        dayStyle, timeStyle);
2403    CFRelease(loc);
2404    tz = CFTimeZoneCopySystem();
2405    CFDateFormatterSetProperty(date_format, kCFDateFormatterTimeZone, tz);
2406    CFRelease(tz);
2407    time_date = CFDateFormatterCreateStringWithAbsoluteTime(kCFAllocatorDefault,
2408        date_format, t);
2409    CFRelease(date_format);
2410
2411    if(time_date)
2412    {
2413        CFStringGetCString(time_date, _date, 60, kCFStringEncodingMacRoman);
2414        printf(dsf, _date); fflush(stdout);
2415        if(newline) printf("\n");
2416        CFRelease(time_date);
2417    }
2418}
2419
2420/******************************************************************************/
2421
2422static void show_assertions_system_aggregates(void)
2423{
2424    /*
2425     *   Copy aggregates
2426     */
2427    CFStringRef             *assertionNames = NULL;
2428    CFNumberRef             *assertionValues = NULL;
2429    char                    name[50];
2430    int                     val;
2431    int                     count;
2432    CFDictionaryRef         assertions_status;
2433    IOReturn                ret;
2434    int                     i;
2435
2436    ret = IOPMCopyAssertionsStatus(&assertions_status);
2437    if ((kIOReturnSuccess != ret) || (NULL == assertions_status))
2438    {
2439        printf("No assertions.\n");
2440        return;
2441    }
2442
2443    count = CFDictionaryGetCount(assertions_status);
2444    if (0 == count)
2445    {
2446        return;
2447    }
2448
2449    assertionNames = (CFStringRef *)malloc(sizeof(void *)*count);
2450    assertionValues = (CFNumberRef *)malloc(sizeof(void *)*count);
2451    CFDictionaryGetKeysAndValues(assertions_status,
2452                                 (const void **)assertionNames, (const void **)assertionValues);
2453
2454    printf("Assertion status system-wide:\n");
2455    for (i=0; i<count; i++)
2456    {
2457        CFNumberGetValue(assertionValues[i], kCFNumberIntType, &val);
2458        if ((kCFCompareEqualTo == CFStringCompare(assertionNames[i], kIOPMAssertionTypeNeedsCPU, 0)) ||
2459            (kCFCompareEqualTo == CFStringCompare(assertionNames[i], kIOPMAssertionTypeDisableInflow, 0)) ||
2460            (kCFCompareEqualTo == CFStringCompare(assertionNames[i], kIOPMAssertionTypeInhibitCharging, 0)) ||
2461            (kCFCompareEqualTo == CFStringCompare(assertionNames[i], kIOPMAssertionTypeDisableLowBatteryWarnings, 0)) ||
2462            (kCFCompareEqualTo == CFStringCompare(assertionNames[i], kIOPMAssertInternalPreventSleep, 0)) ||
2463            (kCFCompareEqualTo == CFStringCompare(assertionNames[i], kIOPMAssertInternalPreventDisplaySleep, 0)) ||
2464            (kCFCompareEqualTo == CFStringCompare(assertionNames[i], kIOPMAssertDisplayWake, 0)) ||
2465            (kCFCompareEqualTo == CFStringCompare(assertionNames[i], kIOPMAssertionTypeDisableRealPowerSources_Debug, 0)))
2466        {
2467            /* These are rarely used. So, print only if they are set */
2468            if (val == 0)
2469                continue;
2470        }
2471
2472#if !TARGET_OS_EMBEDDED
2473        if ((kCFCompareEqualTo == CFStringCompare(assertionNames[i], kIOPMAssertionTypeEnableIdleSleep, 0)) ||
2474            (kCFCompareEqualTo == CFStringCompare(assertionNames[i], kIOPMAssertionTypeSystemIsActive, 0)))
2475            continue;
2476#endif
2477
2478        CFStringGetCString(assertionNames[i], name, 50, kCFStringEncodingMacRoman);
2479        printf("   %-30s %d\n", name, val);
2480    }
2481
2482    free(assertionNames);
2483    free(assertionValues);
2484    CFRelease(assertions_status);
2485}
2486
2487static void show_assertions_individually(void)
2488{
2489    CFDictionaryRef         assertions_info = NULL;
2490    IOReturn                ret;
2491
2492    ret = IOPMCopyAssertionsByProcess(&assertions_info);
2493    if ((kIOReturnSuccess != ret) || !assertions_info) {
2494        return;
2495    }
2496
2497//    printf("\nListed by owning process:\n");
2498    printf("Listed by owning process:\n");
2499    if (!assertions_info) {
2500        printf("   None\n");
2501    } else {
2502
2503        CFNumberRef             *pids = NULL;
2504        CFArrayRef              *assertions = NULL;
2505        int                     process_count;
2506        int                     i;
2507
2508        process_count = CFDictionaryGetCount(assertions_info);
2509        pids = malloc(sizeof(CFNumberRef)*process_count);
2510        assertions = malloc(sizeof(CFArrayRef *)*process_count);
2511        CFDictionaryGetKeysAndValues(assertions_info,
2512                                     (const void **)pids,
2513                                     (const void **)assertions);
2514
2515        for(i=0; i<process_count; i++)
2516        {
2517            int the_pid;
2518            int j;
2519
2520            CFNumberGetValue(pids[i], kCFNumberIntType, &the_pid);
2521
2522            for(j=0; j<CFArrayGetCount(assertions[i]); j++)
2523            {
2524                CFDictionaryRef         tmp_dict = NULL;
2525                CFStringRef             val_string = NULL;
2526                CFStringRef             raw_localizable_string = NULL;
2527                CFStringRef             localized_string = NULL;
2528                CFStringRef             bundlePath = NULL;
2529                CFBundleRef             bundle = NULL;
2530                CFURLRef                _url = NULL;
2531                CFNumberRef             uniqueID = NULL;
2532                CFBooleanRef            power_limits = NULL;
2533                uint64_t                uniqueID_int = 0;
2534                CFDateRef               createdDate = NULL;
2535                CFAbsoluteTime          createdCFTime = 0.0;
2536                char                    ageString[40];
2537                CFStringRef             pidName = NULL;
2538                char                    pid_name_buf[100];
2539
2540                char                    all_assertions_buf[400];
2541                char                    val_buf[300];
2542                bool                    timed_out = false;
2543
2544                tmp_dict = CFArrayGetValueAtIndex(assertions[i], j);
2545                if(!tmp_dict) {
2546                    goto exit;
2547                }
2548
2549                bzero(all_assertions_buf, sizeof(all_assertions_buf));
2550
2551                val_string = CFDictionaryGetValue(tmp_dict, kIOPMAssertionTypeKey);
2552                if (val_string) {
2553                    CFStringGetCString(val_string, all_assertions_buf, sizeof(all_assertions_buf), kCFStringEncodingMacRoman);
2554                } else {
2555                    snprintf(all_assertions_buf, sizeof(all_assertions_buf), "Missing AssertType property");
2556                }
2557
2558                val_string = CFDictionaryGetValue(tmp_dict, kIOPMAssertionNameKey);
2559                if (val_string) {
2560                    CFStringGetCString(val_string, val_buf, sizeof(val_buf), kCFStringEncodingMacRoman);
2561                }
2562
2563                timed_out = CFDictionaryGetValue(tmp_dict, kIOPMAssertionTimedOutDateKey);
2564
2565                uniqueID = CFDictionaryGetValue(tmp_dict, kIOPMAssertionGlobalUniqueIDKey);
2566                if (uniqueID) {
2567                    CFNumberGetValue(uniqueID, kCFNumberSInt64Type, &uniqueID_int);
2568                }
2569
2570                if ((createdDate = CFDictionaryGetValue(tmp_dict, kIOPMAssertionCreateDateKey)))
2571                {
2572                    createdCFTime                   = CFDateGetAbsoluteTime(createdDate);
2573                    int createdSince                = (int)(CFAbsoluteTimeGetCurrent() - createdCFTime);
2574                    int hours                       = createdSince / 3600;
2575                    int minutes                     = (createdSince / 60) % 60;
2576                    int seconds                     = createdSince % 60;
2577                    snprintf(ageString, sizeof(ageString), "%02d:%02d:%02d ", hours, minutes, seconds);
2578                }
2579
2580                if ((pidName = CFDictionaryGetValue(tmp_dict, kIOPMAssertionProcessNameKey)))
2581                {
2582                    CFStringGetCString(pidName, pid_name_buf, sizeof(pid_name_buf), kCFStringEncodingUTF8);
2583                }
2584
2585                printf("   pid %d(%s): [0x%016llx] %s%s named: \"%s\" %s\n",
2586                       the_pid, pidName?pid_name_buf:"?",
2587                       uniqueID_int,
2588                       createdDate ? ageString:"",
2589                       all_assertions_buf,
2590                       val_string ? val_buf : "(error - no name)",
2591                       timed_out ? "(timed out)" : "");
2592
2593                val_string = CFDictionaryGetValue(tmp_dict, kIOPMAssertionDetailsKey);
2594                if (val_string) {
2595                    CFStringGetCString(val_string, val_buf, sizeof(val_buf), kCFStringEncodingMacRoman);
2596                    printf("\tDetails: %s\n", val_buf);
2597                }
2598
2599                raw_localizable_string = CFDictionaryGetValue(tmp_dict, kIOPMAssertionHumanReadableReasonKey);
2600                bundlePath = CFDictionaryGetValue(tmp_dict, kIOPMAssertionLocalizationBundlePathKey);
2601
2602                if (raw_localizable_string && bundlePath) {
2603                    _url = CFURLCreateWithFileSystemPath(0, bundlePath, kCFURLPOSIXPathStyle, TRUE);
2604                    if (_url) {
2605                        bundle = CFBundleCreate(0, _url);
2606                        CFRelease(_url);
2607                    }
2608                    if (bundle) {
2609
2610                        localized_string = CFBundleCopyLocalizedString(bundle, raw_localizable_string, NULL, NULL);
2611
2612                        if (localized_string) {
2613                            if (CFStringGetCString(localized_string, val_buf, sizeof(val_buf), kCFStringEncodingUTF8)) {
2614                                printf("\tLocalized=%s\n", val_buf);
2615                            }
2616                            CFRelease(localized_string);
2617                        }
2618                    }
2619                } // Localize & display human readable string
2620
2621                if ( (power_limits = CFDictionaryGetValue(tmp_dict,
2622                                                          kIOPMAssertionAppliesToLimitedPowerKey)) ) {
2623                    if ((CFBooleanGetValue(power_limits)))
2624                        printf("\tAssertion applied on Battery power also\n");
2625                    else
2626                        printf("\tAssertion applied on AC  power only\n");
2627                }
2628
2629                CFNumberRef         timeoutNumCF    = NULL;
2630                uint64_t            timeout         = 0;
2631                CFStringRef         actionStr       = NULL;
2632                char                actionBuf[55];
2633                CFDateRef           updateDate      = NULL;
2634                CFAbsoluteTime      updateTime      = 0;
2635                CFTimeInterval      timeLeft      = 0;
2636                CFAbsoluteTime      now             = CFAbsoluteTimeGetCurrent();
2637
2638                if ( (timeoutNumCF = CFDictionaryGetValue(tmp_dict, kIOPMAssertionTimeoutTimeLeftKey)))
2639                {
2640                    CFNumberGetValue(timeoutNumCF, kCFNumberIntType, &timeout);
2641
2642                    updateDate = CFDictionaryGetValue(tmp_dict, kIOPMAssertionTimeoutUpdateTimeKey);
2643                    if (updateDate) {
2644                        updateTime = CFDateGetAbsoluteTime(updateDate);
2645                    }
2646
2647                    if (timeout && updateDate && ((timeLeft = updateTime+timeout-now) > 0)) {
2648
2649                        actionStr = CFDictionaryGetValue(tmp_dict, kIOPMAssertionTimeoutActionKey);
2650                        if (actionStr) {
2651                            CFStringGetCString(actionStr, actionBuf, sizeof(actionBuf), kCFStringEncodingUTF8);
2652                        }
2653
2654                        printf("\tTimeout will fire in %.0f secs Action=%s\n",
2655                               timeLeft, actionStr ? actionBuf : "<unknown action>");
2656                    }
2657                }
2658            }
2659        }
2660    }
2661
2662exit:
2663    if(assertions_info)
2664        CFRelease(assertions_info);
2665}
2666
2667static void print_descriptive_kernel_assertions(uint32_t val32)
2668{
2669    bool first = false;
2670    if (0!= val32)
2671        printf("=");
2672    if (val32&kIOPMDriverAssertionCPUBit) {
2673        printf("CPU");
2674        first = true;
2675    }
2676    if (val32&kIOPMDriverAssertionUSBExternalDeviceBit) {
2677        if (first) printf(",");
2678        first=true;
2679        printf("USB");
2680    }
2681    if (val32&kIOPMDriverAssertionBluetoothHIDDevicePairedBit) {
2682        if (first) printf(",");
2683        first=true;
2684        printf("BT-HID");
2685    }
2686    if (val32&kIOPMDriverAssertionExternalMediaMountedBit) {
2687        if (first) printf(",");
2688        first=true;
2689        printf("MEDIA");
2690    }
2691    if (val32&kIOPMDriverAssertionReservedBit5) {
2692        if (first) printf(",");
2693        first=true;
2694        printf("THNDR");
2695    }
2696    if (val32&kIOPMDriverAssertionPreventDisplaySleepBit) {
2697        if (first) printf(",");
2698        first=true;
2699        printf("DSPLY");
2700    }
2701    if (val32&kIOPMDriverAssertionReservedBit7) {
2702        if (first) printf(",");
2703        first=true;
2704        printf("STORAGE");
2705    }
2706    if (val32&kIOPMDriverAssertionMagicPacketWakeEnabledBit) {
2707        if (first) printf(",");
2708        first=true;
2709        printf("MAGICWAKE");
2710    }
2711    return;
2712}
2713
2714static void show_assertions_in_kernel(void)
2715{
2716    CFMutableDictionaryRef  rootDomainProperties = NULL;
2717
2718    CFArrayRef      kernelAssertionsArray = NULL;
2719    CFNumberRef     kernelAssertions = NULL;
2720    int             kernelAssertionsSum = 0;
2721    int             count;
2722    int             i;
2723    io_registry_entry_t rootDomain = copyRootDomainRef();
2724
2725    IORegistryEntryCreateCFProperties(rootDomain, &rootDomainProperties, 0, 0);
2726
2727    if (rootDomainProperties)
2728    {
2729        kernelAssertions = CFDictionaryGetValue(rootDomainProperties, CFSTR(kIOPMAssertionsDriverKey));
2730        if (kernelAssertions) {
2731            CFNumberGetValue(kernelAssertions, kCFNumberIntType, &kernelAssertionsSum);
2732        }
2733
2734        kernelAssertionsArray = CFDictionaryGetValue(rootDomainProperties, CFSTR(kIOPMAssertionsDriverDetailedKey));
2735    }
2736
2737    if (0 == kernelAssertionsSum) {
2738        printf("No kernel assertions.\n");
2739//        printf("\nNo kernel assertions.\n");
2740        return;
2741    }
2742
2743    printf("Kernel Assertions: 0x%x", kernelAssertionsSum);
2744//    printf("\nKernel Assertions: 0x%x", kernelAssertionsSum);
2745    print_descriptive_kernel_assertions(kernelAssertionsSum);
2746    printf("\n");
2747
2748    if (!kernelAssertionsArray
2749        || !(count = CFArrayGetCount(kernelAssertionsArray)))
2750    {
2751        printf("   None");
2752    } else {
2753        CFDictionaryRef whichAssertion = NULL;
2754        CFStringRef     ownerString = NULL;
2755        char            ownerBuf[100];
2756        io_name_t       serviceNameBuf;
2757        CFNumberRef     registryEntryID = NULL;
2758        CFNumberRef     n_id = NULL;
2759        CFNumberRef     n_modified = NULL;
2760        CFNumberRef     n_owner = NULL;
2761        CFNumberRef     n_level = NULL;
2762        CFNumberRef     n_asserted = NULL;
2763        uint64_t        val64=0;
2764        uint32_t        val32=0;
2765
2766        for (i=0; i<count; i++)
2767        {
2768            whichAssertion = isA_CFDictionary(CFArrayGetValueAtIndex(kernelAssertionsArray, i));
2769            if (!whichAssertion)
2770                continue;
2771#ifndef kIOPMDriverRegistryEntryIDKey
2772#define kIOPMDriverRegistryEntryIDKey "RegistryEntryID"
2773#endif
2774            ownerString         = CFDictionaryGetValue(whichAssertion, CFSTR(kIOPMDriverAssertionOwnerStringKey));
2775            registryEntryID     = CFDictionaryGetValue(whichAssertion, CFSTR(kIOPMDriverRegistryEntryIDKey));
2776            n_id                = CFDictionaryGetValue(whichAssertion, CFSTR(kIOPMDriverAssertionIDKey));
2777            n_modified          = CFDictionaryGetValue(whichAssertion, CFSTR(kIOPMDriverAssertionModifiedTimeKey));
2778            n_owner             = CFDictionaryGetValue(whichAssertion, CFSTR(kIOPMDriverAssertionOwnerServiceKey));
2779            n_level             = CFDictionaryGetValue(whichAssertion, CFSTR(kIOPMDriverAssertionLevelKey));
2780            n_asserted          = CFDictionaryGetValue(whichAssertion, CFSTR(kIOPMDriverAssertionAssertedKey));
2781
2782
2783            CFAbsoluteTime      modifiedTime = 1.0;
2784            uint32_t            level = 0;
2785
2786            if (n_modified && CFNumberGetValue(n_modified, kCFNumberSInt64Type, &val64)) {
2787                modifiedTime = _CFAbsoluteTimeFromPMEventTimeStamp(val64);
2788            }
2789            if (n_level) {
2790                CFNumberGetValue(n_level, kCFNumberSInt32Type, &level);
2791            }
2792
2793            if (level != kIOPMAssertionLevelOff)
2794            {
2795                if (n_id && CFNumberGetValue(n_id, kCFNumberSInt64Type, &val64)) {
2796                    printf("   id=%ld ", (long)val64);
2797                }
2798                if (n_owner && CFNumberGetValue(n_owner, kCFNumberSInt64Type, &val64)) {
2799                    printf("by [0x%016lx]", (unsigned long)val64);
2800                }
2801
2802                if (n_asserted) {
2803                    if (CFNumberGetValue(n_asserted, kCFNumberSInt32Type, &val32)) {
2804                        printf(" level=%d 0x%x", level, val32);
2805                        print_descriptive_kernel_assertions(val32);
2806                    }
2807                }
2808                printf(" mod=");
2809                print_short_date(modifiedTime, false);
2810                if (ownerString &&
2811                    CFStringGetCString(ownerString, ownerBuf, sizeof(ownerBuf), kCFStringEncodingUTF8))
2812                {
2813                    printf("description=%s ", ownerBuf);
2814                }
2815
2816                if (registryEntryID && CFNumberGetValue(registryEntryID, kCFNumberSInt64Type, &val64))
2817                {
2818                    io_service_t match = IO_OBJECT_NULL;
2819                    match = IOServiceGetMatchingService(kIOMasterPortDefault, IORegistryEntryIDMatching(val64));
2820                    if (match) {
2821                        IORegistryEntryGetName(match, serviceNameBuf);
2822                        printf("owner=%s", serviceNameBuf);
2823                        IOObjectRelease(match);
2824                    }
2825                }
2826                printf("\n");
2827            }
2828        }
2829    }
2830    CFRelease(rootDomainProperties);
2831}
2832static void show_assertions(const char *decorate)
2833{
2834    print_pretty_date(CFAbsoluteTimeGetCurrent(), decorate?false:true);
2835    if (decorate) {
2836        printf("%s\n", decorate);
2837    }
2838
2839    show_assertions_system_aggregates();
2840    show_assertions_individually();
2841    show_assertions_in_kernel();
2842
2843    return;
2844}
2845
2846static void log_assertions(void)
2847{
2848    int                 token;
2849    int                 notify_status;
2850
2851    IOPMAssertionNotify(kIOPMAssertionsAnyChangedNotifyString, kIOPMNotifyRegister);
2852    notify_status = notify_register_dispatch(
2853            kIOPMAssertionsAnyChangedNotifyString,
2854            &token,
2855            dispatch_get_main_queue(),
2856            ^(int t) {
2857               show_assertions(NULL);
2858             });
2859
2860    if (NOTIFY_STATUS_OK != notify_status) {
2861        printf("Could not get notification for %s. Exiting.\n",
2862                kIOPMAssertionsAnyChangedNotifyString);
2863        return;
2864    }
2865
2866    printf("Logging all assertion changes.\n");
2867    show_assertions(NULL);
2868
2869    dispatch_main();
2870}
2871
2872/******************************************************************************/
2873
2874static const char *stringForGTLevel(int gtl)
2875{
2876    if (kIOSystemLoadAdvisoryLevelGreat == gtl) {
2877        return "Great";
2878    } else if (kIOSystemLoadAdvisoryLevelOK == gtl) {
2879        return "OK";
2880    } else if (kIOSystemLoadAdvisoryLevelBad == gtl) {
2881        return "Bad";
2882    }
2883    return "(Unknown system load level)";
2884}
2885
2886static void show_systemload(void)
2887{
2888    CFDictionaryRef     detailed = NULL;
2889    CFNumberRef         n = NULL;
2890    int                 userLevel       = kIOSystemLoadAdvisoryLevelOK;
2891    int                 batteryLevel    = kIOSystemLoadAdvisoryLevelOK;
2892    int                 thermalLevel    = kIOSystemLoadAdvisoryLevelOK;
2893    int                 combinedLevel   = kIOSystemLoadAdvisoryLevelOK;
2894
2895    print_pretty_date(CFAbsoluteTimeGetCurrent(), true);
2896
2897    combinedLevel = IOGetSystemLoadAdvisory();
2898    if (0 == combinedLevel) {
2899        printf("- Internal error: IOGetSystemLoadAdvisory returns error value %d\n", combinedLevel);
2900        return;
2901    }
2902
2903    detailed = IOCopySystemLoadAdvisoryDetailed();
2904    if (!detailed) {
2905        printf("- Internal error: Invalid dictionary %p returned from IOCopySystemLoadAdvisoryDetailed.\n", detailed);
2906        return;
2907    }
2908
2909    n = CFDictionaryGetValue(detailed, kIOSystemLoadAdvisoryUserLevelKey);
2910    if (n) {
2911        CFNumberGetValue(n, kCFNumberIntType, &userLevel);
2912    }
2913    n = CFDictionaryGetValue(detailed, kIOSystemLoadAdvisoryBatteryLevelKey);
2914    if (n) {
2915        CFNumberGetValue(n, kCFNumberIntType, &batteryLevel);
2916    }
2917    n = CFDictionaryGetValue(detailed, kIOSystemLoadAdvisoryThermalLevelKey);
2918    if (n) {
2919        CFNumberGetValue(n, kCFNumberIntType, &thermalLevel);
2920    }
2921    CFRelease(detailed);
2922
2923    printf("  combined level = %s\n",  stringForGTLevel(combinedLevel));
2924    printf("  - user level = %s\n",    stringForGTLevel(userLevel));
2925    printf("  - battery level = %s\n", stringForGTLevel(batteryLevel));
2926    printf("  - thermal level = %s\n", stringForGTLevel(thermalLevel));
2927    fflush(stdout);
2928
2929    return;
2930}
2931
2932static void log_systemload(void)
2933{
2934    int                 token = 0;
2935    uint32_t            notify_status = 0;
2936
2937    show_systemload();
2938
2939    notify_status = notify_register_dispatch(
2940            kIOSystemLoadAdvisoryNotifyName,
2941            &token,
2942            dispatch_get_main_queue(),
2943            ^(int t) {
2944               show_systemload();
2945             });
2946
2947    if (NOTIFY_STATUS_OK != notify_status)
2948    {
2949        printf("LogSystemLoad: notify_register_dispatch returns error %d; Exiting.\n", notify_status);
2950        return;
2951    }
2952
2953    dispatch_main();
2954}
2955
2956static void log_useractivity()
2957{
2958    int                 notifyToken = 0;
2959    int                 status;
2960    uint64_t            newVal=0xabcd;
2961
2962    status = notify_register_check(kIOUserActivityNotifyName, &notifyToken);
2963    if (NOTIFY_STATUS_OK == status)
2964    {
2965        notify_get_state(notifyToken, &newVal);
2966        notify_cancel(notifyToken);
2967
2968        print_pretty_date(CFAbsoluteTimeGetCurrent(), false);
2969        if (newVal == kIOUserIsIdle)
2970           printf("User is idle on the system\n");
2971        else
2972           printf("User is active on the system\n");
2973    }
2974
2975}
2976
2977static void log_useractivitylog()
2978{
2979    int                 token = 0;
2980    uint32_t            notify_status = 0;
2981    int                 notifyToken = 0;
2982    int                 status;
2983    uint64_t            newVal=0xabcd;
2984
2985    status = notify_register_check(kIOUserActivityNotifyName, &notifyToken);
2986    if (NOTIFY_STATUS_OK == status)
2987    {
2988        notify_get_state(notifyToken, &newVal);
2989        notify_cancel(notifyToken);
2990
2991        print_pretty_date(CFAbsoluteTimeGetCurrent(), false);
2992        if (newVal == kIOUserIsIdle)
2993           printf("User is idle on the system\n");
2994        else
2995           printf("User is active on the system\n");
2996    }
2997
2998    notify_status = notify_register_dispatch(
2999            kIOUserActivityNotifyName,
3000            &token,
3001            dispatch_get_main_queue(),
3002            ^(int t) {
3003               uint64_t newVal;
3004               notify_get_state(t, &newVal);
3005
3006               print_pretty_date(CFAbsoluteTimeGetCurrent(), false);
3007               if (newVal == kIOUserIsIdle)
3008                    printf("User is idle on the system\n");
3009               else
3010                    printf("User is active on the system\n");
3011             });
3012
3013    if (NOTIFY_STATUS_OK != notify_status)
3014    {
3015        printf("LogSystemLoad: notify_register_dispatch returns error %d; Exiting.\n", notify_status);
3016        return;
3017    }
3018
3019
3020
3021    dispatch_main();
3022
3023}
3024
3025/******************************************************************************/
3026
3027static void log_ps_change_handler(void *info)
3028{
3029    int which = (uintptr_t)info;
3030
3031    if (!(which & kShowColumns)) {
3032        print_pretty_date(CFAbsoluteTimeGetCurrent(), false);
3033        printf("IOPSNotificationCreateRunLoopSource\n");
3034    }
3035    show_power_sources(which);
3036}
3037
3038static int install_listen_for_power_sources(uintptr_t which)
3039{
3040    CFRunLoopSourceRef          rls = NULL;
3041
3042    /* Log changes to all attached power sources */
3043    rls = IOPSNotificationCreateRunLoopSource(log_ps_change_handler, (void *)which);
3044    if(!rls) {
3045        printf("Error - IOPSNotificationCreateRunLoopSource failure.\n");
3046        return kParseInternalError;
3047    } else {
3048        CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
3049        CFRelease(rls);
3050
3051        printf("pmset is in logging mode now. Hit ctrl-c to exit.\n");
3052
3053        if (kShowColumns & which)
3054        {
3055            printf("%10s\t%15s\t%10s\t%10s\t%20s\n",
3056                "Elapsed", "TimeRemaining", "Charge", "Charging", "Timestamp");
3057        }
3058
3059        // and show initial power source state:
3060        log_ps_change_handler((void *)which);
3061    }
3062
3063    if (!(which & kShowColumns)) {
3064        int tokenA, tokenB, tokenC;
3065
3066        notify_register_dispatch(kIOPSNotifyLowBattery,
3067                                &tokenA, dispatch_get_main_queue(),
3068                                ^(int t) {
3069                                    print_pretty_date(CFAbsoluteTimeGetCurrent(), false);
3070                                    printf("%s\n", kIOPSNotifyLowBattery);
3071                                });
3072
3073        notify_register_dispatch(kIOPSNotifyTimeRemaining,
3074                                 &tokenB, dispatch_get_main_queue(),
3075                                 ^(int t) {
3076                                     print_pretty_date(CFAbsoluteTimeGetCurrent(), false);
3077                                     printf("%s\n", kIOPSNotifyTimeRemaining);
3078                                 });
3079        notify_register_dispatch(kIOPSNotifyPowerSource,
3080                                 &tokenC, dispatch_get_main_queue(),
3081                                 ^(int t) {
3082                                     print_pretty_date(CFAbsoluteTimeGetCurrent(), false);
3083                                     printf("%s\n", kIOPSNotifyPowerSource);
3084                                 });
3085        notify_register_dispatch(kIOPSNotifyAttach,
3086                                 &tokenC, dispatch_get_main_queue(),
3087                                 ^(int t) {
3088                                     print_pretty_date(CFAbsoluteTimeGetCurrent(), false);
3089                                     printf("%s\n", kIOPSNotifyAttach);
3090                                 });
3091        notify_register_dispatch(kIOPSNotifyAnyPowerSource,
3092                                 &tokenC, dispatch_get_main_queue(),
3093                                 ^(int t) {
3094                                     print_pretty_date(CFAbsoluteTimeGetCurrent(), false);
3095                                     printf("%s\n", kIOPSNotifyAnyPowerSource);
3096                                 });
3097    }
3098
3099    return 0;
3100}
3101
3102
3103
3104
3105/******************************************************************************/
3106/*                                                                            */
3107/*     RAW PS LOGGING                                                         */
3108/*                                                                            */
3109/******************************************************************************/
3110
3111static CFAbsoluteTime getAbsoluteTimeForProperty(CFDictionaryRef d, CFStringRef key)
3112{
3113    CFNumberRef     secSince1970 = NULL;
3114    uint32_t        secs = 0;
3115    CFAbsoluteTime  return_val = 0.0;
3116
3117    if (d && key)
3118    {
3119        secSince1970 = CFDictionaryGetValue(d, key);
3120        if (secSince1970) {
3121            CFNumberGetValue(secSince1970, kCFNumberIntType, &secs);
3122            return_val = (CFAbsoluteTime)secs - kCFAbsoluteTimeIntervalSince1970;
3123            CFRelease(secSince1970);
3124        }
3125    }
3126
3127    return return_val;
3128}
3129
3130static void print_raw_battery_state(io_registry_entry_t b_reg)
3131{
3132    CFDateFormatterRef      date_format;
3133    CFTimeZoneRef           tz;
3134    CFStringRef             time_date;
3135    CFLocaleRef             loc;
3136    char                    _date[60];
3137
3138    CFStringRef             failure;
3139    char                    _failure[200];
3140    CFBooleanRef            boo;
3141    CFNumberRef             n;
3142    int                     tmp;
3143    int                     cur_cap = -1;
3144    int                     max_cap = -1;
3145    int                     design_cap = -1;
3146    int                     cur_cycles = -1;
3147    CFMutableDictionaryRef  prop = NULL;
3148    IOReturn                ret;
3149
3150    loc = CFLocaleCopyCurrent();
3151    date_format = CFDateFormatterCreate(kCFAllocatorDefault, loc,
3152                                        kCFDateFormatterShortStyle, kCFDateFormatterLongStyle);
3153    CFRelease(loc);
3154    tz = CFTimeZoneCopySystem();
3155    CFDateFormatterSetProperty(date_format, kCFDateFormatterTimeZone, tz);
3156    CFRelease(tz);
3157    CFDateFormatterSetFormat(date_format, CFSTR(kDateAndTimeFormat));
3158    time_date = CFDateFormatterCreateStringWithAbsoluteTime(kCFAllocatorDefault,
3159                                                            date_format, CFAbsoluteTimeGetCurrent());
3160
3161    if(time_date)
3162    {
3163        CFStringGetCString(time_date, _date, 60, kCFStringEncodingMacRoman);
3164        printf("%s\n", _date); fflush(stdout);
3165        CFRelease(time_date);
3166    }
3167
3168    if (IO_OBJECT_NULL == b_reg) {
3169        b_reg = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("AppleSmartBattery"));
3170    }
3171
3172    ret = IORegistryEntryCreateCFProperties(b_reg, &prop, 0, 0);
3173    if( (kIOReturnSuccess != ret) || (NULL == prop) )
3174    {
3175        printf("Couldn't read battery status; error = 0%08x\n", ret);
3176        return;
3177    }
3178
3179    boo = CFDictionaryGetValue(prop, CFSTR(kIOPMPSExternalConnectedKey));
3180    printf(" %s; ", (kCFBooleanTrue == boo) ? "AC" : "No AC");
3181
3182    boo = CFDictionaryGetValue(prop, CFSTR(kIOPMPSBatteryInstalledKey));
3183    printf("%s", (kCFBooleanTrue == boo) ? "" : "No battery; ");
3184
3185    boo = CFDictionaryGetValue(prop, CFSTR(kIOPMPSIsChargingKey));
3186    printf("%s; ", (kCFBooleanTrue == boo) ? "Charging" : "Not Charging");
3187
3188    n = CFDictionaryGetValue(prop, CFSTR(kIOPMPSCurrentCapacityKey));
3189    if(n) {
3190        CFNumberGetValue(n, kCFNumberIntType, &cur_cap);
3191    }
3192    n = CFDictionaryGetValue(prop, CFSTR(kIOPMPSMaxCapacityKey));
3193    if(n) {
3194        CFNumberGetValue(n, kCFNumberIntType, &max_cap);
3195    }
3196    n = CFDictionaryGetValue(prop, CFSTR(kIOPMPSDesignCapacityKey));
3197    if(n) {
3198        CFNumberGetValue(n, kCFNumberIntType, &design_cap);
3199    }
3200
3201    if( (-1 != cur_cap) && (-1 != max_cap) )
3202    {
3203        if (0 == max_cap) {
3204            printf("NaN%%; Cap=%d: FCC=%d; Design=%d; ", cur_cap, max_cap, design_cap);
3205        } else {
3206            printf("%d%%; Cap=%d: FCC=%d; Design=%d; ", (cur_cap*100)/max_cap, cur_cap, max_cap, design_cap);
3207        }
3208    }
3209
3210    n = CFDictionaryGetValue(prop, CFSTR(kIOPMPSTimeRemainingKey));
3211    if(n) {
3212        CFNumberGetValue(n, kCFNumberIntType, &tmp);
3213        printf("Time=%d:%02d; ", tmp/60, tmp%60);
3214    }
3215    n = CFDictionaryGetValue(prop, CFSTR(kIOPMPSAmperageKey));
3216    if(n) {
3217        CFNumberGetValue(n, kCFNumberIntType, &tmp);
3218        printf("%dmA; ", tmp);
3219    }
3220    n = CFDictionaryGetValue(prop, CFSTR(kIOPMPSCycleCountKey));
3221    if(n) {
3222        CFNumberGetValue(n, kCFNumberIntType, &cur_cycles);
3223    }
3224
3225    printf("Cycles=%d", cur_cycles);
3226    n = CFDictionaryGetValue(prop, CFSTR(kIOPMPSLocationKey));
3227    if(n) {
3228        CFNumberGetValue(n, kCFNumberIntType, &tmp);
3229        printf("; Location=%d; ", tmp);
3230    }
3231
3232    failure = CFDictionaryGetValue(prop, CFSTR("ErrorCondition"));
3233    if(failure) {
3234        CFStringGetCString(failure, _failure, 200, kCFStringEncodingMacRoman);
3235        printf("\n Failure=\"%s\"", _failure);
3236    }
3237
3238#ifndef kIOBatteryBootPathKey
3239#define kIOBatteryBootPathKey             "BootPathUpdated"
3240#define kIOBatteryFullPathKey             "FullPathUpdated"
3241#define kIOBatterykUserVisPathKey          "UserVisiblePathUpdated"
3242#endif
3243
3244    printf("\n");
3245    CFAbsoluteTime  since = 0.0;
3246    CFStringRef     since_string = NULL;
3247    char            since_str[65];
3248    since = getAbsoluteTimeForProperty(prop, CFSTR(kIOBatteryBootPathKey));
3249    if (0.0 != since) {
3250        since_string = CFDateFormatterCreateStringWithAbsoluteTime(0, date_format, since);
3251        CFStringGetCString(since_string, since_str, sizeof(since_str), kCFStringEncodingUTF8);
3252        printf(" Polled boot=%s", since_str);
3253        CFRelease(since_string);
3254    }
3255    since = getAbsoluteTimeForProperty(prop, CFSTR(kIOBatteryFullPathKey));
3256    if (0.0 != since) {
3257        since_string = CFDateFormatterCreateStringWithAbsoluteTime(0, date_format, since);
3258        CFStringGetCString(since_string, since_str, sizeof(since_str), kCFStringEncodingUTF8);
3259        printf("; Full=%s", since_str);
3260        CFRelease(since_string);
3261    }
3262    since = getAbsoluteTimeForProperty(prop, CFSTR(kIOBatterykUserVisPathKey));
3263    if (0.0 != since) {
3264        since_string = CFDateFormatterCreateStringWithAbsoluteTime(0, date_format, since);
3265        CFStringGetCString(since_string, since_str, sizeof(since_str), kCFStringEncodingUTF8);
3266        printf("; User visible=%s", since_str);
3267        CFRelease(since_string);
3268    }
3269    printf("\n"); fflush(stdout);
3270
3271    CFRelease(date_format);
3272    CFRelease(prop);
3273    return;
3274}
3275
3276
3277static void log_raw_battery_match(
3278    void *refcon,
3279    io_iterator_t b_iter)
3280{
3281    IONotificationPortRef       notify = *((IONotificationPortRef *)refcon);
3282    io_registry_entry_t         battery;
3283    io_object_t                 notification_ref;
3284    int                         found = false;
3285
3286    while ((battery = (io_registry_entry_t)IOIteratorNext(b_iter)))
3287    {
3288        found = true;
3289        printf(" * Battery matched at registry = %d\n", (int32_t)battery);
3290
3291        print_raw_battery_state(battery);
3292
3293        // And install an interest notification on it
3294        IOServiceAddInterestNotification(notify, battery,
3295                            kIOGeneralInterest, log_raw_battery_interest,
3296                            NULL, &notification_ref);
3297
3298        IOObjectRelease(battery);
3299    }
3300
3301    if(!found) {
3302        printf("  (no batteries found; waiting)\n");
3303    }
3304}
3305
3306
3307static void log_raw_battery_interest(
3308    void *refcon,
3309    io_service_t batt,
3310    natural_t messageType,
3311    void *messageArgument)
3312{
3313    if(kIOPMMessageBatteryStatusHasChanged == messageType)
3314    {
3315        print_raw_battery_state((io_registry_entry_t)batt);
3316
3317    }
3318    return;
3319}
3320
3321static int log_raw_power_source_changes(void)
3322{
3323    IONotificationPortRef       notify_port = 0;
3324    io_iterator_t               battery_iter = 0;
3325    CFRunLoopSourceRef          rlser = 0;
3326    IOReturn                    ret;
3327
3328    printf("pmset is in RAW logging mode now. Hit ctrl-c to exit.\n");
3329
3330    notify_port = IONotificationPortCreate(0);
3331    rlser = IONotificationPortGetRunLoopSource(notify_port);
3332    if(!rlser) return 0;
3333    CFRunLoopAddSource(CFRunLoopGetCurrent(), rlser, kCFRunLoopDefaultMode);
3334
3335
3336    ret = IOServiceAddMatchingNotification(
3337                              notify_port,
3338                              kIOFirstMatchNotification,
3339                              IOServiceMatching("IOPMPowerSource"),
3340                              log_raw_battery_match,
3341                              (void *)&notify_port,
3342                              &battery_iter);
3343    if(KERN_SUCCESS != ret){
3344         printf("!!Error prevented matching notifications; err = 0x%08x\n", ret);
3345    }
3346
3347    // Install notifications on existing instances.
3348    log_raw_battery_match((void *)&notify_port, battery_iter);
3349
3350    CFRunLoopRun();
3351
3352    // should never return from CFRunLoopRun
3353    return 0;
3354}
3355
3356
3357static void show_systempower_notify(void)
3358{
3359    IOPMCapabilityBits b;
3360    char stateDescriptionStr[100];
3361
3362    b = IOPMConnectionGetSystemCapabilities();
3363
3364    IOPMGetCapabilitiesDescription(stateDescriptionStr, sizeof(stateDescriptionStr), b);
3365
3366    print_pretty_date(CFAbsoluteTimeGetCurrent(), false);
3367    printf("com.apple.powermanagement.systempowerstate=%s\n", stateDescriptionStr);
3368
3369    return;
3370}
3371
3372static void install_listen_for_notify_system_power(void)
3373{
3374    uint32_t        status;
3375    int             token;
3376
3377    printf("Logging: com.apple.powermanagement.systempowerstate\n");
3378
3379    status = notify_register_dispatch(
3380            kIOSystemLoadAdvisoryNotifyName,
3381            &token,
3382            dispatch_get_main_queue(),
3383            ^(int t) {
3384               show_systempower_notify();
3385             });
3386
3387    if (NOTIFY_STATUS_OK != status) {
3388        fprintf(stderr, "Registration failed for \"%s\" with (%u)\n",
3389                        kIOPMSystemPowerStateNotify, status);
3390    }
3391
3392}
3393
3394/*************************************************************************/
3395
3396void myPMConnectionHandler(
3397    void *param,
3398    IOPMConnection                      connection,
3399    IOPMConnectionMessageToken          token,
3400    IOPMSystemPowerStateCapabilities    capabilities)
3401{
3402#if TARGET_OS_EMBEDDED
3403    return;
3404#else
3405    char                        stateDescriptionStr[100];
3406    IOReturn                    ret;
3407
3408    printf("\n");
3409    print_pretty_date(CFAbsoluteTimeGetCurrent(), true);
3410    IOPMGetCapabilitiesDescription(stateDescriptionStr, sizeof(stateDescriptionStr), (uint64_t)capabilities);
3411
3412    printf("PMConnection: %s caps:0x%x\n", stateDescriptionStr, capabilities);
3413
3414    IOPMSystemPowerStateCapabilities    fromAPI = IOPMConnectionGetSystemCapabilities();
3415    if (capabilities != fromAPI)
3416    {
3417        printf("PMConnection: API IOPMConnectionGetSystemCapabilities() returns 0x%04x, should have returned 0x%04x\n", (uint32_t)fromAPI, (uint32_t)capabilities);
3418    }
3419
3420    if (!(kIOPMCapabilityCPU & capabilities))
3421    {
3422        printSleepAndWakeReasons(kJustPrintSleep);
3423    } else {
3424        printSleepAndWakeReasons(kJustPrintWake);
3425    }
3426
3427    ret = IOPMConnectionAcknowledgeEvent(connection, token);
3428    if (kIOReturnSuccess != ret)
3429    {
3430        printf("\t-> PM Connection acknowledgement error 0x%08x\n", ret);
3431    }
3432#endif /* TARGET_OS_EMBEDDED */
3433}
3434
3435static void install_listen_PM_connection(void)
3436{
3437#if TARGET_OS_EMBEDDED
3438    return;
3439#else
3440    IOPMConnection      myConnection;
3441    IOReturn            ret;
3442
3443    printf("Logging IOPMConnection\n");
3444
3445    ret = IOPMConnectionCreate(
3446                        CFSTR("SleepWakeLogTool"),
3447                        kIOPMEarlyWakeNotification
3448                            | kIOPMCapabilityCPU
3449                            | kIOPMCapabilityDisk
3450                            | kIOPMCapabilityNetwork
3451                            | kIOPMCapabilityAudio
3452                            | kIOPMCapabilityVideo
3453                            | kIOPMCapabilityPushServiceTask
3454                            | kIOPMCapabilityBackgroundTask
3455                            | kIOPMCapabilitySilentRunning,
3456                        &myConnection);
3457
3458    if (kIOReturnSuccess != ret) {
3459        printf("IOPMConnectionCreate Create: Error 0x%08x\n", ret);
3460        return;
3461    }
3462
3463    ret = IOPMConnectionSetNotification(
3464                        myConnection, NULL,
3465                        (IOPMEventHandlerType)myPMConnectionHandler);
3466
3467    if (kIOReturnSuccess != ret) {
3468        printf("IOPMConnectionCreate SetNotification: Error 0x%08x\n", ret);
3469        return;
3470    }
3471
3472    ret = IOPMConnectionScheduleWithRunLoop(
3473                        myConnection, CFRunLoopGetCurrent(),
3474                        kCFRunLoopDefaultMode);
3475
3476    if (kIOReturnSuccess != ret) {
3477        printf("IOPMConnection ScheduleWithRunloop: Error 0x%08x\n", ret);
3478        return;
3479    }
3480#endif /* TARGET_OS_EMBEDDED */
3481}
3482
3483static void install_listen_com_apple_powermanagement_sleepservices_notify(void)
3484{
3485    int     token;
3486    int     status;
3487
3488    status = notify_register_dispatch(kIOPMSleepServiceActiveNotifyName, &token, dispatch_get_main_queue(),
3489                                      ^(int t) {
3490                                          if (IOPMGetSleepServicesActive()) {
3491                                              printf("SleepServices are: ON\n");
3492                                          } else {
3493                                              printf("SleepServices are: OFF\n");
3494                                          }
3495                                      });
3496
3497
3498    if (NOTIFY_STATUS_OK != status) {
3499        fprintf(stderr, "Registration failed for \"%s\" with (%u)\n",
3500                kIOPMSleepServiceActiveNotifyName, status);
3501    }
3502
3503    if (IOPMGetSleepServicesActive()) {
3504        printf("SleepServices are: ON\n");
3505    } else {
3506        printf("SleepServices are: OFF\n");
3507    }
3508}
3509
3510static void install_listen_IORegisterForSystemPower(void)
3511{
3512    io_object_t                 root_notifier = MACH_PORT_NULL;
3513    IONotificationPortRef       notify = NULL;
3514
3515    printf("Logging IORegisterForSystemPower sleep/wake messages\n");
3516
3517    /* Log sleep/wake messages */
3518    gPMAckPort = IORegisterForSystemPower (
3519                        (void *)kLogSleepEvents, &notify,
3520                        sleepWakeCallback, &root_notifier);
3521
3522   if( notify && (MACH_PORT_NULL != gPMAckPort) )
3523   {
3524        CFRunLoopAddSource(CFRunLoopGetCurrent(),
3525                    IONotificationPortGetRunLoopSource(notify),
3526                    kCFRunLoopDefaultMode);
3527    }
3528
3529    return;
3530}
3531
3532static void listen_for_everything(void)
3533{
3534    install_listen_for_power_sources(kApplyToBattery | kApplyToUPS);
3535    install_listen_for_notify_system_power();
3536    install_listen_PM_connection();
3537    install_listen_IORegisterForSystemPower();
3538    install_listen_com_apple_powermanagement_sleepservices_notify();
3539
3540    CFRunLoopRun();
3541    // should never return from CFRunLoopRun
3542}
3543
3544static void log_thermal_events(void)
3545{
3546    int             powerConstraintNotifyToken = 0;
3547    int             cpuPowerNotifyToken = 0;
3548
3549    uint32_t        status;
3550
3551
3552    status = notify_register_dispatch(
3553            kIOPMCPUPowerNotificationKey,
3554            &cpuPowerNotifyToken,
3555            dispatch_get_main_queue(),
3556            ^(int t) {
3557                show_thermal_cpu_power_level();
3558             });
3559
3560
3561    if (NOTIFY_STATUS_OK != status) {
3562        fprintf(stderr, "Registration failed for \"%s\" with (%u)\n",
3563                        kIOPMCPUPowerNotificationKey, status);
3564    }
3565
3566
3567    status = notify_register_dispatch(
3568            kIOPMThermalWarningNotificationKey,
3569            &powerConstraintNotifyToken,
3570            dispatch_get_main_queue(),
3571            ^(int t) {
3572                show_thermal_warning_level();
3573             });
3574
3575
3576    if (NOTIFY_STATUS_OK != status)
3577    {
3578        fprintf(stderr, "Registration failed for \"%s\" with (%u)\n",
3579                        kIOPMThermalWarningNotificationKey, status);
3580    }
3581
3582    show_thermal_warning_level();
3583    show_thermal_cpu_power_level();
3584
3585    dispatch_main();
3586}
3587
3588
3589static void show_thermal_warning_level(void)
3590{
3591    uint32_t                warn = -1;
3592    IOReturn                ret;
3593
3594    ret = IOPMGetThermalWarningLevel(&warn);
3595
3596    if (kIOReturnNotFound == ret) {
3597        printf("Note: No thermal warning level has been recorded\n");
3598        return;
3599    }
3600
3601    if (kIOReturnSuccess != ret)
3602    {
3603        printf("Error: No thermal warning level with error code 0x%08x\n", ret);
3604        return;
3605    }
3606
3607    // successfully found warning level
3608    print_pretty_date(CFAbsoluteTimeGetCurrent(), false);
3609    printf("Thermal Warning Level = %d\n", warn);
3610    return;
3611}
3612
3613
3614static void show_thermal_cpu_power_level(void)
3615{
3616    CFDictionaryRef         cpuStatus;
3617    CFStringRef             *keys = NULL;
3618    CFNumberRef             *vals = NULL;
3619    int                     count = 0;
3620    int                     i;
3621    IOReturn                ret;
3622
3623    ret = IOPMCopyCPUPowerStatus(&cpuStatus);
3624
3625    if (kIOReturnNotFound == ret) {
3626        printf("Note: No CPU power status has been recorded\n");
3627        return;
3628    }
3629
3630    if (!cpuStatus || (kIOReturnSuccess != ret))
3631    {
3632        printf("Error: No CPU power status with error code 0x%08x\n", ret);
3633        return;
3634    }
3635
3636    print_pretty_date(CFAbsoluteTimeGetCurrent(), false);
3637    fprintf(stderr, "CPU Power notify\n"), fflush(stderr);
3638
3639    count = CFDictionaryGetCount(cpuStatus);
3640    keys = (CFStringRef *)malloc(count*sizeof(CFStringRef));
3641    vals = (CFNumberRef *)malloc(count*sizeof(CFNumberRef));
3642    if (!keys||!vals)
3643        goto exit;
3644
3645    CFDictionaryGetKeysAndValues(cpuStatus,
3646                    (const void **)keys, (const void **)vals);
3647
3648    for(i=0; i<count; i++) {
3649        char strbuf[125];
3650        int  valint;
3651
3652        CFStringGetCString(keys[i], strbuf, 125, kCFStringEncodingUTF8);
3653        CFNumberGetValue(vals[i], kCFNumberIntType, &valint);
3654        printf("\t%s \t= %d\n", strbuf, valint);
3655    }
3656
3657
3658exit:
3659    if (keys)
3660        free(keys);
3661    if (vals)
3662        free(vals);
3663    if (cpuStatus)
3664        CFRelease(cpuStatus);
3665
3666}
3667
3668static void show_power_adapter(void)
3669{
3670    CFDictionaryRef     acInfo = NULL;
3671    CFNumberRef         valNum = NULL;
3672    int                 val;
3673
3674    acInfo = IOPSCopyExternalPowerAdapterDetails();
3675    if (!acInfo) {
3676        printf("No adapter attached.\n");
3677        return;
3678    }
3679
3680    valNum = CFDictionaryGetValue(acInfo, CFSTR(kIOPSPowerAdapterWattsKey));
3681    if (valNum) {
3682        CFNumberGetValue(valNum, kCFNumberIntType, &val);
3683        printf(" Wattage = %dW\n", val);
3684    }
3685
3686    valNum = CFDictionaryGetValue(acInfo, CFSTR(kIOPSPowerAdapterSourceKey));
3687    if (valNum) {
3688        // New format
3689        CFNumberGetValue(valNum, kCFNumberIntType, &val);
3690        printf(" SourceID = 0x%04x\n", val);
3691
3692        valNum = CFDictionaryGetValue(acInfo, CFSTR(kIOPSPowerAdapterCurrentKey));
3693        if (valNum) {
3694            CFNumberGetValue(valNum, kCFNumberIntType, &val);
3695            printf(" Current = %dmA\n", val);
3696        }
3697
3698        if ((valNum = CFDictionaryGetValue(acInfo, CFSTR("Voltage")))) {
3699            CFNumberGetValue(valNum, kCFNumberIntType, &val);
3700            printf(" Voltage = %dmW\n", val);
3701        }
3702    }
3703    else {
3704        valNum = CFDictionaryGetValue(acInfo, CFSTR(kIOPSPowerAdapterRevisionKey));
3705        if (valNum) {
3706            CFNumberGetValue(valNum, kCFNumberIntType, &val);
3707            printf(" Revision = 0x%04x\n", val);
3708        }
3709    }
3710
3711    // Legacy format
3712    valNum = CFDictionaryGetValue(acInfo, CFSTR(kIOPSPowerAdapterIDKey));
3713    if (valNum) {
3714        CFNumberGetValue(valNum, kCFNumberIntType, &val);
3715        printf(" AdapterID = 0x%04x\n", val);
3716    }
3717
3718    valNum = CFDictionaryGetValue(acInfo, CFSTR(kIOPSPowerAdapterFamilyKey));
3719    if (valNum) {
3720        CFNumberGetValue(valNum, kCFNumberIntType, &val);
3721        printf(" Family Code = 0x%04x\n", val);
3722    }
3723
3724    valNum = CFDictionaryGetValue(acInfo, CFSTR(kIOPSPowerAdapterSerialNumberKey));
3725    if (valNum) {
3726        CFNumberGetValue(valNum, kCFNumberIntType, &val);
3727        printf(" Serial Number = 0x%08x\n", val);
3728    }
3729    CFRelease(acInfo);
3730}
3731
3732
3733/******************************************************************************/
3734/*                                                                            */
3735/*     BORING SETTINGS & PARSING                                              */
3736/*                                                                            */
3737/******************************************************************************/
3738
3739
3740static int checkAndSetIntValue(
3741    char *valstr,
3742    CFStringRef settingKey,
3743    int apply,
3744    int isOnOffSetting,
3745    int multiplier,
3746    CFMutableDictionaryRef ac,
3747    CFMutableDictionaryRef batt,
3748    CFMutableDictionaryRef ups)
3749{
3750    CFNumberRef     cfnum;
3751    char            *endptr = NULL;
3752    long            val;
3753    int32_t         val32;
3754
3755    if(!valstr) return -1;
3756
3757    val = strtol(valstr, &endptr, 0);
3758
3759    if(0 != *endptr)
3760    {
3761        // the string contained some non-numerical characters - bail
3762        return -1;
3763    }
3764
3765    // for on/off settings, turn any non-zero number into a 1
3766    if(isOnOffSetting) {
3767        val = (val?1:0);
3768    } else {
3769        // Numerical values may have multipliers (i.e. x1000 for sec -> msec)
3770        if(0 != multiplier) val *= multiplier;
3771    }
3772    // negative number? reject it
3773    if(val < 0) return -1;
3774
3775    val32 = (int32_t)val;
3776    cfnum = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &val32);
3777    if(!cfnum) return -1;
3778    if(apply & kApplyToBattery)
3779        CFDictionarySetValue(batt, settingKey, cfnum);
3780    if(apply & kApplyToCharger)
3781        CFDictionarySetValue(ac, settingKey, cfnum);
3782    if(apply & kApplyToUPS)
3783        CFDictionarySetValue(ups, settingKey, cfnum);
3784    CFRelease(cfnum);
3785    return 0;
3786}
3787
3788static int checkAndSetStrValue(char *valstr, CFStringRef settingKey, int apply,
3789                CFMutableDictionaryRef ac, CFMutableDictionaryRef batt, CFMutableDictionaryRef ups)
3790{
3791    CFStringRef     cfstr;
3792
3793    if(!valstr) return -1;
3794
3795    cfstr = CFStringCreateWithCString(kCFAllocatorDefault,
3796                        valstr, kCFStringEncodingMacRoman);
3797    if(!cfstr) return -1;
3798    if(apply & kApplyToBattery)
3799        CFDictionarySetValue(batt, settingKey, cfstr);
3800    if(apply & kApplyToCharger)
3801        CFDictionarySetValue(ac, settingKey, cfstr);
3802    if(apply & kApplyToUPS)
3803        CFDictionarySetValue(ups, settingKey, cfstr);
3804    CFRelease(cfstr);
3805    return 0;
3806}
3807
3808
3809static int setUPSValue(char *valstr,
3810    CFStringRef    whichUPS,
3811    CFStringRef settingKey,
3812    int apply,
3813    CFMutableDictionaryRef thresholds)
3814{
3815    CFMutableDictionaryRef ups_setting = NULL;
3816    CFDictionaryRef     tmp_ups_setting = NULL;
3817    CFNumberRef     cfnum = NULL;
3818    CFBooleanRef    on_off = kCFBooleanTrue;
3819    char            *endptr = NULL;
3820    long            val;
3821    int32_t         val32;
3822
3823    if(!valstr) return -1;
3824
3825    val = strtol(valstr, &endptr, 10);
3826
3827    if(0 != *endptr)
3828    {
3829        // the string contained some non-numerical characters - bail
3830        return -1;
3831    }
3832
3833    if(-1 == val)
3834    {
3835        on_off = kCFBooleanFalse;
3836    }
3837
3838    // negative number? reject it
3839    if(val < 0) val = 0;
3840
3841    // if this should be a percentage, cap the value at 100%
3842    if(kCFCompareEqualTo == CFStringCompare(settingKey, CFSTR(kIOUPSShutdownAtLevelKey), 0))
3843    {
3844        if(val > 100) val = 100;
3845    };
3846
3847    // bail if -u or -a hasn't been specified:
3848    if(!(apply & kApplyToUPS)) return -1;
3849
3850    // Create the nested dictionaries of UPS settings
3851    tmp_ups_setting = CFDictionaryGetValue(thresholds, settingKey);
3852    ups_setting = CFDictionaryCreateMutableCopy(0, 0, tmp_ups_setting);
3853    if(!ups_setting)
3854    {
3855        ups_setting = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
3856            &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
3857    }
3858
3859    val32 = (int32_t)val;
3860    cfnum = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &val32);
3861
3862    if(kCFBooleanFalse == on_off) {
3863        // If user is turning this setting off, then preserve the existing value in there.
3864        // via CFDictionaryAddValue
3865        CFDictionaryAddValue(ups_setting, CFSTR(kIOUPSShutdownLevelValueKey), cfnum);
3866    } else {
3867        // If user is providing a new value for this setting, overwrite the existing value.
3868        CFDictionarySetValue(ups_setting, CFSTR(kIOUPSShutdownLevelValueKey), cfnum);
3869    }
3870    CFRelease(cfnum);
3871    CFDictionarySetValue(ups_setting, CFSTR(kIOUPSShutdownLevelEnabledKey), on_off);
3872
3873    CFDictionarySetValue(thresholds, settingKey, ups_setting);
3874    CFRelease(ups_setting);
3875    return 0;
3876}
3877
3878
3879//  pmset repeat cancel
3880//  pmset repeat <type> <days of week> <time> [<type> <days of week> <time>]\n");
3881static int parseRepeatingEvent(
3882    char                        **argv,
3883    int                         *num_args_parsed,
3884    CFMutableDictionaryRef      local_repeating_event,
3885    bool                        *local_cancel_repeating)
3886{
3887    CFDateFormatterRef          formatter = 0;
3888    CFTimeZoneRef               tz = 0;
3889    CFStringRef                 cf_str_date = 0;
3890    int                         i = 0;
3891    int                         j = 0;
3892    int                         str_len = 0;
3893    int                         days_mask = 0;
3894    int                         on_off = 0;
3895    IOReturn                    ret = kParseInternalError;
3896
3897    CFStringRef                 the_type = 0;
3898    CFNumberRef                 the_days = 0;
3899    CFDateRef                   cf_date = 0;
3900    CFGregorianDate             cf_greg_date;
3901    int                         event_time = 0;
3902    CFNumberRef                 the_time = 0;       // in minutes from midnight
3903    CFMutableDictionaryRef      one_repeating_event = 0;
3904
3905    formatter = CFDateFormatterCreate(kCFAllocatorDefault, CFLocaleGetSystem(),
3906        kCFDateFormatterShortStyle, kCFDateFormatterMediumStyle);
3907    if(!formatter) {
3908        ret = kParseInternalError;
3909        goto exit;
3910    }
3911    tz = CFTimeZoneCopySystem();
3912    if(!tz) {
3913        ret = kParseInternalError;
3914        goto exit;
3915    }
3916    CFDateFormatterSetFormat(formatter, CFSTR(kTimeFormat));
3917    if(!argv[i]) {
3918        ret = kParseBadArgs;
3919        goto exit;
3920    }
3921    // cancel ALL repeating events
3922    if(0 == strcmp(argv[i], ARG_CANCEL) ) {
3923
3924        *local_cancel_repeating = true;
3925        i++;
3926        ret = kParseSuccess;
3927        goto exit;
3928    }
3929
3930    while(argv[i])
3931    {
3932        string_tolower(argv[i], argv[i]);
3933
3934        // type
3935        if(0 == strcmp(argv[i], ARG_SLEEP))
3936        {
3937            on_off = 0;
3938            the_type = CFSTR(kIOPMAutoSleep);
3939        } else if(0 == strcmp(argv[i], ARG_SHUTDOWN))
3940        {
3941            on_off = 0;
3942            the_type =  CFSTR(kIOPMAutoShutdown);
3943        } else if(0 == strcmp(argv[i], ARG_RESTART))
3944        {
3945            on_off = 0;
3946            the_type =  CFSTR(kIOPMAutoRestart);
3947        } else if(0 == strcmp(argv[i], ARG_WAKE))
3948        {
3949            on_off = 1;
3950            the_type =  CFSTR(kIOPMAutoWake);
3951        } else if(0 == strcmp(argv[i], ARG_POWERON))
3952        {
3953            on_off = 1;
3954            the_type =  CFSTR(kIOPMAutoPowerOn);
3955        } else if(0 == strcmp(argv[i], ARG_WAKEORPOWERON))
3956        {
3957            on_off = 1;
3958            the_type =  CFSTR(kIOPMAutoWakeOrPowerOn);
3959        } else {
3960            printf("Error: Unspecified scheduled event type\n");
3961            ret = kParseBadArgs;
3962            goto bail;
3963        }
3964
3965        i++;
3966
3967        // days of week
3968        // Expect argv[i] to be a NULL terminated string with a subset of: MTWRFSU
3969        // indicating the days of the week to schedule repeating wakeup
3970        // TODO: accept M-F style ranges
3971        if (!argv[i] || !argv[i+1]) {
3972            ret = kParseBadArgs;
3973            goto bail;
3974        }
3975
3976        string_tolower(argv[i], argv[i]);
3977
3978		days_mask = 0;
3979        str_len = strlen(argv[i]);
3980        for(j=0; j<str_len; j++)
3981        {
3982            if('m' == argv[i][j]) {
3983                days_mask |= kIOPMMonday;
3984            } else if('t' == argv[i][j]) {
3985                days_mask |= kIOPMTuesday;
3986            } else if('w' == argv[i][j]) {
3987                days_mask |= kIOPMWednesday;
3988            } else if('r' == argv[i][j]) {
3989                days_mask |= kIOPMThursday;
3990            } else if('f' == argv[i][j]) {
3991                days_mask |= kIOPMFriday;
3992            } else if('s' == argv[i][j]) {
3993                days_mask |= kIOPMSaturday;
3994            } else if('u' == argv[i][j]) {
3995                days_mask |= kIOPMSunday;
3996            }
3997        }
3998        if(0 == days_mask) {
3999            // something went awry; we expect a non-zero days mask.
4000            ret = kParseBadArgs;
4001            goto bail;
4002        }
4003
4004        i++;
4005        string_tolower(argv[i], argv[i]);
4006
4007        cf_str_date = CFStringCreateWithCString(kCFAllocatorDefault,
4008                        argv[i], kCFStringEncodingMacRoman);
4009        if (!cf_str_date) {
4010            ret = kParseInternalError;
4011            goto bail;
4012        }
4013        cf_date = CFDateFormatterCreateDateFromString(0, formatter, cf_str_date, 0);
4014        CFRelease(cf_str_date);
4015        if (!cf_date) {
4016            ret = kParseBadArgs;
4017            goto bail;
4018        }
4019        cf_greg_date = CFAbsoluteTimeGetGregorianDate(CFDateGetAbsoluteTime(cf_date), tz);
4020        event_time = cf_greg_date.hour*60 + cf_greg_date.minute;
4021        the_time = CFNumberCreate(0, kCFNumberIntType, &event_time);
4022
4023        i++;
4024
4025        the_days = CFNumberCreate(0, kCFNumberIntType, &days_mask);
4026
4027        // check for existence of the_days, the_time, the_type
4028        // if this was a validly formatted dictionary, pack the repeating dict appropriately.
4029        if( isA_CFNumber(the_days) && isA_CFString(the_type) && isA_CFNumber(the_time) )
4030        {
4031            one_repeating_event = CFDictionaryCreateMutable(0, 0,
4032                &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
4033            if(one_repeating_event)
4034            {
4035                CFDictionarySetValue(one_repeating_event, CFSTR(kIOPMPowerEventTypeKey), the_type);
4036                CFDictionarySetValue(one_repeating_event, CFSTR(kIOPMDaysOfWeekKey), the_days);
4037                CFDictionarySetValue(one_repeating_event, CFSTR(kIOPMPowerEventTimeKey), the_time);
4038
4039                CFDictionarySetValue(local_repeating_event,
4040                     (on_off ? CFSTR(kIOPMRepeatingPowerOnKey):CFSTR(kIOPMRepeatingPowerOffKey)),
4041                                    one_repeating_event);
4042                CFRelease(one_repeating_event);
4043            }
4044        }
4045        if (the_days)
4046            CFRelease(the_days);
4047        if (the_time)
4048            CFRelease(the_time);
4049        if (cf_date)
4050            CFRelease(cf_date);
4051
4052    } // while loop
4053
4054    ret = kParseSuccess;
4055    goto exit;
4056
4057bail:
4058    fprintf(stderr, "Error: badly formatted repeating power event\n");
4059    fflush(stderr);
4060
4061exit:
4062    if (the_type)
4063        CFRelease(the_type);
4064    if(num_args_parsed)
4065        *num_args_parsed = i;
4066    if(tz)
4067        CFRelease(tz);
4068    if(formatter)
4069        CFRelease(formatter);
4070    return ret;
4071}
4072
4073
4074// pmset sched wake "4/27/04 1:00:00 PM" "Ethan Bold"
4075// pmset sched cancel sleep "4/27/04 1:00:00 PM" "MyAlarmClock"
4076// pmset sched cancel shutdown "4/27/04 1:00:00 PM"
4077static int parseScheduledEvent(
4078    char                        **argv,
4079    int                         *num_args_parsed,
4080    ScheduledEventReturnType    *local_scheduled_event,
4081    bool                        *cancel_scheduled_event,
4082    bool                        is_relative_event)
4083{
4084    CFDateFormatterRef          formatter = 0;
4085    CFStringRef                 cf_str_date = 0;
4086    int                         i = 0;
4087    IOReturn                    ret = kParseInternalError;
4088
4089    formatter = CFDateFormatterCreate(kCFAllocatorDefault, CFLocaleGetSystem(),
4090        kCFDateFormatterShortStyle, kCFDateFormatterMediumStyle);
4091    if(!formatter)
4092        return kParseInternalError;
4093
4094    *num_args_parsed = 0;
4095
4096    // We manually set the format (as recommended by header comments)
4097    // to ensure it doesn't vary from release to release or from locale
4098    // to locale.
4099    CFDateFormatterSetFormat(formatter, CFSTR(kDateAndTimeFormat));
4100    if(!argv[i]) {
4101        ret = kParseInternalError;
4102        goto exit;
4103    }
4104
4105    string_tolower(argv[i], argv[i]);
4106
4107    // cancel
4108    if(!is_relative_event && (0 == strcmp(argv[i], ARG_CANCEL))) {
4109        char            *endptr = NULL;
4110        long            val;
4111        CFArrayRef      all_events = 0;
4112        CFDictionaryRef the_event = 0;
4113
4114        *cancel_scheduled_event = true;
4115        i++;
4116
4117        // See if the next field is an integer. If so, we cancel the event
4118        // indicated by the indices printed in "pmset -g sched"
4119        // If not, parse out the rest of the entry for a full-description
4120        // of the event to cancel.
4121        if(!argv[i]) {
4122            goto exit;
4123        }
4124
4125        val = strtol(argv[i], &endptr, 10);
4126
4127        if(0 == *endptr)
4128        {
4129            all_events = IOPMCopyScheduledPowerEvents();
4130            if(!all_events) {
4131                ret = kParseInternalError;
4132                goto exit;
4133            }
4134            if(val >= 0 && val < CFArrayGetCount(all_events)) {
4135
4136                // the string was indeed a number
4137                the_event = isA_CFDictionary(CFArrayGetValueAtIndex(all_events, val));
4138                if(!the_event) {
4139                        ret = kParseInternalError;
4140                } else {
4141                    local_scheduled_event->when = CFRetain(
4142                        CFDictionaryGetValue(the_event, CFSTR(kIOPMPowerEventTimeKey)));
4143                    local_scheduled_event->who = CFRetain(
4144                        CFDictionaryGetValue(the_event, CFSTR(kIOPMPowerEventAppNameKey)));
4145                    local_scheduled_event->which = CFRetain(
4146                        CFDictionaryGetValue(the_event, CFSTR(kIOPMPowerEventTypeKey)));
4147                    ret = kParseSuccess;
4148                }
4149
4150                i++;
4151            } else {
4152                ret = kParseBadArgs;
4153            }
4154
4155            CFRelease(all_events);
4156            goto exit;
4157        }
4158    }
4159
4160    string_tolower(argv[i], argv[i]);
4161
4162    // type
4163    if(0 == strcmp(argv[i], ARG_SLEEP))
4164    {
4165        local_scheduled_event->which = (!is_relative_event) ?
4166            CFStringCreateWithCString(0, kIOPMAutoSleep, kCFStringEncodingMacRoman) : 0;
4167        i++;
4168    } else if(0 == strcmp(argv[i], ARG_SHUTDOWN))
4169    {
4170        local_scheduled_event->which = (!is_relative_event) ?
4171            CFStringCreateWithCString(0, kIOPMAutoShutdown, kCFStringEncodingMacRoman) : 0;
4172        i++;
4173    } else if(0 == strcmp(argv[i], ARG_RESTART))
4174    {
4175        local_scheduled_event->which = (!is_relative_event) ?
4176            CFStringCreateWithCString(0, kIOPMAutoRestart, kCFStringEncodingMacRoman) : 0;
4177        i++;
4178    } else if(0 == strcmp(argv[i], ARG_WAKE))
4179    {
4180        local_scheduled_event->which = (!is_relative_event) ?
4181            CFStringCreateWithCString(0, kIOPMAutoWake, kCFStringEncodingMacRoman) :
4182            CFStringCreateWithCString(0, kIOPMAutoWakeRelativeSeconds, kCFStringEncodingMacRoman);
4183        i++;
4184    } else if(0 == strcmp(argv[i], ARG_POWERON))
4185    {
4186        local_scheduled_event->which = (!is_relative_event) ?
4187            CFStringCreateWithCString(0, kIOPMAutoPowerOn, kCFStringEncodingMacRoman) : 0;
4188        i++;
4189    } else if(0 == strcmp(argv[i], ARG_WAKEORPOWERON))
4190    {
4191        local_scheduled_event->which = (!is_relative_event) ?
4192            CFStringCreateWithCString(0, kIOPMAutoWakeOrPowerOn, kCFStringEncodingMacRoman) : 0;
4193        i++;
4194    } else {
4195        printf("Error: Unspecified scheduled event type\n");
4196        ret = kParseBadArgs;
4197        goto exit;
4198    }
4199
4200    if(0 == local_scheduled_event->which) {
4201        printf("Error: Unspecified scheduled event type (2)\n");
4202        ret = kParseBadArgs;
4203        goto exit;
4204    }
4205
4206    // date & time
4207    if(argv[i]) {
4208        if (is_relative_event) {
4209            char    *endptr = NULL;
4210            long    secs;
4211
4212            secs = strtol(argv[i], &endptr, 10);
4213            if ((0 != *endptr) || !secs) {
4214                ret = kParseBadArgs;
4215                goto exit;
4216            }
4217
4218            local_scheduled_event->when = CFDateCreate(0, CFAbsoluteTimeGetCurrent() + secs);
4219            i++;
4220        } else {
4221            string_tolower(argv[i], argv[i]);
4222
4223            cf_str_date = CFStringCreateWithCString(kCFAllocatorDefault,
4224                            argv[i], kCFStringEncodingMacRoman);
4225            if(!cf_str_date) {
4226                local_scheduled_event->when = NULL;
4227                ret = kParseInternalError;
4228                goto exit;
4229            }
4230            local_scheduled_event->when =
4231                CFDateFormatterCreateDateFromString(
4232                    0,
4233                    formatter,
4234                    cf_str_date,
4235                    NULL);
4236            CFRelease(cf_str_date);
4237            i++;
4238        }
4239    } else {
4240        printf("Error: Badly formatted date\n");
4241        ret = kParseBadArgs;
4242        goto exit;
4243    }
4244
4245    if(0 == local_scheduled_event->when) {
4246        printf("Error: Badly formatted date (2)\n");
4247        ret = kParseBadArgs;
4248        goto exit;
4249    }
4250
4251    // Author. Please preserve case - do not lowercase - this argument.
4252    if(argv[i]) {
4253        local_scheduled_event->who = CFStringCreateWithCString(0, argv[i], kCFStringEncodingMacRoman);
4254        i++;
4255    } else {
4256        local_scheduled_event->who = 0;
4257    }
4258
4259    ret = kParseSuccess;
4260
4261exit:
4262    if(num_args_parsed) *num_args_parsed = i;
4263
4264    if(formatter) CFRelease(formatter);
4265
4266    if (kParseSuccess != ret) {
4267        exit(EX_SOFTWARE);
4268    }
4269
4270    return ret;
4271}
4272
4273static void string_tolower(char *lower_me, char *dst)
4274{
4275	int length = strlen(lower_me);
4276	int j = 0;
4277
4278	for (j=0; j<length; j++)
4279	{
4280	    dst[j] = tolower(lower_me[j]);
4281	}
4282}
4283
4284static void string_toupper(char *upper_me, char *dst)
4285{
4286	int length = strlen(upper_me);
4287	int j = 0;
4288
4289	for (j=0; j<length; j++)
4290	{
4291	    dst[j] = toupper(upper_me[j]);
4292	}
4293}
4294
4295/*
4296 * parseArgs - parse argv input stream into executable commands
4297 *      and returns executable commands.
4298 * INPUTS:
4299 *  int argc,
4300 *  char* argv[],
4301 * OUTPUTS:
4302 * If these pointers are specified on exit, that means parseArgs modified these settings
4303 * and they should be written out to persistent store by the caller.
4304 *  settings: Energy Saver settings
4305 *  modified_power_sources: which power sources the modified Energy Saver settings apply to
4306 *                          (only valid if settings is defined)
4307 *  active_profiles: Changes the active profile
4308 *  system_power_settings: system-wide settings, not tied to power source. like "disablesleep"
4309 *  ups_thresholds: UPS shutdown thresholds
4310 *  scheduled_event: Description of a one-time power event
4311 *  cancel_scheduled_event: true = cancel the scheduled event/false = schedule the event
4312 *                          (only valid if scheduled_event is defined)
4313 *  repeating_event: Description of a repeating power event
4314 *  cancel_repeating_event: true = cancel the repeating event/false = schedule the repeating event
4315 *                          (only valid if repeating_event is defined)
4316*/
4317
4318static int parseArgs(int argc,
4319    char* argv[],
4320    CFDictionaryRef             *settings,
4321    int                         *modified_power_sources,
4322    bool                        *force_activate_settings,
4323    CFDictionaryRef             *active_profiles,
4324    CFDictionaryRef             *system_power_settings,
4325    CFDictionaryRef             *ups_thresholds,
4326    ScheduledEventReturnType    **scheduled_event,
4327    bool                        *cancel_scheduled_event,
4328    CFDictionaryRef             *repeating_event,
4329    bool                        *cancel_repeating_event,
4330    uint32_t                    *pmCmd)
4331{
4332    int                         i = 1;
4333    int                         apply = 0;
4334    int                         ret = kParseSuccess;
4335    int                         modified = 0;
4336    IOReturn                    kr;
4337    ScheduledEventReturnType    *local_scheduled_event = 0;
4338    bool                        local_cancel_event = false;
4339    CFMutableDictionaryRef      local_repeating_event = 0;
4340    bool                        local_cancel_repeating = false;
4341    CFDictionaryRef             tmp_profiles = 0;
4342    CFMutableDictionaryRef      local_profiles = 0;
4343    CFDictionaryRef             tmp_ups_settings = 0;
4344    CFMutableDictionaryRef      local_ups_settings = 0;
4345    CFDictionaryRef             tmp_settings = 0;
4346    CFMutableDictionaryRef      local_settings = 0;
4347    CFMutableDictionaryRef      local_system_power_settings = 0;
4348    CFDictionaryRef             tmp_battery = 0;
4349    CFMutableDictionaryRef      battery = 0;
4350    CFDictionaryRef             tmp_ac = 0;
4351    CFMutableDictionaryRef      ac = 0;
4352    CFDictionaryRef             tmp_ups = 0;
4353    CFMutableDictionaryRef      ups = 0;
4354
4355    if(argc == 1) {
4356        return kParseBadArgs;
4357    }
4358
4359
4360/*
4361 * Check for any commands
4362 * Commands may not be combined with any other flags
4363 *
4364 */
4365    if(0 == strcmp(argv[1], ARG_TOUCH))
4366    {
4367        *pmCmd = kPMCommandTouch;
4368        return kIOReturnSuccess;
4369    } else if(0 == strcmp(argv[1], ARG_NOIDLE))
4370    {
4371        *pmCmd = kPMCommandNoIdle;
4372        return kIOReturnSuccess;
4373    } else if(0 == strcmp(argv[1], ARG_SLEEPNOW))
4374    {
4375        *pmCmd = kPMCommandSleepNow;
4376        return kIOReturnSuccess;
4377    } else if(0 == strcmp(argv[1], ARG_DISPLAYSLEEPNOW))
4378    {
4379        *pmCmd = kPMCommandDisplaySleepNow;
4380        return kIOReturnSuccess;
4381    } else if(0 == strcmp(argv[1], ARG_DEBUGTRIG))
4382    {
4383        *pmCmd = kPMCommandDebugTrig;
4384        return kIOReturnSuccess;
4385    } else if ((0 == strcmp(argv[1], ARG_RESETDISPLAYAMBIENTPARAMS))
4386              || (0 == strcmp(argv[1], ARG_RDAP)) )
4387    {
4388        #if PLATFORM_HAS_DISPLAYSERVICES
4389        {
4390            IOReturn ret = DisplayServicesResetAmbientLightAll();
4391
4392            if (kIOReturnSuccess == ret) {
4393                printf("Success.\n");
4394            } else if (kIOReturnNoDevice == ret) {
4395                printf("Error: No supported displays found for pmset argument \"%s\"\n", argv[1]);
4396            } else {
4397                printf("Error: Failure 0%08x setting display ambient parameters.\n", ret);
4398            }
4399        }
4400        #else
4401        {
4402            printf("Error: this command isn't supported on this platform (no DisplayServices).\n");
4403            exit (EX_UNAVAILABLE);
4404        }
4405        #endif
4406
4407        return kIOReturnSuccess;
4408    }
4409
4410
4411/***********
4412 * Setup mutable PM preferences
4413 ***********/
4414    tmp_settings = IOPMCopyActivePMPreferences();
4415    if(!tmp_settings) {
4416        ret = kParseInternalError;
4417        goto exit;
4418    }
4419    local_settings = CFDictionaryCreateMutableCopy(0, 0, tmp_settings);
4420    CFRelease(tmp_settings);
4421    if(!local_settings) {
4422        ret = kParseInternalError;
4423        goto exit;
4424    }
4425
4426    // Either battery or AC settings may not exist if the system doesn't support it.
4427    tmp_battery = isA_CFDictionary(CFDictionaryGetValue(local_settings, CFSTR(kIOPMBatteryPowerKey)));
4428    if(tmp_battery) {
4429        battery = CFDictionaryCreateMutableCopy(0, 0, tmp_battery);
4430        if(battery) {
4431            CFDictionarySetValue(local_settings, CFSTR(kIOPMBatteryPowerKey), battery);
4432            CFRelease(battery);
4433        }
4434    }
4435    tmp_ac = isA_CFDictionary(CFDictionaryGetValue(local_settings, CFSTR(kIOPMACPowerKey)));
4436    if(tmp_ac) {
4437        ac = CFDictionaryCreateMutableCopy(0, 0, tmp_ac);
4438        if(ac) {
4439            CFDictionarySetValue(local_settings, CFSTR(kIOPMACPowerKey), ac);
4440            CFRelease(ac);
4441        }
4442    }
4443    tmp_ups = isA_CFDictionary(CFDictionaryGetValue(local_settings, CFSTR(kIOPMUPSPowerKey)));
4444    if(tmp_ups) {
4445        ups = CFDictionaryCreateMutableCopy(0, 0, tmp_ups);
4446        if(ups) {
4447            CFDictionarySetValue(local_settings, CFSTR(kIOPMUPSPowerKey), ups);
4448            CFRelease(ups);
4449        }
4450    }
4451/***********
4452 * Setup mutable UPS thersholds
4453 ***********/
4454    tmp_ups_settings = IOPMCopyUPSShutdownLevels(CFSTR(kIOPMDefaultUPSThresholds));
4455    if(tmp_ups_settings) {
4456        local_ups_settings = CFDictionaryCreateMutableCopy(0, 0, tmp_ups_settings);
4457        CFRelease(tmp_ups_settings);
4458    }
4459
4460/***********
4461 * Setup mutable Active profiles
4462 ***********/
4463    tmp_profiles = IOPMCopyActivePowerProfiles();
4464    if(tmp_profiles) {
4465        local_profiles = CFDictionaryCreateMutableCopy(0, 0, tmp_profiles);
4466        CFRelease(tmp_profiles);
4467    }
4468
4469/************
4470 * Setup system power settings holder dictionary
4471 ************/
4472    local_system_power_settings = CFDictionaryCreateMutable(0, 0,
4473                                &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
4474
4475    // Unless specified, apply changes to both battery and AC
4476    if(battery) apply |= kApplyToBattery;
4477    if(ac) apply |= kApplyToCharger;
4478    if(ups) apply |= kApplyToUPS;
4479
4480    i=1;
4481    while(i < argc)
4482    {
4483		string_tolower(argv[i], argv[i]);	// in place
4484
4485        if( (argv[i][0] == '-')
4486            && ('1' != argv[i][1]) ) // don't try to process it as a abcg argument if it's a -1
4487                                     // the profiles parsing code below is expecting the -1
4488        {
4489        // Process -a/-b/-c/-g arguments
4490            apply = 0;
4491            switch (argv[i][1])
4492            {
4493                case 'a':
4494                    if(battery) apply |= kApplyToBattery;
4495                    if(ac) apply |= kApplyToCharger;
4496                    if(ups) apply |= kApplyToUPS;
4497                    break;
4498                case 'b':
4499                    if(battery) apply = kApplyToBattery;
4500                    break;
4501                case 'c':
4502                    if(ac) apply = kApplyToCharger;
4503                    break;
4504                case 'u':
4505                    if(ups) apply = kApplyToUPS;
4506                    break;
4507                case 'g':
4508                    // One of the "getters"
4509                    if('\0' != argv[i][2]) {
4510                        ret = kParseBadArgs;
4511                        goto exit;
4512                    }
4513                    i++;
4514
4515                    const char *canonical_arg = getCanonicalArgForSynonym(argv[i]);
4516                    if (!canonical_arg) {
4517                        ret = kParseBadArgs;
4518                        goto exit;
4519                    }
4520
4521                    int getter_iterator;
4522                    bool handled_getter_arg = false;
4523                    for (getter_iterator=0; getter_iterator<the_getters_count; getter_iterator++) {
4524                        if (!strncmp(the_getters[getter_iterator].arg, canonical_arg, kMaxArgStringLength)) {
4525                            the_getters[getter_iterator].action(&argv[i+1]);
4526                            handled_getter_arg = true;
4527                            break;
4528                        }
4529                    }
4530                    if (!handled_getter_arg)
4531                    {
4532#if 0
4533                        // TODO: ARG_SEARCH is the only getter that's not described in the
4534                        // "the_getters" array. If possible, we should fit it in there too.
4535                        if (!strncmp(canonical_arg, ARG_SEARCH, kMaxArgStringLength) && argv[i+1] )
4536                        {
4537                            string_toupper(argv[i+1], argv[i+1]);
4538                            show_details_for_UUID(argv[i+1]);
4539                            goto exit;
4540                        }
4541#endif
4542                    }
4543
4544                    // return immediately - don't handle any more setting arguments
4545                    ret = kParseSuccess;
4546                    goto exit;
4547                    break;
4548                default:
4549                    // bad!
4550                    ret = kParseBadArgs;
4551                    goto exit;
4552                    break;
4553            }
4554
4555            i++;
4556        } else if( (0 == strncmp(argv[i], ARG_SCHEDULE, kMaxArgStringLength))
4557                || (0 == strncmp(argv[i], ARG_SCHED, kMaxArgStringLength)) )
4558        {
4559            // Process rest of input as a cancel/schedule power event
4560            int args_parsed;
4561
4562            local_scheduled_event = scheduled_event_struct_create();
4563            if(!local_scheduled_event) {
4564                ret = kParseInternalError;
4565                goto exit;
4566            }
4567            i += 1;
4568            ret = parseScheduledEvent(
4569                            &(argv[i]),
4570                            &args_parsed,
4571                            local_scheduled_event,
4572                            &local_cancel_event,
4573                            false);
4574            if(kParseSuccess != ret)
4575            {
4576                goto exit;
4577            }
4578
4579            i += args_parsed;
4580            modified |= kModSched;
4581        } else if(0 == strncmp(argv[i], ARG_RELATIVE, kMaxArgStringLength))
4582        {
4583            // Process rest of input as a relative power event
4584            int args_parsed;
4585
4586            local_scheduled_event = scheduled_event_struct_create();
4587            if(!local_scheduled_event) {
4588                ret = kParseInternalError;
4589                goto exit;
4590            }
4591            i += 1;
4592            ret = parseScheduledEvent(
4593                            &(argv[i]),
4594                            &args_parsed,
4595                            local_scheduled_event,
4596                            &local_cancel_event,
4597                            true);
4598            if(kParseSuccess != ret)
4599            {
4600                goto exit;
4601            }
4602
4603            i += args_parsed;
4604            modified |= kModSched;
4605        } else if(0 == strncmp(argv[i], ARG_REPEAT, kMaxArgStringLength))
4606        {
4607            int args_parsed;
4608
4609            local_repeating_event = CFDictionaryCreateMutable(0, 0,
4610                &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
4611            if(!local_repeating_event) {
4612                ret = kParseInternalError;
4613                goto exit;
4614            }
4615            i+=1;
4616            ret = parseRepeatingEvent(
4617                            &(argv[i]),
4618                            &args_parsed,
4619                            local_repeating_event,
4620                            &local_cancel_repeating);
4621
4622            if(kParseSuccess == ret)
4623            {
4624                modified |= kModRepeat;
4625            } else {
4626                ret = kParseBadArgs;
4627            }
4628            goto exit;
4629        } else
4630        {
4631        // Process the settings
4632          if(!strncmp(argv[i], ARG_BOOKMARK, kMaxArgStringLength))
4633          {
4634            set_new_power_bookmark();
4635            goto exit;
4636          } else if(0 == strncmp(argv[i], ARG_DEBUGFLAGS, kMaxArgStringLength))
4637          {
4638             if (argv[i+1])
4639                set_debugFlags(&argv[i+1]);
4640              else
4641                  printf("Error: You need to specify debug flags value\n");
4642              goto exit;
4643          } else if(0 == strncmp(argv[i], ARG_BTINTERVAL, kMaxArgStringLength))
4644          {
4645              if(argv[i+1])
4646                set_btInterval(&argv[i+1]);
4647              else
4648                  printf("Error: You need to specify an interval in seconds\n");
4649              goto exit;
4650          } else if(0 == strncmp(argv[i], ARG_DWLINTERVAL, kMaxArgStringLength))
4651          {
4652              if(argv[i+1])
4653                  set_dwlInterval(&argv[i+1]);
4654              else
4655                  printf("Error: You need to specify an interval in seconds\n");
4656              goto exit;
4657          } else if(0 == strncmp(argv[i], ARG_DISABLEASSERTION, kMaxArgStringLength))
4658          {
4659              if(argc <= 2) {
4660                  printf("Error: Assertion type to disable is missing\n");
4661                  goto exit;
4662              }
4663              kr = IOPMCtlAssertionType(argv[i+1], kIOPMDisableAssertionType);
4664              if (kr == kIOReturnNotPrivileged)
4665                  printf("\'%s\' must be run as root to disable assertions\n", argv[0]);
4666              else if (kr != kIOReturnSuccess)
4667                  printf("Failed to disable assertions with err code 0x%x\n", kr);
4668              goto exit;
4669          } else if(0 == strncmp(argv[i], ARG_ENABLEASSERTION, kMaxArgStringLength))
4670          {
4671              if(argc <= 2) {
4672                  printf("Error: Assertion type to enable is missing\n");
4673                  goto exit;
4674              }
4675              kr = IOPMCtlAssertionType(argv[i+1], kIOPMEnableAssertionType);
4676              if (kr == kIOReturnNotPrivileged)
4677                  printf("\'%s\' must be run as root to enable assertions\n", argv[0]);
4678              else if (kr != kIOReturnSuccess)
4679                  printf("Failed to enable assertions with err code 0x%x\n", kr);
4680              goto exit;
4681
4682          } else if (0 == strncmp(argv[i], ARG_MT2BOOK, kMaxArgStringLength))
4683          {
4684              mt2bookmark();
4685              goto exit;
4686          } else if (0 == strncmp(argv[i], ARG_SETSAAFLAGS, kMaxArgStringLength))
4687          {
4688              if(argv[i+1])
4689                set_saaFlags(&argv[i+1]);
4690              else
4691                  printf("Error: You need to specify an integer flag value\n");
4692              goto exit;
4693          } else if (0 == strncmp(argv[i], ARG_NOPOLL, kMaxArgStringLength))
4694          {
4695              set_nopoll();
4696              goto exit;
4697         } else if(0 == strncmp(argv[i], ARG_BOOT, kMaxArgStringLength))
4698          {
4699              // Tell kernel power management that bootup is complete
4700              kr = setRootDomainProperty(CFSTR("System Boot Complete"), kCFBooleanTrue);
4701              if(kr == kIOReturnSuccess) {
4702                 printf("Setting boot completed.\n");
4703              } else {
4704                  fprintf(stderr, "pmset: Error 0x%x setting boot property\n", kr);
4705                  fflush(stderr);
4706              }
4707
4708                i++;
4709            } else if(0 == strncmp(argv[i], ARG_UNBOOT, kMaxArgStringLength))
4710            {
4711                // Tell kernel power management that bootup is complete
4712                kr = setRootDomainProperty(CFSTR("System Shutdown"), kCFBooleanTrue);
4713                if(kr == kIOReturnSuccess) {
4714                    printf("Setting shutdown true.\n");
4715                } else {
4716                    fprintf(stderr, "pmset: Error 0x%x setting boot property\n", kr);
4717                    fflush(stderr);
4718                }
4719
4720                i++;
4721            } else if (0 == strncmp(argv[i], ARG_POLLBOOT, kMaxArgStringLength)) {
4722                ret = IOPSRequestBatteryUpdate(kIOPSReadSystemBoot);
4723                if (kIOReturnSuccess != ret) {
4724                    fprintf(stderr, "pmset: Must be run as root.\n");
4725                }
4726                goto exit;
4727            } else if (0 == strncmp(argv[i], ARG_POLLALL, kMaxArgStringLength)) {
4728                ret = IOPSRequestBatteryUpdate(kIOPSReadAll);
4729                if (kIOReturnSuccess != ret) {
4730                    fprintf(stderr, "pmset: Must be run as root.\n");
4731                }
4732                goto exit;
4733            } else if (0 == strncmp(argv[i], ARG_POLLUSER, kMaxArgStringLength)) {
4734                ret = IOPSRequestBatteryUpdate(kIOPSReadUserVisible);
4735                if (kIOReturnSuccess != ret) {
4736                    fprintf(stderr, "pmset: Must be run as root.\n");
4737                }
4738                goto exit;
4739            } else if(0 == strncmp(argv[i], ARG_FORCE, kMaxArgStringLength))
4740            {
4741                *force_activate_settings = true;
4742                i++;
4743            } else if( (0 == strncmp(argv[i], ARG_DIM, kMaxArgStringLength)) ||
4744                       (0 == strncmp(argv[i], ARG_DISPLAYSLEEP, kMaxArgStringLength)) )
4745            {
4746                // either 'dim' or 'displaysleep' argument sets minutes until display dims
4747                if(-1 == checkAndSetIntValue( argv[i+1],
4748                                                CFSTR(kIOPMDisplaySleepKey),
4749                                                apply, false, kNoMultiplier,
4750                                                ac, battery, ups))
4751                {
4752                    ret = kParseBadArgs;
4753                    goto exit;
4754                }
4755                modified |= kModSettings;
4756                i+=2;
4757            } else if( (0 == strncmp(argv[i], ARG_SPINDOWN, kMaxArgStringLength)) ||
4758                       (0 == strncmp(argv[i], ARG_DISKSLEEP, kMaxArgStringLength)))
4759            {
4760                // either 'spindown' or 'disksleep' argument sets minutes until disk spindown
4761                if(-1 == checkAndSetIntValue( argv[i+1],
4762                                                CFSTR(kIOPMDiskSleepKey),
4763                                                apply, false, kNoMultiplier,
4764                                                ac, battery, ups))
4765                {
4766                    ret = kParseBadArgs;
4767                    goto exit;
4768                }
4769                modified |= kModSettings;
4770                i+=2;
4771            } else if(0 == strncmp(argv[i], ARG_SLEEP, kMaxArgStringLength))
4772            {
4773                if(-1 == checkAndSetIntValue( argv[i+1],
4774                                                CFSTR(kIOPMSystemSleepKey),
4775                                                apply, false, kNoMultiplier,
4776                                                ac, battery, ups))
4777                {
4778                    ret = kParseBadArgs;
4779                    goto exit;
4780                }
4781                modified |= kModSettings;
4782                i+=2;
4783            } else if(0 == strncmp(argv[i], ARG_WOMP, kMaxArgStringLength))
4784            {
4785                if(-1 == checkAndSetIntValue(argv[i+1], CFSTR(kIOPMWakeOnLANKey),
4786                                                apply, true, kNoMultiplier,
4787                                                ac, battery, ups))
4788                {
4789                    ret = kParseBadArgs;
4790                    goto exit;
4791                }
4792                modified |= kModSettings;
4793                i+=2;
4794            } else if(0 == strncmp(argv[i], ARG_RING, kMaxArgStringLength))
4795            {
4796                if(-1 == checkAndSetIntValue(argv[i+1], CFSTR(kIOPMWakeOnRingKey),
4797                                                apply, true, kNoMultiplier,
4798                                                ac, battery, ups))
4799                {
4800                    ret = kParseBadArgs;
4801                    goto exit;
4802                }
4803                modified |= kModSettings;
4804                i+=2;
4805            } else if(0 == strncmp(argv[i], ARG_AUTORESTART, kMaxArgStringLength))
4806            {
4807                if(-1 == checkAndSetIntValue(argv[i+1], CFSTR(kIOPMRestartOnPowerLossKey),
4808                                                apply, true, kNoMultiplier,
4809                                                ac, battery, ups))
4810                {
4811                    ret = kParseBadArgs;
4812                    goto exit;
4813                }
4814                modified |= kModSettings;
4815                i+=2;
4816            } else if(0 == strncmp(argv[i], ARG_WAKEONACCHANGE, kMaxArgStringLength))
4817            {
4818                if(-1 == checkAndSetIntValue(argv[i+1], CFSTR(kIOPMWakeOnACChangeKey),
4819                                                apply, true, kNoMultiplier,
4820                                                ac, battery, ups))
4821                {
4822                    ret = kParseBadArgs;
4823                    goto exit;
4824                }
4825                modified |= kModSettings;
4826                i+=2;
4827            }  else if(0 == strncmp(argv[i], ARG_LIDWAKE, kMaxArgStringLength))
4828            {
4829                if(-1 == checkAndSetIntValue(argv[i+1], CFSTR(kIOPMWakeOnClamshellKey),
4830                                                apply, true, kNoMultiplier,
4831                                                ac, battery, ups))
4832                {
4833                    ret = kParseBadArgs;
4834                    goto exit;
4835                }
4836                modified |= kModSettings;
4837                i+=2;
4838            } else if(0 == strncmp(argv[i], ARG_REDUCEBRIGHT, kMaxArgStringLength))
4839            {
4840                if(-1 == checkAndSetIntValue(argv[i+1], CFSTR(kIOPMReduceBrightnessKey),
4841                                                apply, true, kNoMultiplier,
4842                                                ac, battery, ups))
4843                {
4844                    ret = kParseBadArgs;
4845                    goto exit;
4846                }
4847                modified |= kModSettings;
4848                i+=2;
4849            } else if(0 == strncmp(argv[i], ARG_SLEEPUSESDIM, kMaxArgStringLength))
4850            {
4851                if(-1 == checkAndSetIntValue(argv[i+1], CFSTR(kIOPMDisplaySleepUsesDimKey),
4852                                                apply, true, kNoMultiplier,
4853                                                ac, battery, ups))
4854                {
4855                    ret = kParseBadArgs;
4856                    goto exit;
4857                }
4858                modified |= kModSettings;
4859                i+=2;
4860            } else if((0 == strncmp(argv[i], ARG_MOTIONSENSOR, kMaxArgStringLength))
4861                   || (0 == strncmp(argv[i], ARG_MOTIONSENSOR2, kMaxArgStringLength)) )
4862            {
4863                if(-1 == checkAndSetIntValue(argv[i+1], CFSTR(kIOPMMobileMotionModuleKey),
4864                                                apply, true, kNoMultiplier,
4865                                                ac, battery, ups))
4866                {
4867                    ret = kParseBadArgs;
4868                    goto exit;
4869                }
4870                modified |= kModSettings;
4871                i+=2;
4872            } else if(0 == strncmp(argv[i], ARG_TTYKEEPAWAKE, kMaxArgStringLength))
4873            {
4874                if(-1 == checkAndSetIntValue(argv[i+1], CFSTR(kIOPMTTYSPreventSleepKey),
4875                                                apply, true, kNoMultiplier,
4876                                                ac, battery, ups))
4877                {
4878                    ret = kParseBadArgs;
4879                    goto exit;
4880                }
4881                modified |= kModSettings;
4882                i+=2;
4883            } else if(0 == strncmp(argv[i], ARG_DISABLESLEEP, kMaxArgStringLength))
4884            {
4885                char            *endptr = NULL;
4886                long            val;
4887
4888                if( argv[i+1] )
4889                {
4890                    val = strtol(argv[i+1], &endptr, 10);
4891
4892                    if(0 != *endptr)
4893                    {
4894                        // the string contained some non-numerical characters - bail
4895                        ret = kParseBadArgs;
4896                        goto exit;
4897                    }
4898
4899                    // Any non-zero value of val (preferably 1) means DISABLE sleep.
4900                    // A zero value means ENABLE sleep.
4901
4902                    CFDictionarySetValue( local_system_power_settings,
4903                                          kIOPMSleepDisabledKey,
4904                                          val ? kCFBooleanTrue : kCFBooleanFalse);
4905
4906                    modified |= kModSystemSettings;
4907                }
4908                i+=2;
4909            } else if(0 ==  strncmp(argv[i], ARG_DISABLEFDEKEYSTORE, kMaxArgStringLength))
4910            {
4911                char            *endptr = NULL;
4912                long            val;
4913
4914                if( argv[i+1] )
4915                {
4916                    val = strtol(argv[i+1], &endptr, 10);
4917
4918                    if(0 != *endptr)
4919                    {
4920                        // the string contained some non-numerical characters - bail
4921                        ret = kParseBadArgs;
4922                        goto exit;
4923                    }
4924
4925                    // Any non-zero value of val (preferably 1) means Allow storing
4926                    // FDE Keys to hardware
4927                    // A zero value means Avoid storing keys to hardware
4928
4929                    CFDictionarySetValue( local_system_power_settings,
4930                                          CFSTR(kIOPMDestroyFVKeyOnStandbyKey),
4931                                          val ? kCFBooleanTrue : kCFBooleanFalse );
4932
4933                    modified |= kModSystemSettings;
4934                }
4935                i+=2;
4936
4937            } else if(0 == strncmp(argv[i], ARG_HALTLEVEL, kMaxArgStringLength))
4938            {
4939                if(-1 == setUPSValue(argv[i+1], CFSTR(kIOPMDefaultUPSThresholds),
4940                                                CFSTR(kIOUPSShutdownAtLevelKey),
4941                                                apply, local_ups_settings))
4942                {
4943                    ret = kParseBadArgs;
4944                    goto exit;
4945                }
4946                modified |= kModUPSThresholds;
4947                i+=2;
4948            } else if(0 == strncmp(argv[i], ARG_HALTAFTER, kMaxArgStringLength))
4949            {
4950                if(-1 == setUPSValue(argv[i+1], CFSTR(kIOPMDefaultUPSThresholds),
4951                                                CFSTR(kIOUPSShutdownAfterMinutesOn),
4952                                                apply, local_ups_settings))
4953                {
4954                    ret = kParseBadArgs;
4955                    goto exit;
4956                }
4957                modified |= kModUPSThresholds;
4958                i+=2;
4959            } else if(0 == strncmp(argv[i], ARG_HALTREMAIN, kMaxArgStringLength))
4960            {
4961                if(-1 == setUPSValue(argv[i+1], CFSTR(kIOPMDefaultUPSThresholds),
4962                                                CFSTR(kIOUPSShutdownAtMinutesLeft),
4963                                                apply, local_ups_settings))
4964                {
4965                    ret = kParseBadArgs;
4966                    goto exit;
4967                }
4968                modified |= kModUPSThresholds;
4969                i+=2;
4970            } else if(0 == strncmp(argv[i], ARG_HIBERNATEMODE, kMaxArgStringLength))
4971            {
4972                if(-1 == checkAndSetIntValue(argv[i+1], CFSTR(kIOHibernateModeKey),
4973                                                        apply, false, kNoMultiplier,
4974                                                        ac, battery, ups))
4975                {
4976                    ret = kParseBadArgs;
4977                    goto exit;
4978                }
4979                modified |= kModSettings;
4980                i+=2;
4981            } else if(0 == strncmp(argv[i], ARG_HIBERNATEFREERATIO, kMaxArgStringLength))
4982            {
4983                if(-1 == checkAndSetIntValue(argv[i+1], CFSTR(kIOHibernateFreeRatioKey),
4984                                                        apply, false, kNoMultiplier,
4985                                                        ac, battery, ups))
4986                {
4987                    ret = kParseBadArgs;
4988                    goto exit;
4989                }
4990                modified |= kModSettings;
4991                i+=2;
4992            } else if(0 == strncmp(argv[i], ARG_HIBERNATEFREETIME, kMaxArgStringLength))
4993            {
4994                if(-1 == checkAndSetIntValue(argv[i+1], CFSTR(kIOHibernateFreeTimeKey),
4995                                                        apply, false, kNoMultiplier,
4996                                                        ac, battery, ups))
4997                {
4998                    ret = kParseBadArgs;
4999                    goto exit;
5000                }
5001                modified |= kModSettings;
5002                i+=2;
5003            } else if(0 == strncmp(argv[i], ARG_HIBERNATEFILE, kMaxArgStringLength))
5004            {
5005                if(-1 == checkAndSetStrValue(argv[i+1], CFSTR(kIOHibernateFileKey),
5006                                                        apply, ac, battery, ups))
5007                {
5008                    ret = kParseBadArgs;
5009                    goto exit;
5010                }
5011                modified |= kModSettings;
5012                i+=2;
5013            } else if(0 == strncmp(argv[i], ARG_GPU, kMaxArgStringLength))
5014            {
5015                if(-1 == checkAndSetIntValue(argv[i+1], CFSTR(kIOPMGPUSwitchKey),
5016                                                        apply, false, kNoMultiplier,
5017                                                        ac, battery, ups))
5018                {
5019                    ret = kParseBadArgs;
5020                    goto exit;
5021                }
5022                modified |= kModSettings;
5023                i+=2;
5024            } else if(0 == strncmp(argv[i], ARG_NETAVAILABLE, kMaxArgStringLength))
5025            {
5026                if(-1 == checkAndSetIntValue(argv[i+1],
5027                                     CFSTR(kIOPMPrioritizeNetworkReachabilityOverSleepKey),
5028                                     apply, false, kNoMultiplier,
5029                                     ac, battery, ups))
5030                {
5031                    ret = kParseBadArgs;
5032                    goto exit;
5033                }
5034                modified |= kModSettings;
5035                i+=2;
5036            } else if(0 == strncmp(argv[i], ARG_DEEPSLEEP, kMaxArgStringLength))
5037            {
5038                if(-1 == checkAndSetIntValue(argv[i+1], CFSTR(kIOPMDeepSleepEnabledKey),
5039                                             apply, false, kNoMultiplier,
5040                                             ac, battery, ups))
5041                {
5042                    ret = kParseBadArgs;
5043                    goto exit;
5044                }
5045                modified |= kModSettings;
5046                i+=2;
5047            } else if(0 == strncmp(argv[i], ARG_DEEPSLEEPDELAY, kMaxArgStringLength))
5048            {
5049                if(-1 == checkAndSetIntValue(argv[i+1], CFSTR(kIOPMDeepSleepDelayKey),
5050                                             apply, false, kNoMultiplier,
5051                                             ac, battery, ups))
5052                {
5053                    ret = kParseBadArgs;
5054                    goto exit;
5055                }
5056                modified |= kModSettings;
5057                i+=2;
5058            } else if(0 == strncmp(argv[i], ARG_DARKWAKES, kMaxArgStringLength))
5059            {
5060                if((-1 == checkAndSetIntValue(argv[i+1],
5061                            CFSTR(kIOPMDarkWakeBackgroundTaskKey), apply,
5062                            false, kNoMultiplier, ac, battery, ups)) ||
5063                    (-1 == checkAndSetIntValue(argv[i+1],
5064                             CFSTR(kIOPMSleepServicesKey), apply, false,
5065                             kNoMultiplier, ac, battery, ups)))
5066                {
5067                    ret = kParseBadArgs;
5068                    goto exit;
5069                }
5070                modified |= kModSettings;
5071                i+=2;
5072            } else if(0 == strncmp(argv[i], ARG_AUTOPOWEROFF, kMaxArgStringLength))
5073            {
5074                if(-1 == checkAndSetIntValue(argv[i+1], CFSTR(kIOPMAutoPowerOffEnabledKey),
5075                                             apply, false, kNoMultiplier,
5076                                             ac, battery, ups))
5077                    return kParseBadArgs;
5078                modified |= kModSettings;
5079                i+=2;
5080            } else if(0 == strncmp(argv[i], ARG_AUTOPOWEROFFDELAY, kMaxArgStringLength))
5081            {
5082                if(-1 == checkAndSetIntValue(argv[i+1], CFSTR(kIOPMAutoPowerOffDelayKey),
5083                                             apply, false, kNoMultiplier,
5084                                             ac, battery, ups))
5085                    return kParseBadArgs;
5086                modified |= kModSettings;
5087                i+=2;
5088            } else {
5089                // Determine if this is a number.
5090                // If so, the user is setting the active power profile
5091                // for the power sources specified in applyTo
5092                // If not, bail with bad input.
5093                char                    *endptr = 0;
5094                long                    val;
5095                CFNumberRef             prof_val = 0;
5096
5097                if(!local_profiles) {
5098                    ret = kParseInternalError;
5099                    goto exit;
5100                }
5101
5102                val = strtol(argv[i], &endptr, 10);
5103
5104                if(0 != *endptr || (val < -1) || (val > 4) )
5105                {
5106                    // the string contained some non-numerical characters
5107                    // or the profile number was out of the expected range
5108                    ret = kParseBadArgs;
5109                    goto exit;
5110                }
5111                prof_val = CFNumberCreate(0, kCFNumberIntType, &val);
5112                if(!prof_val) {
5113                    ret = kParseInternalError;
5114                } else {
5115                    // setting a profile
5116                    if(kApplyToBattery & apply) {
5117                        CFDictionarySetValue(local_profiles, CFSTR(kIOPMBatteryPowerKey), prof_val);
5118                    }
5119                    if(kApplyToCharger & apply) {
5120                        CFDictionarySetValue(local_profiles, CFSTR(kIOPMACPowerKey), prof_val);
5121                    }
5122                    if(kApplyToUPS & apply) {
5123                        CFDictionarySetValue(local_profiles, CFSTR(kIOPMUPSPowerKey), prof_val);
5124                    }
5125                    CFRelease(prof_val);
5126
5127                    modified |= kModProfiles;
5128                }
5129                goto exit;
5130            }
5131        } // if
5132    } // while
5133
5134exit:
5135    if(modified & kModSettings) {
5136        *settings = local_settings;
5137        *modified_power_sources = apply;
5138    } else {
5139        if(local_settings) CFRelease(local_settings);
5140    }
5141
5142    if(modified & kModSystemSettings) {
5143        *system_power_settings = local_system_power_settings;
5144    } else {
5145        if(local_system_power_settings) CFRelease(local_system_power_settings);
5146    }
5147
5148    if(modified & kModProfiles) {
5149        *active_profiles = local_profiles;
5150    } else {
5151        if(local_profiles) CFRelease(local_profiles);
5152    }
5153
5154    if(modified & kModUPSThresholds) {
5155        if(ups_thresholds) *ups_thresholds = local_ups_settings;
5156    } else {
5157        if(local_ups_settings) CFRelease(local_ups_settings);
5158    }
5159
5160    if(modified & kModSched) {
5161        *scheduled_event = local_scheduled_event;
5162        *cancel_scheduled_event = local_cancel_event;
5163    }
5164
5165    if(modified & kModRepeat) {
5166        *repeating_event = local_repeating_event;
5167        *cancel_repeating_event = local_cancel_repeating;
5168    } else {
5169        if(local_repeating_event) CFRelease(local_repeating_event);
5170    }
5171
5172    return ret;
5173}
5174
5175// int arePowerSourceSettingsInconsistent(CFDictionaryRef)
5176// Function - determine if the settings will produce the "intended" idle sleep consequences
5177// Parameter - The CFDictionary contains energy saver settings of
5178//             CFStringRef keys and CFNumber/CFBoolean values
5179// Return - non-zero bitfield, each bit indicating a setting inconsistency
5180//          0 if settings will produce expected result
5181//         -1 in case of other error
5182static int arePowerSourceSettingsInconsistent(CFDictionaryRef set)
5183{
5184    int                 sleep_time, disk_time, dim_time;
5185    CFNumberRef         num;
5186    int                 ret = 0;
5187
5188    num = isA_CFNumber(CFDictionaryGetValue(set, CFSTR(kIOPMSystemSleepKey)));
5189    if(!num || !CFNumberGetValue(num, kCFNumberIntType, &sleep_time)) return -1;
5190
5191    num = isA_CFNumber(CFDictionaryGetValue(set, CFSTR(kIOPMDisplaySleepKey)));
5192    if(!num || !CFNumberGetValue(num, kCFNumberIntType, &dim_time)) return -1;
5193
5194    num = isA_CFNumber(CFDictionaryGetValue(set, CFSTR(kIOPMDiskSleepKey)));
5195    if(!num || !CFNumberGetValue(num, kCFNumberIntType, &disk_time)) return -1;
5196
5197    // For system sleep to occur around the time you set it to, the disk and display
5198    // sleep timers must conform to these rules:
5199    // 1. display sleep <= system sleep
5200    // 2. If system sleep != Never, then disk sleep can not be == Never
5201    //    2a. It is, however, OK for disk sleep > system sleep. A funky hack in
5202    //        the kernel IOPMrootDomain allows this.
5203    // and note: a time of zero means "never power down"
5204
5205    if(sleep_time != 0)
5206    {
5207        if(dim_time > sleep_time || dim_time == 0) ret |= kInconsistentDisplaySetting;
5208
5209        if(disk_time == 0) ret |= kInconsistentDiskSetting;
5210    }
5211
5212    return ret;
5213}
5214
5215// void checkSettingConsistency(CFDictionaryRef)
5216// Checks ES settings profile by profile
5217// Prints a user warning if any idle timer settings violate the kernel's assumptions
5218// about idle, disk, and display sleep timers.
5219// Parameter - a CFDictionary of energy settings "profiles", usually one per power supply
5220static void checkSettingConsistency(CFDictionaryRef profiles)
5221{
5222    int                 num_profiles;
5223    int                 i;
5224    int                 ret;
5225    char                buf[kMaxLongStringLength];
5226    CFStringRef         *keys;
5227    CFDictionaryRef     *values;
5228
5229    num_profiles = CFDictionaryGetCount(profiles);
5230    keys = (CFStringRef *)malloc(num_profiles * sizeof(void *));
5231    values = (CFDictionaryRef *)malloc(num_profiles * sizeof(void *));
5232    if(!keys || !values) return;
5233    CFDictionaryGetKeysAndValues(profiles, (const void **)keys, (const void **)values);
5234
5235// TODO: Warn user if 1) they have just changed the custom settings
5236//       2) their active profile is _NOT_ custom
5237
5238    for(i=0; i<num_profiles; i++)
5239    {
5240        // Check settings profile by profile
5241        if( isA_CFDictionary(values[i])
5242            && (ret = arePowerSourceSettingsInconsistent(values[i])) )
5243        {
5244            // get profile name
5245            if(!CFStringGetCString(keys[i], buf, kMaxLongStringLength, kCFStringEncodingMacRoman)) break;
5246
5247            fprintf(stderr, "Warning: Idle sleep timings for \"%s\" may not behave as expected.\n", buf);
5248            if(ret & kInconsistentDisplaySetting)
5249            {
5250                fprintf(stderr, "- Display sleep should have a lower timeout than system sleep.\n");
5251            }
5252            if(ret & kInconsistentDiskSetting)
5253            {
5254                fprintf(stderr, "- Disk sleep should be non-zero whenever system sleep is non-zero.\n");
5255            }
5256            fflush(stderr);
5257        }
5258    }
5259
5260    free(keys);
5261    free(values);
5262}
5263
5264static ScheduledEventReturnType *scheduled_event_struct_create(void)
5265{
5266    ScheduledEventReturnType *ret = malloc(sizeof(ScheduledEventReturnType));
5267    if(!ret) return NULL;
5268    ret->who = 0;
5269    ret->when = 0;
5270    ret->which = 0;
5271    return ret;
5272}
5273
5274static void scheduled_event_struct_destroy(
5275    ScheduledEventReturnType *free_me)
5276{
5277    if( (0 == free_me) ) return;
5278    if(free_me->who) {
5279        CFRelease(free_me->who);
5280        free_me->who = 0;
5281    }
5282    if(free_me->when) {
5283        CFRelease(free_me->when);
5284        free_me->when = 0;
5285    }
5286    if((free_me)->which) {
5287        CFRelease(free_me->which);
5288        free_me->which = 0;
5289    }
5290    free(free_me);
5291}
5292
5293
5294static IOReturn _pm_connect(mach_port_t *newConnection)
5295{
5296    kern_return_t       kern_result = KERN_SUCCESS;
5297
5298    if(!newConnection) return kIOReturnBadArgument;
5299
5300    // open reference to PM configd
5301    kern_result = bootstrap_look_up2(bootstrap_port,
5302                                    kIOPMServerBootstrapName,
5303                                    newConnection,
5304                                    0,
5305                                    BOOTSTRAP_PRIVILEGED_SERVER);
5306
5307    if(KERN_SUCCESS != kern_result) {
5308        return kIOReturnError;
5309    }
5310    return kIOReturnSuccess;
5311}
5312
5313static IOReturn _pm_disconnect(mach_port_t connection)
5314{
5315    if(!connection) return kIOReturnBadArgument;
5316    mach_port_destroy(mach_task_self(), connection);
5317    return kIOReturnSuccess;
5318}
5319
5320/******************************************************************************/
5321/*                                                                            */
5322/*     ASL & MESSAGETRACER & HISTORY                                          */
5323/*                                                                            */
5324/******************************************************************************/
5325
5326/*
5327 * Cache the message in a temp ring buffer.
5328 *
5329 * ASL doesn't allow re-positioning the current read pointer into
5330 * aslresponse. There is no aslresponse_prev() API. So, we
5331 * store the message retrieved from aslreponse in a ring
5332 * buffer.
5333 */
5334static aslmsg _cacheAndGetMsg(aslresponse pmresponse)
5335{
5336   aslmsg msg = NULL;
5337
5338   if (msgCache == NULL)
5339   {
5340      msgCache = calloc(1, sizeof(MsgCache));
5341      if (!msgCache) return NULL;
5342   }
5343
5344   if (((msgCache->writeIdx+1) % RING_SIZE) == msgCache->readIdx)
5345      return NULL; /* overflow */
5346
5347   msg = aslresponse_next(pmresponse);
5348   if (!msg) return NULL;
5349
5350   msgCache->msgRing[msgCache->writeIdx] = msg;
5351
5352   msgCache->writeIdx = (msgCache->writeIdx+1) % RING_SIZE;
5353   return  msg;
5354}
5355
5356static aslmsg _my_next_response(aslresponse pmresponse)
5357{
5358    aslmsg   next_msg = 0;
5359
5360    /*
5361     * _my_next_response returns messages from our cache
5362     * until there aren't any more messages in it.
5363     * Then it returns messages from the PM ASL store, via pmresponse.
5364     */
5365    if (msgCache && (msgCache->readIdx != msgCache->writeIdx))
5366    {
5367        next_msg = msgCache->msgRing[msgCache->readIdx];
5368        msgCache->readIdx = (msgCache->readIdx+1) % RING_SIZE;
5369    }
5370
5371    /*
5372     * If the cache is empty, then we pull messages straight from the ASL store.
5373     */
5374    if (0 == next_msg) {
5375        next_msg = aslresponse_next(pmresponse);
5376    }
5377
5378    return next_msg;
5379}
5380
5381/*
5382 * Called when current event is 'Sleep', to find out
5383 * the time stamp of next wake event.
5384 *
5385 * Possible transitions:
5386 * Sleep -> Wake
5387 * Sleep -> DarkWake
5388 */
5389
5390static int32_t _getNextWakeTime(aslresponse pmresponse)
5391{
5392   const char *domain = NULL;
5393   const char *timeStr = NULL;
5394   int32_t wakeTime = -1;
5395   aslmsg next;
5396
5397   do {
5398
5399      if ((next = _cacheAndGetMsg(pmresponse)) == NULL) break;
5400
5401      domain = asl_get(next, kPMASLDomainKey);
5402      if (!domain) break;
5403
5404      if ( (!strncmp(kPMASLDomainPMWake, domain, sizeof(kPMASLDomainPMWake) )) ||
5405            (!strncmp(kPMASLDomainPMDarkWake, domain, sizeof(kPMASLDomainPMDarkWake) )) )
5406      {
5407         timeStr = asl_get(next, ASL_KEY_TIME);
5408         if (timeStr)
5409            wakeTime = atol(timeStr);
5410         break;
5411      }
5412      else if (!strncmp(kPMASLDomainPMSleep, domain, sizeof(kPMASLDomainPMSleep) ))
5413      {
5414          /* Came across another sleep trace. Wake trace is missing */
5415          break;
5416      }
5417   } while(1);
5418
5419   return wakeTime;
5420}
5421
5422/*
5423 * Called when current event is 'wake/darkWake', to find out
5424 * the time stamp of next sleep/wake event.
5425 *
5426 * Possible transitions:
5427 * Wake -> Sleep
5428 * DarkWake -> Sleep
5429 * DarkWake -> Wake
5430 */
5431static int32_t _getNextSleepTime(aslresponse pmresponse, const char *curr_domain)
5432{
5433   const char *domain = NULL;
5434   const char *timeStr = NULL;
5435   int32_t sleepTime = -1;
5436   uint32_t sleepCnt = 0;
5437   aslmsg next;
5438
5439   do {
5440
5441
5442      if ((next = _cacheAndGetMsg(pmresponse)) == NULL) break;
5443      domain = asl_get(next, kPMASLDomainKey);
5444      if (!domain) continue;
5445
5446      /* Check for events with unexpected transitions */
5447      if (( !strncmp(kPMASLDomainPMWake, curr_domain, sizeof(kPMASLDomainPMWake) )) &&
5448          ( (!strncmp(kPMASLDomainPMWake, domain, sizeof(kPMASLDomainPMWake) )) ||
5449            (!strncmp(kPMASLDomainPMDarkWake, domain, sizeof(kPMASLDomainPMDarkWake)) )
5450          ))
5451      {
5452          /* Wake -> Wake or Wake -> DarkWake is unexpected */
5453          break;
5454      }
5455
5456      else if ((!strncmp(kPMASLDomainPMDarkWake, curr_domain, sizeof(kPMASLDomainPMDarkWake))) &&
5457               (!strncmp(kPMASLDomainPMDarkWake, domain, sizeof(kPMASLDomainPMDarkWake)) ))
5458      {
5459          /* DarkWake ->  DarkWake is unexpected */
5460          break;
5461      }
5462
5463      if ( (!strncmp(kPMASLDomainPMSleep, domain, sizeof(kPMASLDomainPMSleep) )) ||
5464               (!strncmp(kPMASLDomainPMWake, domain, sizeof(kPMASLDomainPMWake) )) )
5465      {
5466         const char *value1 = asl_get(next, kPMASLValueKey);
5467         if (value1) {
5468            sleepCnt = strtol(value1, NULL, 0);
5469
5470            if (sleepCnt == 1)
5471               break;  /* System rebooted at this point */
5472         }
5473
5474         timeStr = asl_get(next, ASL_KEY_TIME);
5475         if (timeStr)
5476            sleepTime = atol(timeStr);
5477         break;
5478      }
5479   } while(1);
5480
5481   return sleepTime;
5482}
5483
5484#define kPMASLStorePath                 "/var/log/powermanagement"
5485
5486static aslresponse open_pm_asl_store(int *result)
5487{
5488    aslresponse         query = NULL;
5489    aslresponse         response = NULL;
5490    asl_store_t         *pmstore = NULL;
5491    uint64_t            endMessageID;
5492
5493    query = (aslresponse)calloc(1, sizeof(asl_search_result_t));
5494    if (query != NULL)
5495    {
5496        query->msg = (asl_msg_t **)calloc(1, sizeof(asl_msg_t *));
5497        if (query->msg != NULL)
5498        {
5499            asl_msg_t *cq = (asl_msg_t *)asl_new(ASL_TYPE_QUERY);
5500            if (cq != NULL)
5501            {
5502                query->msg[0] = cq;
5503                query->count = 1;
5504                asl_set_query((aslmsg)cq, ASL_KEY_FACILITY, kPMFacility, ASL_QUERY_OP_EQUAL);
5505
5506                *result = asl_store_open_read(kPMASLStorePath, &pmstore);
5507                if (0 == *result) {
5508                    *result = asl_store_match(pmstore, query, &response, &endMessageID, 0, 0, 1);
5509                }
5510                asl_free((aslmsg)cq);
5511            }
5512            free(query->msg);
5513        }
5514        free(query);
5515    }
5516
5517    return response;
5518}
5519
5520/* All PM messages in ASL log */
5521static void show_log(void)
5522{
5523    aslmsg              m = 0;
5524    char                uuid[100];
5525    long                sleep_cnt = 0;
5526    int                 dark_wake_cnt = 0;
5527    bool                first_iter = true;
5528    CFAbsoluteTime      boot_time = 0;
5529
5530    int                 asl_result = -1;
5531    aslresponse         response = NULL;
5532
5533    response = open_pm_asl_store(&asl_result);
5534    if (!response)
5535    {
5536        printf("Error(%d) - no messages found in PM ASL data store at: %s\n", asl_result, kPMASLStorePath);
5537        return;
5538    } else {
5539        printf("PM ASL data store: %s\n", kPMASLStorePath);
5540    }
5541
5542    uuid[0] = 0;
5543
5544    while ((m = _my_next_response(response)))
5545    {
5546        const char    *val = NULL;
5547        int32_t      print_duration_time = 0;
5548        uint32_t      time_read = 0;
5549        char          buf[40];
5550        bool          new_boot_cycle = false;
5551
5552        if ((val = asl_get(m, kPMASLDomainKey)))
5553        {
5554            if (!strncmp(val, kPMASLDomainPMStart, sizeof(kPMASLDomainPMStart)-1)) {
5555                new_boot_cycle = true;
5556            }
5557        }
5558
5559        if (((val = asl_get(m, kPMASLUUIDKey)) && (strncmp( val, uuid, sizeof(uuid)) != 0)) || new_boot_cycle )
5560        {
5561            // New Sleep cycle is about to begin
5562            // Print Sleep cnt and dark wake cnt of previous sleep/wake cycle
5563            if ( !first_iter )
5564            {
5565               printf("Sleep/Wakes since boot");
5566               if (boot_time) {
5567                  printf(" at ");
5568                  print_pretty_date(boot_time, false);
5569
5570               }
5571               printf(":%ld   Dark Wake Count in this sleep cycle:%d\n", sleep_cnt, dark_wake_cnt);
5572            }
5573            first_iter = false;
5574
5575            printf("\n");   // Extra line to seperate from previous sleep/wake cycles
5576            dark_wake_cnt = 0;
5577
5578            // Print the header for each column
5579            printf("%-25s %-20s\t%-75s\t%-10s\t%-10s\n", "Time stamp", "Domain", "Message", "Duration", "Delay");
5580            printf("%-25s %-20s\t%-75s\t%-10s\t%-10s\n", "==========", "======", "=======", "========", "=====");
5581
5582            // Print and save UUID of the new cycle
5583            snprintf(uuid, sizeof(uuid), "%s", val);
5584            printf("UUID: %s\n", val);
5585            sleep_cnt = 0;
5586        }
5587
5588        // Time
5589        if ((val = asl_get(m, ASL_KEY_TIME)))
5590        {
5591            time_read = atol(val);
5592            CFAbsoluteTime  abs_time = (CFAbsoluteTime)(time_read - kCFAbsoluteTimeIntervalSince1970);
5593            print_pretty_date(abs_time, false);
5594            if (new_boot_cycle)
5595               boot_time = abs_time;
5596        }
5597
5598
5599        // Domain
5600        if ((val = asl_get(m, kPMASLDomainKey)))
5601        {
5602            const char *value1 = asl_get(m, kPMASLValueKey);
5603
5604            if (strnstr(val, "Response.", strlen(val))) {
5605               printf("%-20s\t",  ((char *)val + (uintptr_t)strlen("Response.")));
5606            } else {
5607                printf("%-20s\t",  (char *)val);
5608            }
5609
5610            if (!strncmp(kPMASLDomainPMSleep, val, sizeof(kPMASLDomainPMSleep) ))
5611            {
5612               if (value1) {
5613                   sleep_cnt = strtol(value1, NULL, 0);
5614
5615                }
5616                if ( (print_duration_time = _getNextWakeTime(response)) != -1) {
5617                    print_duration_time -= time_read;
5618                } else {
5619                    print_duration_time = 0;
5620                }
5621            }
5622            else if (!strncmp(kPMASLDomainPMDarkWake, val, sizeof(kPMASLDomainPMDarkWake) ))
5623            {
5624               if (value1) {
5625                  dark_wake_cnt = strtol(value1, NULL, 0);
5626               }
5627
5628               if( (print_duration_time = _getNextSleepTime(response, val)) != -1) {
5629                    print_duration_time -= time_read;
5630                } else {
5631                    print_duration_time = 0;
5632                }
5633            }
5634            else if (!strncmp(kPMASLDomainPMWake, val, sizeof(kPMASLDomainPMWake) ))
5635            {
5636               if ( (print_duration_time = _getNextSleepTime(response, val)) != -1) {
5637                    print_duration_time -= time_read;
5638                } else {
5639                    print_duration_time = 0;
5640                }
5641            }
5642/*            else if (!strnstr(val, kPMASLDomainSummaryPrefix, strlen(kPMASLDomainSummaryPrefix)))
5643            {
5644                print_duration_time = value1;
5645            }
5646 */
5647        }
5648        else
5649        {
5650            printf("%-20s\t",  " ");
5651        }
5652
5653        // Message
5654        if ((val = asl_get(m, ASL_KEY_MSG))) {
5655            printf("%-75s\t", val);
5656        } else {
5657            printf("%-75s\t",  " ");
5658        }
5659
5660        // Duration/Delay
5661        if (0 != print_duration_time) {
5662            snprintf(buf, sizeof(buf), "%d secs", print_duration_time);
5663        } else {
5664            buf[0] = 0;
5665        }
5666        printf("%-10s", buf);
5667
5668        if ((val = asl_get(m, kPMASLDelayKey)))
5669        {
5670            printf("%-10s\t", val);
5671        }
5672
5673        printf("\n");
5674    }
5675
5676    if (sleep_cnt || dark_wake_cnt) {
5677        printf("\nTotal Sleep/Wakes since boot");
5678        if (boot_time) {
5679            printf(" at ");
5680            print_pretty_date(boot_time, false);
5681        }
5682        printf(":%ld\n", sleep_cnt);
5683    }
5684    printf("\n");
5685    show_assertions("Showing all currently held IOKit power assertions");
5686}
5687
5688
5689static void show_power_event_history(void)
5690{
5691    IOReturn        ret;
5692    CFArrayRef      powpowHistory = NULL;
5693    CFStringRef     uuid = NULL;
5694    CFDictionaryRef uuid_details;
5695    char            uuid_cstr[255];
5696    int             uuid_index;
5697    int             uuid_count;
5698    //CFAbsoluteTime  set_time = 0.0;
5699    //CFAbsoluteTime  clear_time = 0.0;
5700    //CFNumberRef     timestamp;
5701    CFStringRef     timestamp;
5702    char            st[60];
5703    char            ct[60];
5704
5705    ret = IOPMCopyPowerHistory(&powpowHistory);
5706
5707    if (kIOReturnSuccess != ret || NULL == powpowHistory)
5708    {
5709        printf("Error - no power history found. (IOPMCopyPowerHistory error = 0x%08x)\n", ret);
5710        goto exit;
5711    }
5712
5713    uuid_count = CFArrayGetCount(powpowHistory);
5714    printf("Power History Summary (%d UUIDs)\n", uuid_count);
5715
5716    int i = 0;
5717    for(; i < 9; i++)
5718      printf("----------");
5719    printf("\n");
5720
5721    printf("%-40s|%-24s|%-24s|\n", "UUID", "Set Time", "Clear Time");
5722
5723    i = 0;
5724    for(; i < 9; i++)
5725      printf("----------");
5726    printf("\n");
5727
5728    for (uuid_index = 0; uuid_index < uuid_count; uuid_index++)
5729    {
5730        uuid_details = isA_CFDictionary(CFArrayGetValueAtIndex(powpowHistory, uuid_index));
5731        if (uuid_details) {
5732            uuid = CFDictionaryGetValue(
5733                                uuid_details,
5734                                CFSTR(kIOPMPowerHistoryUUIDKey));
5735            CFStringGetCString(uuid, uuid_cstr, sizeof(uuid_cstr), kCFStringEncodingUTF8);
5736
5737            printf("%-40s|", uuid_cstr);
5738
5739            timestamp = CFDictionaryGetValue(uuid_details,
5740                                       CFSTR(kIOPMPowerHistoryTimestampKey));
5741            CFStringGetCString(timestamp, st, sizeof(st), kCFStringEncodingUTF8);
5742
5743            timestamp = CFDictionaryGetValue(uuid_details,
5744                                       CFSTR(kIOPMPowerHistoryTimestampCompletedKey));
5745            CFStringGetCString(timestamp, ct, sizeof(ct), kCFStringEncodingUTF8);
5746
5747            printf("%-24.24s|%-24.24s|\n", st, ct);
5748        }
5749    }
5750    i = 0;
5751    for(; i < 9; i++)
5752      printf("----------");
5753    printf("\n");
5754exit:
5755    return;
5756}
5757
5758
5759static void printHistoryDetailedEventDictionary(CFDictionaryRef event)
5760{
5761    CFStringRef     evTypeString = NULL;
5762    CFNumberRef     evReasonNum = NULL;
5763    CFNumberRef     evResultNum = NULL;
5764    CFStringRef     evDeviceNameString = NULL;
5765    CFStringRef     evUUIDString = NULL;
5766    CFStringRef     evInterestedDeviceNameString = NULL;
5767    CFNumberRef     evTimestampAbsTime = NULL;
5768    CFNumberRef     evElapsedTimeMicroSec = NULL;
5769    CFNumberRef     evOldState = NULL;
5770    CFNumberRef     evNewState = NULL;
5771
5772    CFAbsoluteTime  ts = 0.0;
5773    int             foo = 0;
5774    int             bar = 0;
5775    char            buf_cstr[40];
5776    char            *display_cstr = NULL;
5777
5778    evTypeString = isA_CFString(CFDictionaryGetValue(event, CFSTR(kIOPMPowerHistoryEventTypeKey)));
5779    evReasonNum = isA_CFNumber(CFDictionaryGetValue(event, CFSTR(kIOPMPowerHistoryEventReasonKey)));
5780    evResultNum = isA_CFNumber(CFDictionaryGetValue(event, CFSTR(kIOPMPowerHistoryEventResultKey)));
5781    evDeviceNameString = isA_CFString(CFDictionaryGetValue(event, CFSTR(kIOPMPowerHistoryDeviceNameKey)));
5782    evUUIDString = isA_CFString(CFDictionaryGetValue(event, CFSTR(kIOPMPowerHistoryUUIDKey)));
5783    evInterestedDeviceNameString = isA_CFString(CFDictionaryGetValue(event, CFSTR(kIOPMPowerHistoryInterestedDeviceNameKey)));
5784    evTimestampAbsTime = isA_CFNumber(CFDictionaryGetValue(event, CFSTR(kIOPMPowerHistoryTimestampKey)));
5785    evOldState = isA_CFNumber(CFDictionaryGetValue(event, CFSTR(kIOPMPowerHistoryOldStateKey)));
5786    evNewState = isA_CFNumber(CFDictionaryGetValue(event, CFSTR(kIOPMPowerHistoryNewStateKey)));
5787    evElapsedTimeMicroSec = isA_CFNumber(CFDictionaryGetValue(event, CFSTR(kIOPMPowerHistoryElapsedTimeUSKey)));
5788
5789    // Timestamp
5790    if (evTimestampAbsTime) {
5791        CFNumberGetValue(evTimestampAbsTime, kCFNumberDoubleType, &ts);
5792        print_pretty_date(ts, false);
5793        printf("|");
5794    }
5795    else
5796      printf("\t");
5797
5798    bool systemEvent = false;
5799
5800    //Event Type
5801    if (evTypeString) {
5802        if (CFStringGetCString(evTypeString, buf_cstr, sizeof(buf_cstr), kCFStringEncodingUTF8)) {
5803            display_cstr = buf_cstr;
5804        } else {
5805            display_cstr = "String encoding error";
5806        }
5807
5808        if(   !strcmp(display_cstr, "UUIDSet")
5809           || !strcmp(display_cstr, "UUIDClear")
5810           || !strcmp(display_cstr, "Sleep")
5811           || !strcmp(display_cstr, "SleepDone")
5812           || !strcmp(display_cstr, "Wake")
5813           || !strcmp(display_cstr, "WakeDone") ) {
5814
5815          systemEvent = true;
5816
5817          // Prints bold lettering on supported systems
5818          printf("%c[1m", (char)27);
5819        }
5820        printf("%-25.25s", display_cstr);
5821        if( systemEvent ) {
5822          printf("%c[0m", (char)27);
5823        }
5824        printf("|");
5825    }
5826    else {
5827        printf("%-25s", " ");
5828    }
5829
5830    // Power State Change
5831    if (evOldState && evNewState) {
5832        CFNumberGetValue(evOldState, kCFNumberIntType, &foo);
5833        CFNumberGetValue(evNewState, kCFNumberIntType, &bar);
5834        printf("%d to %d |", foo, bar);
5835    }
5836    else
5837      printf("%-7s|", " ");
5838
5839    // Reason number
5840    if (evReasonNum) {
5841        CFNumberGetValue(evReasonNum, kCFNumberIntType, &foo);
5842        printf("%-7d|", foo);
5843    }
5844    else
5845      printf("%-7s|", " ");
5846
5847    // Result Number
5848    if (evResultNum) {
5849        CFNumberGetValue(evResultNum, kCFNumberIntType, &foo);
5850        printf("%-7d|", foo);
5851    }
5852    else
5853      printf("%-7s|", " ");
5854
5855    // Device Name
5856    if (evDeviceNameString) {
5857        if (CFStringGetCString(evDeviceNameString, buf_cstr, sizeof(buf_cstr), kCFStringEncodingUTF8)) {
5858            display_cstr = buf_cstr;
5859        } else {
5860            display_cstr = "String encoding error";
5861        }
5862
5863        printf("%-30.30s|", display_cstr);
5864    }
5865    else {
5866      if ( !systemEvent ) {
5867        printf("%-30s|", " ");
5868      }
5869    }
5870
5871    // Event UUID, for system events
5872    if (evUUIDString) {
5873        if (CFStringGetCString(evUUIDString, buf_cstr, sizeof(buf_cstr), kCFStringEncodingUTF8)) {
5874            display_cstr = buf_cstr;
5875        } else {
5876            display_cstr = "String encoding error";
5877        }
5878        // Bold lettering, in supported systems
5879        printf("%c[1m", (char)27);
5880        printf("%-61s", display_cstr);
5881        printf("%c[0m", (char)27);
5882
5883        printf("|");
5884    }
5885
5886    // Interested Device
5887    if (evInterestedDeviceNameString) {
5888        if (CFStringGetCString(evInterestedDeviceNameString, buf_cstr, sizeof(buf_cstr), kCFStringEncodingUTF8)) {
5889            display_cstr = buf_cstr;
5890        } else {
5891            display_cstr = "String encoding error";
5892        }
5893
5894        printf("%-30.30s|", display_cstr);
5895    }
5896    else {
5897      if( !systemEvent ) {
5898        printf("%-30s|", " ");
5899      }
5900    }
5901
5902    // Time Elapsed
5903    if (evElapsedTimeMicroSec) {
5904        CFNumberGetValue(evElapsedTimeMicroSec, kCFNumberIntType, &foo);
5905        printf("%-7d |", foo);
5906    }
5907    else
5908      printf("%-7s|", " ");
5909
5910    printf("\n");
5911}
5912
5913static void mt2bookmark(void)
5914{
5915    mach_port_t     connectIt = MACH_PORT_NULL;
5916    int disregard;
5917
5918    if (kIOReturnSuccess == _pm_connect(&connectIt))
5919    {
5920        io_pm_get_value_int(connectIt, kIOPMMT2Bookmark, &disregard);
5921        _pm_disconnect(connectIt);
5922    }
5923    return;
5924}
5925
5926
5927static void show_power_event_history_detailed(void)
5928{
5929    IOReturn        ret;
5930    CFArrayRef      powpowHistory = NULL;
5931    CFStringRef     uuid = NULL;
5932    char            uuid_cstr[50];
5933    CFDictionaryRef uuid_details;
5934    int             uuid_index;
5935    int             uuid_count;
5936
5937    ret = IOPMCopyPowerHistory(&powpowHistory);
5938
5939    if (kIOReturnSuccess == kIOReturnNotFound)
5940    {
5941        printf("No power management history to display. (See 'man pmset' to turn on history logging.)\n");
5942        goto exit;
5943    } else if (kIOReturnSuccess != ret)
5944    {
5945        printf("Error reading power management history (0x%08x)\n", ret);
5946        goto exit;
5947    }
5948
5949    uuid_count = CFArrayGetCount(powpowHistory);
5950
5951    //Bold lettering, on supported systems
5952    printf("%c[1m", (char)27);
5953    printf("Power History Detailed:\n");
5954    printf("%c[0m", (char)27);
5955
5956    for (uuid_index = 0; uuid_index < uuid_count; uuid_index++)
5957    {
5958        uuid_details = isA_CFDictionary(CFArrayGetValueAtIndex(powpowHistory, uuid_index));
5959        assert(uuid_details);
5960        if (!uuid_details) {
5961            continue;
5962        }
5963
5964        uuid = CFDictionaryGetValue(uuid_details,
5965                                    CFSTR(kIOPMPowerHistoryUUIDKey));
5966        CFStringGetCString(uuid, uuid_cstr,
5967                           sizeof(uuid_cstr), kCFStringEncodingUTF8);
5968        show_details_for_UUID( (char **)&uuid_cstr );
5969    }
5970
5971    CFRelease(powpowHistory);
5972exit:
5973    return;
5974}
5975
5976static void set_debugFlags(char **argv)
5977{
5978    uint32_t  newFlags, oldFlags;
5979    IOReturn err;
5980
5981    newFlags = strtol(argv[0], NULL, 0);
5982    if (errno == EINVAL ) {
5983        printf("Invalid argument\n");
5984        return;
5985    }
5986    err = IOPMSetDebugFlags(newFlags, &oldFlags);
5987    if (err == kIOReturnSuccess)
5988        printf("Debug flags changed from 0x%x to 0x%x\n",
5989                oldFlags, newFlags);
5990    else
5991        printf("Failed to change debugFlags. err=0x%x\n", err);
5992
5993}
5994
5995static void set_btInterval(char **argv)
5996{
5997    uint32_t  newInterval, oldInterval;
5998    IOReturn err;
5999
6000    newInterval = strtol(argv[0], NULL, 0);
6001    if (errno == EINVAL) {
6002        printf("Invalid argument\n");
6003        return;
6004    }
6005    err = IOPMSetBTWakeInterval(newInterval, &oldInterval);
6006    if (err == kIOReturnSuccess)
6007        printf("Background task wake interval changed from %d secs to %d secs\n",
6008                oldInterval, newInterval);
6009    else
6010        printf("Failed to change Background task wake interval. err=0x%x\n", err);
6011
6012}
6013
6014static void set_dwlInterval(char **argv)
6015{
6016    uint32_t newInterval, oldInterval;
6017    IOReturn err;
6018
6019    newInterval = strtol(argv[0], NULL, 0);
6020    if(errno == EINVAL) {
6021        printf("Invalid argument\n");
6022        return;
6023    }
6024    err = IOPMSetDWLingerInterval(newInterval, &oldInterval);
6025    if(err == kIOReturnSuccess)
6026        printf("DarkWake linger interval changed from %d secs to %d secs\n",
6027                oldInterval, newInterval);
6028    else
6029        printf("Failed to change DarkWake linger interval. err=0x%x\n", err);
6030}
6031
6032static void set_saaFlags(char **argv)
6033{
6034    uint32_t newFlags, oldFlags;
6035    IOReturn err;
6036
6037    newFlags = strtol(argv[0], NULL, 0);
6038    if(errno == EINVAL) {
6039        printf("Invalid argument\n");
6040        return;
6041    }
6042
6043    err = IOPMChangeSystemActivityAssertionBehavior(newFlags, &oldFlags);
6044    if(err == kIOReturnSuccess)
6045        printf("System activity assertion behvior changed from %u to %u\n",
6046                oldFlags, newFlags);
6047    else
6048        printf("Failed to change system activity assertion behavior. err=0x%x\n", err);
6049}
6050
6051static bool isBatteryPollingStopped(void)
6052{
6053    int                 myNotifyToken = 0;
6054    uint64_t            packedBatteryData = 0;
6055    int                 myNotifyStatus = 0;
6056
6057    myNotifyStatus = notify_register_check(kIOPSTimeRemainingNotificationKey, &myNotifyToken);
6058
6059    if (NOTIFY_STATUS_OK == myNotifyStatus) {
6060        notify_get_state(myNotifyToken, &packedBatteryData);
6061        notify_cancel(myNotifyToken);
6062    }
6063
6064    return (packedBatteryData & kPSTimeRemainingNotifyNoPollBit) ? 1:0;
6065}
6066
6067static void set_nopoll(void)
6068{
6069    mach_port_t     connectIt = MACH_PORT_NULL;
6070    bool            old_nopoll = isBatteryPollingStopped();
6071
6072    if (kIOReturnSuccess == _pm_connect(&connectIt))
6073    {
6074        printf("Turning battery polling: %s\n", old_nopoll ? "On":"Off");
6075        io_pm_set_value_int(connectIt, kIOPMSetNoPoll, old_nopoll ? 0:1);
6076        _pm_disconnect(connectIt);
6077    } else {
6078        printf("Error: could not connect to powerd.\n");
6079    }
6080
6081    if (!old_nopoll) {
6082        printf("Battery updates are stopped. Run \"pmset nopoll\" again, or reboot the system to resume.\n");
6083    }
6084}
6085
6086static void set_new_power_bookmark(void) {
6087  printf("Bookmarked: Deprecated. Did not set a bookmark. \n");
6088}
6089
6090static void show_details_for_UUID( char **argv ) {
6091
6092  char *uuid_cstr = argv[0];
6093
6094  if (!uuid_cstr) return;
6095
6096  string_toupper(uuid_cstr, uuid_cstr);
6097  CFStringRef uuid = CFStringCreateWithCString( kCFAllocatorDefault,
6098                                                uuid_cstr,
6099                                                kCFStringEncodingUTF8);
6100  if( uuid == NULL )
6101    return;
6102
6103  CFArrayRef event_array;
6104  CFDictionaryRef uuid_details;
6105
6106  IOReturn ret = IOPMCopyPowerHistoryDetailed(uuid, &uuid_details);
6107  if (kIOReturnSuccess != ret)
6108  {
6109    printf("No power management history to display for this UUID! \n");
6110      CFRelease(uuid);
6111    return;
6112  }
6113  if (!uuid_details)
6114  {
6115    printf("No power management history available for this UUID! \n");
6116    CFRelease(uuid);
6117    return;
6118  }
6119
6120  CFNumberRef timestamp;
6121  CFAbsoluteTime set_time   = 0.0;
6122  CFAbsoluteTime clear_time = 0.0;
6123
6124  timestamp = isA_CFNumber(
6125                  CFDictionaryGetValue(uuid_details,
6126                                       CFSTR(kIOPMPowerHistoryTimestampKey)));
6127
6128  CFNumberGetValue(timestamp, kCFNumberDoubleType, &set_time);
6129
6130  timestamp = isA_CFNumber(
6131                  CFDictionaryGetValue(
6132                              uuid_details,
6133                              CFSTR(kIOPMPowerHistoryTimestampCompletedKey)));
6134
6135  CFNumberGetValue(timestamp, kCFNumberDoubleType, &clear_time);
6136  //Bold lettering, on supported systems
6137
6138  printf("%c[1m", (char)27);
6139
6140  // Hacky way of centering the UUID title
6141  printf("\t\t\t\t\t *UUID =  %s\n", uuid_cstr);
6142  // No more bold lettering
6143  printf("%c[0m", (char)27);
6144
6145  // Print column headers, make nice table to display
6146  // power events under this UUID
6147  int i = 0;
6148  for(; i < 144; i+= 12)
6149    printf("------------");
6150  printf("--\n");
6151
6152  printf("%-24s|", "Timestamp");
6153  printf("%-25s|", "Event Type");
6154  printf("%-7s|", "Change");
6155  printf("%-7s|", "Reason");
6156  printf("%-7s|", "Result");
6157  printf("%-30s|","Device Name");
6158  printf("%-30s|","Interested Device");
6159  printf("Time(uS)|");
6160  printf("\n");
6161
6162  i = 0;
6163  for(; i < 144; i+= 12)
6164    printf("------------");
6165  printf("--\n");
6166
6167  event_array = CFDictionaryGetValue(uuid_details,
6168                                     CFSTR(kIOPMPowerHistoryEventArrayKey));
6169  int event_count = CFArrayGetCount(event_array);
6170  int event_index;
6171  CFDictionaryRef an_event;
6172
6173  // Print out individual event details
6174  for (event_index = 0; event_index < event_count; event_index++)
6175  {
6176    an_event = isA_CFDictionary(CFArrayGetValueAtIndex(event_array, event_index));
6177    assert(an_event);
6178    if (!an_event)
6179      continue;
6180    printHistoryDetailedEventDictionary(an_event);
6181  }
6182
6183  i = 0;
6184  for(; i < 144; i+= 12)
6185    printf("------------");
6186  printf("--\n");
6187
6188  printf("\t Total of ");
6189
6190  printf("%c[1m", (char)27); // Bold letters
6191  printf("%d ", event_count);
6192  printf("%c[0m", (char)27); // Un-bold letters
6193
6194  printf("events under UUID ");
6195
6196  printf("%c[1m", (char)27); // Bold letters
6197  printf("%s ", uuid_cstr);
6198  printf("%c[0m", (char)27); // Un-bold letters
6199  printf("from ");
6200  printf("%c[1m", (char)27);
6201  print_pretty_date(set_time, false);
6202  printf("%c[0m", (char)27);
6203  printf("to ");
6204  printf("%c[1m", (char)27);
6205  print_pretty_date(clear_time, true);
6206  printf("%c[0m", (char)27);
6207
6208  // Done with our CFObjects. Don't want to own them anymore
6209  CFRelease(event_array);
6210  CFRelease(uuid);
6211}
6212
6213static void _print_uuid_string(){
6214    CFStringRef     _uuid = IOPMSleepWakeCopyUUID();
6215    char            str[kMaxLongStringLength];
6216
6217    if (!_uuid) {
6218        printf("(NULL)\n");
6219        return;
6220    }
6221
6222    CFStringGetCString(_uuid, str, sizeof(str), kCFStringEncodingUTF8);
6223    printf("%s\n", str);
6224    CFRelease(_uuid);
6225}
6226static void _show_uuid_handler(
6227    void *refcon,
6228    io_service_t batt,
6229    natural_t messageType,
6230    void *messageArgument)
6231{
6232    if (messageType != kIOPMMessageSleepWakeUUIDChange)
6233        return;
6234
6235    print_pretty_date(CFAbsoluteTimeGetCurrent(), false);
6236
6237    if (messageArgument == (void *)kIOPMMessageSleepWakeUUIDCleared) {
6238        printf("Cleared.\n");
6239    } else if (messageArgument == (void *)kIOPMMessageSleepWakeUUIDSet) {
6240        _print_uuid_string();
6241    }
6242}
6243
6244static void show_uuid(bool keep_running)
6245{
6246    if (!keep_running) {
6247        _print_uuid_string();
6248        return;
6249    }
6250
6251    io_registry_entry_t     rd = copyRootDomainRef();
6252    IONotificationPortRef   notify = NULL;
6253    io_object_t             notification_ref = IO_OBJECT_NULL;
6254
6255    notify = IONotificationPortCreate(kIOMasterPortDefault);
6256    IONotificationPortSetDispatchQueue(notify, dispatch_get_main_queue());
6257
6258    IOServiceAddInterestNotification(notify, rd,
6259                                     kIOGeneralInterest, _show_uuid_handler,
6260                                     NULL, &notification_ref);
6261     install_listen_IORegisterForSystemPower();
6262     printf("Logging UUID changes.\n");
6263
6264    print_pretty_date(CFAbsoluteTimeGetCurrent(), false);
6265    _print_uuid_string();
6266
6267    CFRunLoopRun();
6268}
6269
6270
6271static void show_NULL_HID_events(void)
6272{
6273    CFArrayRef          systemHIDEvents = NULL;
6274    IOReturn            ret;
6275    int                 topLevelCount = 0;
6276
6277    ret = IOPMCopyHIDPostEventHistory(&systemHIDEvents);
6278    if (kIOReturnNotFound == ret) {
6279        // System is not collecting HID event history.
6280        // Assuming this is a setting that you can turn off with a hidden pmset flag,
6281        // then kIOReturnNotFound indicates it's turned off.
6282        printf("FAIL: ret=0x%08x kIOReturnNotFound - HID event capturing is OFF\n", ret);
6283        goto exit;
6284    } else if (kIOReturnSuccess != ret) {
6285        // Any other non-success return indicates a failure.
6286        printf("FAIL: ret=0x%08x - unexpected error\n", ret);
6287        return;
6288    }
6289
6290    if (!systemHIDEvents || (0 == (topLevelCount = CFArrayGetCount(systemHIDEvents))))
6291    {
6292        printf("PASS: kIOReturnSuccess with %s\n", systemHIDEvents?"zero events":"no returned dictionary");
6293        goto exit;
6294    }
6295
6296    int i;
6297    for (i=0; i<topLevelCount; i++)
6298    {
6299        CFDictionaryRef     d = CFArrayGetValueAtIndex(systemHIDEvents, i);
6300        char                app_path_string[1024];
6301        CFStringRef         appPathString = NULL;
6302        CFArrayRef          dataList = NULL;
6303        CFDataRef           dataChunk = NULL;
6304        IOPMHIDPostEventActivityWindow  *bucket = NULL;
6305        CFNumberRef         pidNum = NULL;
6306        int                 _pid = 0;
6307
6308        printf("\n");
6309
6310        pidNum = CFDictionaryGetValue(d, kIOPMHIDAppPIDKey);
6311        CFNumberGetValue(pidNum, kCFNumberIntType, &_pid);
6312        printf("* PID = %d\n", _pid);
6313
6314        appPathString = CFDictionaryGetValue(d, kIOPMHIDAppPathKey);
6315        if (appPathString
6316            && CFStringGetCString(appPathString, app_path_string, sizeof(app_path_string), kCFStringEncodingMacRoman))
6317        {
6318            printf(" Name = %s\n", app_path_string);
6319        } else {
6320            printf(" Name = unknown\n");
6321        }
6322
6323        dataList = CFDictionaryGetValue(d, kIOPMHIDHistoryArrayKey);
6324        int j;
6325        for (j=0; j<CFArrayGetCount(dataList); j++)
6326        {
6327            dataChunk = CFArrayGetValueAtIndex(dataList, j);
6328            bucket = (IOPMHIDPostEventActivityWindow *)CFDataGetBytePtr(dataChunk);
6329            printf(" Bucket (5 minute) starts: ");
6330            print_pretty_date(bucket->eventWindowStart, true);
6331            printf("   NULL events = %d\n", bucket->nullEventCount);
6332            printf("   Non-NULL events = %d\n", bucket->hidEventCount);
6333        }
6334
6335    }
6336
6337exit:
6338    if (systemHIDEvents)
6339        CFRelease(systemHIDEvents);
6340    return;
6341}
6342static bool is_display_dim_captured(void)
6343{
6344    io_registry_entry_t disp_wrangler = IO_OBJECT_NULL;
6345    CFBooleanRef dimCaptured          = NULL;
6346    bool ret                          = false;
6347
6348    disp_wrangler = IORegistryEntryFromPath(
6349                            kIOMasterPortDefault,
6350                            kIOServicePlane ":/IOResources/IODisplayWrangler");
6351    if(!disp_wrangler)
6352        return false;
6353
6354    dimCaptured = IORegistryEntryCreateCFProperty(
6355                        disp_wrangler,
6356                        CFSTR("DimCaptured"),
6357                        kCFAllocatorDefault,
6358                        kNilOptions);
6359
6360    if(dimCaptured)
6361    {
6362        ret = (kCFBooleanTrue == dimCaptured);
6363        CFRelease(dimCaptured);
6364    }
6365
6366    IOObjectRelease(disp_wrangler);
6367
6368    return ret;
6369}
6370#define kRootDomainUserClientClass 	"RootDomainUserClient"
6371static void show_root_domain_user_clients(void)
6372{
6373	io_registry_entry_t		_rootdomain = copyRootDomainRef();
6374	io_iterator_t			_matchingUserClients = IO_OBJECT_NULL;
6375	io_registry_entry_t		_iter = IO_OBJECT_NULL;
6376	kern_return_t			kr;
6377
6378	if (!_rootdomain) {
6379		printf("Internal Error - can't find root domain.");
6380		return;
6381	}
6382
6383	kr = IORegistryEntryGetChildIterator(_rootdomain, kIOServicePlane, &_matchingUserClients);
6384	if (kr != KERN_SUCCESS || !_matchingUserClients) {
6385		printf("Internal Error - can't find user clients. (kern_return_t error = %d)", kr);
6386		return;
6387	}
6388
6389	while ( ( _iter = IOIteratorNext(_matchingUserClients) ) )
6390	{
6391		io_name_t 			objectClass;
6392
6393		IOObjectGetClass((io_object_t)_iter, objectClass);
6394		if (!strncmp(objectClass, kRootDomainUserClientClass, strlen(kRootDomainUserClientClass)))
6395		{
6396			CFStringRef 	creatorString = NULL;
6397			char			stringBuf[kMaxLongStringLength];
6398
6399			creatorString = (CFStringRef)IORegistryEntryCreateCFProperty(_iter, CFSTR(kIOUserClientCreatorKey), 0, 0);
6400			if (creatorString
6401			&& CFStringGetCString(creatorString, stringBuf, sizeof(stringBuf), kCFStringEncodingMacRoman))
6402			{
6403				printf(" - %s\n", stringBuf);
6404			}
6405
6406            if(creatorString)
6407                CFRelease(creatorString);
6408		}
6409	}
6410
6411	IOObjectRelease(_matchingUserClients);
6412	IOObjectRelease(_rootdomain);
6413
6414	return;
6415}
6416
6417static void show_getters(void)
6418{
6419    int i = 0;
6420    for (i=0; i<the_getters_count; i++)
6421    {
6422        if (the_getters[i].actionType == kActionGetOnceNoArgs) {
6423            printf("%s\n", the_getters[i].arg);
6424        }
6425    }
6426}
6427
6428void fetchChannelData( char     *object,
6429    uint64_t                channel_id,
6430    bool                    print_error,
6431    void                    (^processChannelData)(uint64_t, CFStringRef))
6432{
6433    CFMutableDictionaryRef  desiredChs = NULL, subbedChs = NULL;
6434    CFDictionaryRef 		mdict  = NULL;
6435    IOReportSubscriptionRef iorsub = NULL;
6436    CFDictionaryRef         samples = NULL;
6437
6438
6439    if (!(mdict = IOServiceMatching(object))) {
6440        printf("Failed to match an object with name %s in registry\n", object);
6441        goto exit;
6442    }
6443    desiredChs = IOReportCopyChannelsWithID(mdict, channel_id, NULL);
6444    if (!desiredChs) {
6445        if (print_error)
6446            printf("Failed to find channel reporting power state for the object %s\n", object);
6447        goto exit;
6448    }
6449    if (!(iorsub = IOReportCreateSubscription(nil, desiredChs, &subbedChs, 0, NULL))) {
6450            if (print_error)
6451                printf("Internal failure: Failed to get power state information\n");
6452        goto exit;
6453    }
6454
6455
6456    if ((samples = IOReportCreateSamples(iorsub, subbedChs, NULL))) {
6457        IOReportIterate(samples, ^(IOReportSampleRef ch) {
6458
6459            uint64_t curstate = IOReportSimpleGetIntegerValue(ch, NULL);
6460            CFStringRef drv_name = IOReportChannelGetDriverName(ch);
6461
6462            processChannelData(curstate, drv_name);
6463            return kIOReportIterOk;
6464        });
6465	}
6466    else {
6467        if (print_error)
6468            printf("Internal failure: Failed to get power state information\n");
6469        goto exit;
6470    }
6471
6472
6473exit:
6474    if (iorsub) CFRelease(iorsub);
6475    if (subbedChs)  CFRelease(subbedChs);
6476    if (desiredChs) CFRelease(desiredChs);
6477    if (mdict) CFRelease(mdict);
6478
6479
6480    return;
6481
6482}
6483
6484
6485void display_powerstate( char *object, bool print_error)
6486{
6487    static  bool            row1 = true;
6488
6489
6490    if (row1) {
6491        printf("\n%15s  %13s  %9s  %s\n", "Driver ID", "Current State", "Max State", "Current State Description");
6492        row1= false;
6493    }
6494
6495    fetchChannelData(object, kPMCurrStateChID, print_error,  ^(uint64_t state_id, CFStringRef drv_name) {
6496        bool is_on = false, is_usable = false, is_lowpower = false;
6497        uint32_t cur_st=0, max_st=0;
6498        CFNumberRef objRef = NULL;
6499        const char *dname_cstr;
6500        char dname_buf[25], *spcptr;
6501
6502        // making this name useful is one reason this code might be better
6503        // in ioreg :P
6504        dname_cstr = CFStringGetCStringPtr(drv_name, kCFStringEncodingUTF8);
6505        if (!dname_cstr)    dname_cstr = "missing";
6506        snprintf(dname_buf, sizeof(dname_buf), "%s", dname_cstr);
6507        if ((spcptr = strchr(dname_buf, ' ')))        *spcptr = '\0';
6508
6509
6510        CFDictionaryRef dict = IOPMCopyPowerStateInfo(state_id);
6511        if (!dict) {
6512            printf("Internal error: Failed to obtain power state information for driver %s\n", dname_cstr);
6513            return ;
6514        }
6515        objRef = CFDictionaryGetValue(dict, kIOPMNodeCurrentState);
6516        if (objRef)
6517            CFNumberGetValue(objRef, kCFNumberIntType, &cur_st);
6518
6519        objRef = CFDictionaryGetValue(dict, kIOPMNodeMaxState);
6520        if (objRef)
6521            CFNumberGetValue(objRef, kCFNumberIntType, &max_st);
6522
6523        is_on = (CFDictionaryGetValue(dict, kIOPMNodeIsPowerOn) == kCFBooleanTrue) ? true : false;
6524        is_usable = (CFDictionaryGetValue(dict, kIOPMNodeIsDeviceUsable) == kCFBooleanTrue) ? true : false;
6525        is_lowpower = (CFDictionaryGetValue(dict, kIOPMNodeIsLowPower) == kCFBooleanTrue) ? true : false;
6526
6527
6528
6529        printf("%-25s %3d  %9d  ", dname_buf, cur_st, max_st);
6530        if ( (is_on || is_usable || is_lowpower) == false) printf("None\n");
6531        else {
6532            bool comma = false;
6533            if (is_on) {
6534                printf("ON");
6535                comma = true;
6536            }
6537            if (is_usable) {
6538                if (comma) printf(",");
6539                printf("USEABLE");
6540                comma = true;
6541            }
6542            if (is_lowpower) {
6543                if (comma) printf(",");
6544                printf("LOW_POWER");
6545            }
6546            printf("\n");
6547        }
6548        if (dict) CFRelease(dict);
6549        return ;
6550    });
6551
6552
6553    return;
6554}
6555
6556
6557
6558void scan_powerplane(io_registry_entry_t service)
6559{
6560    io_registry_entry_t child       = 0; // (needs release)
6561    io_registry_entry_t childUpNext = 0; // (don't release)
6562    io_iterator_t       children    = 0; // (needs release)
6563    io_name_t           name;
6564    kern_return_t       status      = KERN_SUCCESS;
6565
6566
6567    status = IORegistryEntryGetChildIterator(service, "IOPower", &children);
6568    if (status != KERN_SUCCESS) {
6569        return;
6570    }
6571
6572    childUpNext = IOIteratorNext(children);
6573
6574    status = IORegistryEntryGetNameInPlane(service, "IOPower", name);
6575
6576    if (strncmp(name, "IOPowerConnection", sizeof("IOPowerConnection"))) {
6577
6578        display_powerstate(name, false);
6579    }
6580
6581
6582    while (childUpNext) {
6583        child       = childUpNext;
6584        childUpNext = IOIteratorNext(children);
6585
6586        scan_powerplane(child);
6587
6588        IOObjectRelease(child);
6589    }
6590
6591    IOObjectRelease(children);
6592
6593}
6594static void show_power_state(char **argv)
6595{
6596    char                    *object = NULL;
6597    int                     i = 0, cnt = 0;
6598    io_registry_entry_t     service  = 0;
6599
6600    if (argv[i] != NULL) {
6601        object = argv[i++];
6602
6603        do {
6604            display_powerstate(object, true);
6605            cnt++;
6606        } while ((object = argv[i++]) != NULL);
6607        if (cnt == 0) goto exit;
6608    }
6609    else if ((service = IORegistryGetRootEntry(kIOMasterPortDefault)) != 0) {
6610        scan_powerplane(service);
6611        IOObjectRelease(service);
6612        goto exit;
6613    }
6614    else {
6615        printf("Internal failure: Failed to get the registry root entry\n");
6616        goto exit;
6617    }
6618
6619exit:
6620    ;   // C doesn't allow labels at the end of functions?
6621}
6622
6623static void display_statelog(IOReportChannelRef ch, int nobjects)
6624{
6625    uint32_t nstates, i;
6626    uint64_t state_id, transitions, ticks;
6627    uint64_t drv_name = IOReportChannelGetDriverName(ch);
6628    const char *dname_cstr;
6629    char dname_buf[22], *spcptr;
6630    uint32_t max_st=0;
6631    CFNumberRef objRef = NULL;
6632    CFDictionaryRef dict;
6633    static int max_states = 0;
6634    static int cnt = 0;
6635    int cur_state;
6636
6637
6638    nstates = IOReportStateGetCount(ch);
6639    if (cnt < nobjects) {
6640        for (i=0; i<nstates; i++) {
6641            state_id = IOReportStateGetIDForIndex(ch, i);
6642
6643            dict = IOPMCopyPowerStateInfo(state_id);
6644            if (!dict) continue;
6645
6646            objRef = CFDictionaryGetValue(dict, kIOPMNodeMaxState);
6647            if (objRef) {
6648                CFNumberGetValue(objRef, kCFNumberIntType, &max_st);
6649                if (max_st+1 > max_states) max_states=max_st+1;
6650            }
6651
6652            CFRelease(dict);
6653        }
6654
6655        cnt++;
6656        return;
6657    }
6658
6659    cur_state = IOReportStateGetCurrent(ch);
6660    if ((cnt-nobjects) % (10*nobjects) == 0) {
6661        printf("\n");
6662        print_pretty_date(CFAbsoluteTimeGetCurrent(), true);
6663        printf("%-18s ", "    Driver");
6664        for (i=0; i < max_states; i++) {
6665            printf("%8s[%d] ", "Time", i);
6666        }
6667        printf("       ");
6668        for (i=0; i < max_states; i++) {
6669            printf("%8s[%d] ", "Entries", i);
6670        }
6671        printf("\n");
6672    }
6673
6674    // making this name useful is one reason this code might be better
6675    // in ioreg :P
6676    dname_cstr = CFStringGetCStringPtr(drv_name, kCFStringEncodingUTF8);
6677    if (!dname_cstr)    dname_cstr = "missing";
6678    snprintf(dname_buf, sizeof(dname_buf), "%s", dname_cstr);
6679    if ((spcptr = strchr(dname_buf, ' ')))        *spcptr = '\0';
6680
6681
6682    printf("%-22s ", dname_buf);
6683    for (i=0; i<nstates; i++) {
6684        ticks = IOReportStateGetResidency(ch, i);
6685        if (cur_state == i)
6686            printf("*%#-11llx", ticks);
6687        else
6688            printf("%#-12llx", ticks);
6689    }
6690    for (;i < max_states; i++) {
6691        printf("%-12s ", " ");
6692    }
6693    printf("    ");
6694    for (i=0; i<nstates; i++) {
6695        transitions = IOReportStateGetInTransitions(ch, i);
6696        printf("%-11lld ", transitions);
6697    }
6698    for (;i < max_states; i++) {
6699        printf("%-11s ", " ");
6700    }
6701
6702    printf("\n");
6703
6704    cnt++;
6705}
6706
6707
6708static void show_power_statelog(char **argv)
6709{
6710    CFDictionaryRef 		mdict = NULL;
6711    IOReportSubscriptionRef sub = NULL;
6712    CFMutableDictionaryRef  desiredChs = NULL, subbedChs = NULL;
6713    CFDictionaryRef         current = NULL, diff = NULL;
6714    CFDictionaryRef         prev = NULL;
6715    char                    *object = NULL;
6716    int                     i = 0, nobjects = 0;
6717    int                     interval = 0;
6718
6719    if (argv[i] != NULL) {
6720        if (!strncmp(argv[i], "-i", sizeof("-i"))) {
6721            interval = strtol(argv[i+1], NULL, 0);
6722            i += 2;
6723        }
6724    }
6725
6726    if (argv[i] != NULL)
6727        object = argv[i++];
6728    else
6729        object = "IOPMrootDomain";
6730
6731    if (!interval) interval = 5;
6732    do {
6733        if (!(mdict = IOServiceMatching(object))) {
6734            printf("Failed to match an object with name %s in registry\n", object);
6735            continue;
6736        }
6737
6738        desiredChs = IOReportCopyChannelsWithID(mdict, kPMPowerStatesChID, NULL);
6739        CFRelease(mdict); mdict = NULL;
6740
6741        if (!desiredChs) {
6742            printf("Failed to find channel reporting power state for the object %s\n", object);
6743            continue;
6744        }
6745        nobjects++;
6746    } while ((object = argv[i++]) != NULL);
6747
6748    if (nobjects == 0) goto exit;
6749
6750	if (!(sub = IOReportCreateSubscription(nil, desiredChs, &subbedChs, 0, NULL))) {
6751        printf("Internal failure: Failed to get power state information\n");
6752        goto exit;
6753	}
6754
6755    printf("Polling at %d secs interval\n", interval);
6756    while ((current = IOReportCreateSamples(sub, subbedChs, NULL))) {
6757        if (prev) {
6758            diff = IOReportCreateSamplesDelta(prev, current, NULL);
6759            if (!diff) {
6760                printf("failed to compare power state to previous state");
6761                goto exit;
6762            }
6763            CFRelease(prev);
6764            prev = current;
6765            // samples = diff;
6766        }
6767        else {
6768            prev = current;
6769        }
6770        IOReportIterate(diff, ^(IOReportChannelRef ch) {
6771            display_statelog(ch, nobjects);
6772
6773            return kIOReportIterOk;
6774        });
6775
6776        sleep(interval);
6777	}
6778
6779exit:
6780    if (sub) CFRelease(sub);
6781    if (desiredChs) CFRelease(desiredChs);
6782    if (subbedChs) CFRelease(subbedChs);
6783}
6784
6785static void show_rdStats(char **argv)
6786{
6787
6788    fetchChannelData("IOPMrootDomain", kSleepCntChID, true,
6789            ^(uint64_t state_id, CFStringRef drv_name){ printf("Sleep Count:%lld\n", state_id); } );
6790
6791    fetchChannelData("IOPMrootDomain", kDarkWkCntChID, true,
6792            ^(uint64_t state_id, CFStringRef drv_name){ printf("Dark Wake Count:%lld\n", state_id); } );
6793
6794    fetchChannelData("IOPMrootDomain", kUserWkCntChID, true,
6795            ^(uint64_t state_id, CFStringRef drv_name){ printf("User Wake Count:%lld\n", state_id); } );
6796
6797}
6798
6799
6800#define kIOPMSystemCapabilitiesKey  "System Capabilities"
6801#define kPwrMgtKey                  "IOPowerManagement"
6802static void show_sysstate(char **argv)
6803{
6804    CFMutableDictionaryRef  rdProps = NULL;
6805    CFDictionaryRef  states = NULL;
6806    io_registry_entry_t rootDomain = copyRootDomainRef();
6807    CFNumberRef caps_cf = NULL, currSt_cf = NULL, desiredSt_cf = NULL;
6808    uint32_t caps;
6809    unsigned long currSt, desiredSt;
6810
6811    IORegistryEntryCreateCFProperties(rootDomain, &rdProps, 0, 0);
6812
6813    if (!rdProps) {
6814        printf("Internal error: Failed to get IOPMrootDomain properties\n");
6815        goto exit;
6816    }
6817
6818    caps_cf = CFDictionaryGetValue(rdProps, CFSTR(kIOPMSystemCapabilitiesKey));
6819    if (caps_cf) {
6820        CFNumberGetValue(caps_cf, kCFNumberIntType, &caps);
6821        printf("Current System Capabilities are: ");
6822        if (caps) {
6823            if (caps & kIOPMSystemCapabilityCPU) printf("CPU ");
6824            if (caps & kIOPMSystemCapabilityGraphics) printf("Graphics ");
6825            if (caps & kIOPMSystemCapabilityAudio) printf("Audio ");
6826            if (caps & kIOPMSystemCapabilityNetwork) printf("Network ");
6827        }
6828        else {
6829            printf("None");
6830        }
6831        printf("\n");
6832    }
6833
6834    states = CFDictionaryGetValue(rdProps, CFSTR(kPwrMgtKey));
6835    if (!states) goto exit;
6836
6837    currSt_cf = CFDictionaryGetValue(states, CFSTR("CurrentPowerState"));
6838    if (currSt_cf) {
6839        CFNumberGetValue(currSt_cf, kCFNumberLongType, &currSt);
6840        printf("Current Power State: %lu\n", currSt);
6841    }
6842    desiredSt_cf = CFDictionaryGetValue(states, CFSTR("DesiredPowerState"));
6843    if (desiredSt_cf) {
6844        CFNumberGetValue(desiredSt_cf, kCFNumberLongType, &desiredSt);
6845        if (desiredSt != currSt) {
6846            printf("Desired State: %lu\n", desiredSt);
6847            if (desiredSt == 1)
6848                printf("System restart is in progress\n");
6849            else if(desiredSt == 2)
6850                printf("System State is changing to Sleep\n");
6851            else if (desiredSt == 3)
6852                printf("System is waking from sleep\n");
6853        }
6854    }
6855
6856exit:
6857    if (rootDomain) IOObjectRelease(rootDomain);
6858    if (rdProps) CFRelease(rdProps);
6859
6860}
6861
6862static void show_everything(char **argv)
6863{
6864    printf("pmset is invoking all non-blocking -g arguments");
6865    int i=0;
6866	for (i=0; i<the_getters_count; i++) {
6867	    if (the_getters[i].actionType == kActionGetOnceNoArgs) {
6868            printf("\nINVOKE: pmset -g %s\n", the_getters[i].arg);
6869            the_getters[i].action(argv);
6870        }
6871    }
6872}
6873
6874