power: refactor power operations
[platform/core/system/deviced.git] / src / power / power-off.c
1 /*
2  * deviced
3  *
4  * Copyright (c) 2012 - 2013 Samsung Electronics Co., Ltd.
5  *
6  * Licensed under the Apache License, Version 2.0 (the License);
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 #include <unistd.h>
20 #include <time.h>
21 #include <limits.h>
22 #include <fcntl.h>
23 #include <dirent.h>
24 #include <vconf.h>
25 #include <assert.h>
26 #include <sys/syscall.h>
27 #include <linux/reboot.h>
28 #include <sys/time.h>
29 #include <mntent.h>
30 #include <sys/mount.h>
31 #include <bundle.h>
32 #include <eventsystem.h>
33 #include <stdbool.h>
34 #include <signal.h>
35 #include <systemd/sd-daemon.h>
36 #include <libsyscommon/libgdbus.h>
37 #include <libsyscommon/libsystemd.h>
38 #include <libsyscommon/ini-parser.h>
39
40 #include "dd-deviced.h"
41 #include "core/log.h"
42 #include "shared/device-notifier.h"
43 #include "shared/common.h"
44 #include "shared/devices.h"
45 #include "display/poll.h"
46 #include "display/setting.h"
47 #include "display/core.h"
48 #include "display/display-ops.h"
49 #include "power-off.h"
50 #include "apps/apps.h"
51 #include "power-boot.h"
52 #include "shared/plugin.h"
53
54 #define POWEROFF_WAIT_RESOURCED     (0.5*1000) /* 0.5 seconds */
55 #define POWEROFF_WAIT_MAX           10 /* 10 seconds */
56 #define POWEROFF_WAIT_SYSTEMD_MS    (30 * 1000/*ms*/) /* 30 seconds */
57 #define SIGNAL_POWEROFF_STATE       "ChangeState"
58 #define POWER_CONF_FILE             "/etc/deviced/power.conf"
59
60 static struct display_plugin *disp_plgn;
61
62 static struct timeval tv_start_poweroff;
63 static GList *poweroff_options;
64 static struct power_option poweroff_opt;
65 static GList *poweroff_handles;
66
67 static const char *poweroff_type_flagpaths[] = { // index denotes type
68         [POWEROFF_TYPE_POWEROFF] = POWER_FLAG_POWEROFF,
69         [POWEROFF_TYPE_REBOOT] = POWER_FLAG_REBOOT,
70         [POWEROFF_TYPE_EXIT] = POWER_FLAG_EXIT,
71 };
72
73 static const char *poweroff_type_names[] = { // index denotes type
74         [POWEROFF_TYPE_POWEROFF] = POWER_POWEROFF,
75         [POWEROFF_TYPE_REBOOT] = POWER_REBOOT,
76         [POWEROFF_TYPE_EXIT] = POWER_EXIT,
77 };
78
79 enum poweroff_stage {
80         POWEROFF_DEFAULT,           /* Default stage, poweroff has not been triggered */
81         POWEROFF_TRIGGERED,         /* Poweroff is triggered. Wait timer can be added up to this stage */
82         POWEROFF_WAIT_OTHERS,       /* Wait for other processes to clean up their resources */
83 };
84
85 static int poweroff_delay_second = 0;
86 static enum poweroff_stage poweroff_stage;
87
88 static const char *poweroff_type_to_name(enum poweroff_type type)
89 {
90         if (type <= 0 || type >= ARRAY_SIZE(poweroff_type_names))
91                 return NULL;
92
93         return poweroff_type_names[type];
94 }
95
96 static enum poweroff_type poweroff_name_to_type(const char *name)
97 {
98         if (!name)
99                 goto out;
100
101         for (int i = 0; i < ARRAY_SIZE(poweroff_type_names); i++) {
102                 if (poweroff_type_names[i] && strcmp(poweroff_type_names[i], name) == 0)
103                         return i;
104         }
105 out:
106         return POWEROFF_TYPE_INVALID;
107 }
108
109 static void poweroff_start_animation(void)
110 {
111         int ret_val;
112
113         ret_val = systemd_start_unit_async("shutdown-animation.service", NULL);
114         if (ret_val < 0)
115                 _E("Failed to start shutdown animation.");
116
117         gettimeofday(&tv_start_poweroff, NULL);
118 }
119
120 static void poweroff_notify_resourced(void)
121 {
122         _I("Request to stop systemd service to resourced.");
123         gdbus_call_sync_with_reply_timeout(RESOURCED_BUS_NAME,
124                                 RESOURCED_PATH_PROCESS,
125                                 RESOURCED_INTERFACE_PROCESS,
126                                 "PrePoweroff",
127                                 NULL,
128                                 NULL,
129                                 POWEROFF_WAIT_RESOURCED);
130 }
131
132 static void disable_display(void)
133 {
134         const struct device_ops *display_device_ops = NULL;
135         FIND_DEVICE_VOID(display_device_ops, "display");
136         display_device_ops->stop(NORMAL_MODE);
137 }
138
139 static int disable_systemd_journald(void)
140 {
141         int ret_val;
142
143         ret_val = systemd_stop_unit_async("systemd-journald.socket", NULL);
144         if (ret_val < 0) {
145                 _E("Failed to stop 'systemd-journald.socket'.");
146                 return ret_val;
147         }
148
149         ret_val = systemd_stop_unit_async("systemd-journald.service", NULL);
150         if (ret_val < 0) {
151                 _E("Failed to stop 'systemd-journald.service'.");
152                 return ret_val;
153         }
154         return 0;
155 }
156
157 /* processes might start to fail abnormally after we kill them via
158  * umount_partition_by_kill. Failing services can trigger coredump
159  * handler, which might have trouble handling core in inconsistent
160  * system state (eg. lack of /opt).  Due to this we disable the
161  * coredump handler for the shutdown period.
162  */
163 static bool disable_coredump_handler(void)
164 {
165         int ret_val = 0;
166         int fd = open("/proc/sys/kernel/core_pattern", O_WRONLY);
167         if (fd >= 0) {
168                 ret_val = write(fd, "/dev/null", sizeof("/dev/null") - 1);
169                 close(fd);
170         }
171
172         bool is_ok = ret_val > 0;
173         _I("Disabling core dumps %s.", is_ok  ? "succeeded" : "failed");
174
175         return is_ok;
176 }
177
178 void poweroff_request_shutdown(void)
179 {
180         const char *method;
181
182         if (poweroff_opt.type == POWEROFF_TYPE_REBOOT)
183                 method = "Reboot";
184         else if (poweroff_opt.type == POWEROFF_TYPE_POWEROFF)
185                 method = "PowerOff";
186         else if (poweroff_opt.type == POWEROFF_TYPE_EXIT)
187                 method = "Exit";
188         else {
189                 _E("Poweroff invalid type(%d).", poweroff_opt.type);
190                 return;
191         }
192
193         CRITICAL_LOG("Requested %s via systemd.", method);
194         gdbus_call_sync_with_reply_timeout(SYSTEMD_DBUS_DEST,
195                                         SYSTEMD_DBUS_PATH,
196                                         SYSTEMD_DBUS_IFACE_MANAGER,
197                                         method,
198                                         NULL,
199                                         NULL,
200                                         POWEROFF_WAIT_SYSTEMD_MS);
201
202         raise(SIGUSR1);
203 }
204
205 static void poweroff_delay_for_seconds(void)
206 {
207         static int wait;
208         struct timeval now;
209         int check_duration = 0;
210
211         if (poweroff_delay_second == 0)
212                 return;
213
214         watchdog_notify();
215
216         gettimeofday(&now, NULL);
217         check_duration = now.tv_sec - tv_start_poweroff.tv_sec;
218
219         while (check_duration < poweroff_delay_second) {
220                 if (wait == 0) {
221                         _I("Wait poweroff %d %d.", check_duration, poweroff_delay_second);
222                         wait = 1;
223                 }
224                 usleep(100000);
225
226                 gettimeofday(&now, NULL);
227                 check_duration = now.tv_sec - tv_start_poweroff.tv_sec;
228
229                 if (check_duration < 0)
230                         break;
231         }
232
233         watchdog_notify();
234 }
235
236 void poweroff_prepare(void)
237 {
238         int off = poweroff_opt.type;
239
240         if (off == POWEROFF_TYPE_POWEROFF)
241                 CRITICAL_LOG("Prepare PowerOff.");
242         else if (off == POWEROFF_TYPE_REBOOT)
243                 CRITICAL_LOG("Prepare Reboot.");
244
245         poweroff_notify_resourced();
246         disable_systemd_journald();
247         disable_coredump_handler();
248
249         poweroff_delay_for_seconds();
250
251         disable_display();
252
253         /* Below functions follow after notifying DEVICE_NOTIFIER_POWEROFF
254            1. pmlock
255            - pmlock_detector_poweroff_cb()
256            - cleanup_pmlock_statistics()
257            - do_copy_force()
258            - save_display_log()
259            2. tzip
260            - tzip_poweroff()
261            - tzip_server_exit()
262            3. udev
263            - device_change_poweroff()
264            - uevent_control_stop()
265         */
266         device_notify(DEVICE_NOTIFIER_POWEROFF, &off);
267 }
268
269 int poweroff_check_revived(void)
270 {
271         for (int i = 0; i < ARRAY_SIZE(poweroff_type_flagpaths); i++) {
272                 if (access(poweroff_type_flagpaths[i], F_OK) == 0) {
273                         poweroff_opt.type = i;
274                         poweroff_opt.option = NULL;
275                         return 1;
276                 }
277         }
278
279         return 0;
280 }
281
282 static void make_power_flag(enum poweroff_type type, const char *option)
283 {
284         const char *path;
285         int fd;
286         ssize_t len;
287
288         if (type <= 0 || type >= ARRAY_SIZE(poweroff_type_flagpaths))
289                 return;
290
291         path = poweroff_type_flagpaths[type];
292         if (!path)
293                 return;
294
295         fd = open(path, O_RDWR|O_CREAT, S_IRUSR | S_IWUSR);
296         if (fd < 0) {
297                 _E("Failed to create '%s'.", path);
298                 return;
299         }
300
301         if (option) {
302                 len = write(fd, option, strlen(option));
303                 if (len <= 0)
304                         _E("Failed to store option: %zd", len < 0 ? errno : len);
305         }
306
307         close(fd);
308 }
309
310 static void poweroff_remove_handle(pid_t pid)
311 {
312         struct poweroff_handle *handle;
313         GList *elem;
314
315         SYS_G_LIST_FOREACH(poweroff_handles, elem, handle) {
316                 if (handle->pid == pid)
317                         break;
318         }
319
320         assert(handle);
321
322         _D("Remove handle pid=%d(%s) timeout=%d timeout_id=%d.", handle->pid, handle->comm, handle->timeout, handle->timeout_id);
323         SYS_G_LIST_REMOVE(poweroff_handles, handle);
324
325         if (handle->timeout_id) {
326                 g_source_remove(handle->timeout_id);
327                 handle->timeout = 0;
328                 handle->timeout_id = 0;
329         }
330
331         free(handle);
332 }
333
334 static int poweroff_add_handle(pid_t pid)
335 {
336         struct poweroff_handle *handle;
337         GList *l;
338
339         SYS_G_LIST_FOREACH(poweroff_handles, l, handle) {
340                 if (handle->pid == pid)
341                         break;
342         }
343
344         if (handle)
345                 poweroff_remove_handle(pid);
346
347         _D("Make a new handle.");
348         handle = (struct poweroff_handle *)malloc(sizeof(struct poweroff_handle));
349         if (handle == NULL) {
350                 _E("Not enough memory.");
351                 return -ENOMEM;
352         }
353
354         handle->pid = pid;
355         handle->timeout_id = 0;
356         handle->timeout = POWEROFF_WAIT_MAX;
357         get_command(pid, handle->comm, sizeof(handle->comm));
358
359         SYS_G_LIST_APPEND(poweroff_handles, handle);
360         _D("Add a new poweroff timer. pid=%d(%s) timeout=%d", handle->pid, handle->comm, handle->timeout);
361
362         return 0;
363 }
364
365 static gboolean poweroff_wait_timeout_cb(void *data)
366 {
367         char timeout[50] = {0,};
368         pid_t pid = (pid_t)((intptr_t)data);
369
370         poweroff_remove_handle(pid);
371
372         /* All other processes finished cleanup. Poweroff is now on standby */
373         if (poweroff_stage == POWEROFF_WAIT_OTHERS && SYS_G_LIST_LENGTH(poweroff_handles) == 0) {
374                 _D("The last poweroff wait timer for pid %d is expired. Poweroff is now on standby.", pid);
375
376                 CRITICAL_LOG("Starting poweroff sequence.");
377
378                 // Watchdog timeout 90 -> 30 sec to reduce delay from unexpected poweroff failure.
379                 snprintf(timeout, sizeof(timeout), "WATCHDOG_USEC=%llu", (unsigned long long)POWEROFF_WAIT_SYSTEMD_MS*1000);
380                 sd_notify(0, timeout);
381
382                 make_power_flag(poweroff_opt.type, poweroff_opt.option);
383
384                 if (disp_plgn->pm_lock_internal)
385                         disp_plgn->pm_lock_internal(INTERNAL_LOCK_POWEROFF, LCD_OFF, STAY_CUR_STATE, 0);
386
387                 poweroff_prepare();
388                 poweroff_request_shutdown();
389         } else {
390                 _D("Poweroff wait timer for pid %d is expired, but keep waiting for others...", pid);
391         }
392
393         return G_SOURCE_REMOVE;
394 }
395
396 static gboolean poweroff_start_timers(void *data)
397 {
398         struct poweroff_handle *handle = NULL;
399         GList *l;
400         bool timer_exist = false;
401         int pid_alive = 0;
402
403         poweroff_stage = POWEROFF_WAIT_OTHERS;
404
405         SYS_G_LIST_FOREACH(poweroff_handles, l, handle) {
406                 pid_alive = kill(handle->pid, 0);
407                 if (pid_alive == -1) {
408                         _D("Pid=%d(%s) is dead.", handle->pid, handle->comm);
409                         handle->timeout = 0;
410                 }
411
412                 _D("Run timer, pid=%d(%s) timeout=%d timeout_id=%d.", handle->pid, handle->comm, handle->timeout, handle->timeout_id);
413
414                 handle->timeout_id = g_timeout_add_seconds(handle->timeout,
415                                 poweroff_wait_timeout_cb,
416                                 (void *)((intptr_t)(handle->pid)));
417
418                 timer_exist = true;
419         }
420
421         if (timer_exist) {
422                 return G_SOURCE_REMOVE;
423         } else {
424                 _D("Handle is NULL.");
425
426                 handle = (struct poweroff_handle *)malloc(sizeof(struct poweroff_handle));
427                 if (handle == NULL) {
428                         _E("Not enough memory.");
429                         return G_SOURCE_REMOVE;
430                 }
431
432                 handle->pid = getpid();
433                 handle->timeout = 0;
434                 handle->timeout_id = g_timeout_add_seconds(handle->timeout,
435                                 poweroff_wait_timeout_cb,
436                                 (void *)((intptr_t)(handle->pid)));
437
438                 if (!handle->timeout_id) {
439                         _E("Failed to timer_add.");
440                         free(handle);
441                         return G_SOURCE_REMOVE;
442                 }
443
444                 SYS_G_LIST_APPEND(poweroff_handles, handle);
445         }
446
447         _D("Last Timer: timer_id=%d pid=%d timeout=%d", handle->timeout_id, handle->pid, handle->timeout);
448
449         return G_SOURCE_REMOVE;
450 }
451
452 static void system_shutdown_send_system_event(void)
453 {
454         bundle *b;
455
456         b = bundle_create();
457         bundle_add_str(b, EVT_KEY_SYSTEM_SHUTDOWN, EVT_VAL_SYSTEM_SHUTDOWN_TRUE);
458         eventsystem_send_system_event(SYS_EVENT_SYSTEM_SHUTDOWN, b);
459         bundle_free(b);
460 }
461
462 static int poweroff_option_valid(enum poweroff_type type_e, const char *option)
463 {
464         GList *l;
465         struct power_option *elem;
466
467         SYS_G_LIST_FOREACH(poweroff_options, l, elem) {
468                 if (elem->type != type_e)
469                         continue;
470
471                 /* Do not match option
472                 if (option) {
473                         if (elem->option == NULL)
474                                 continue;
475                         if (strncmp(elem->option, option, strlen(elem->option)))
476                                 continue;
477                 } else {
478                         if (elem->option != NULL)
479                                 continue;
480                 } */
481                 return 1;
482         }
483
484         return 0;
485 }
486
487 static void poweroff_send_broadcast(int status)
488 {
489         static int old = 0;
490         int ret_dbus;
491
492         if (old == status)
493                 return;
494
495         _D("Broadcast poweroff %d.", status);
496
497         old = status;
498
499         /* Need to notify to deviced-vibrator. deviced-vibrator receives ChangeState signal for POWEROFF_TYPE_DIRECT and POWEROFF_TYPE_RESTART */
500         ret_dbus = gdbus_signal_emit(NULL,
501                                                 DEVICED_PATH_POWEROFF,
502                                                 DEVICED_INTERFACE_POWEROFF,
503                                                 SIGNAL_POWEROFF_STATE,
504                                                 g_variant_new("(i)", status));
505         if (ret_dbus < 0)
506                 _E("Failed to send dbus signal(%s)", SIGNAL_POWEROFF_STATE);
507 }
508
509 static int __poweroff_trigger_poweroff(const char *typename, const char *option)
510 {
511         int ret_val;
512
513         if (poweroff_stage >= POWEROFF_TRIGGERED) {
514                 _E("Duplicate poweroff request. Poweroff was already triggered.");
515                 return -EINVAL;
516         }
517
518         enum poweroff_type type_e = poweroff_name_to_type(typename);
519         if (type_e == POWEROFF_TYPE_INVALID) {
520                 _E("Failed to get type enum value(%d).", type_e);
521                 return -EINVAL;
522         }
523
524         if (poweroff_option_valid(type_e, option)) {
525                 poweroff_opt.type = type_e;
526                 free(poweroff_opt.option);
527                 poweroff_opt.option = NULL;
528                 if (option)
529                         poweroff_opt.option = strdup(option);
530         } else {
531                 _E("Failed to find supported type(%s). option=%s", typename, (option ? option : "NULL"));
532                 return -EINVAL;
533         }
534
535         ret_val = vconf_set_int(VCONFKEY_SYSMAN_POWER_OFF_STATUS, poweroff_opt.type);
536         if (ret_val < 0)
537                 _E("Failed to set vconf value for power off status: %d", vconf_get_ext_errno());
538
539         poweroff_stage = POWEROFF_TRIGGERED;
540         if (disp_plgn->update_pm_setting)
541                 disp_plgn->update_pm_setting(SETTING_POWEROFF, poweroff_opt.type);
542
543         /* Poweroff event broadcasting */
544         system_shutdown_send_system_event();
545         poweroff_send_broadcast(poweroff_opt.type);
546
547         /* Skip running animation if option is silent */
548         if (poweroff_opt.option != NULL && !strcmp(poweroff_opt.option, "silent"))
549                 _D("Skip running poweroff animation.");
550         else
551                 poweroff_start_animation();
552
553         /* Spare time for AddPowerOffWait requests */
554         g_timeout_add_seconds(1, poweroff_start_timers, NULL);
555
556         return 0;
557 }
558
559 int poweroff_trigger_poweroff(void *data)
560 {
561         return __poweroff_trigger_poweroff((char *)data, NULL);
562 }
563
564 static int check_sender_process(GDBusConnection *conn, const char *sender)
565 {
566         pid_t pid;
567
568         if (sender == NULL || g_dbus_is_name(sender) == FALSE) {
569                 _E("Invalid sender");
570                 return -EINVAL;
571         }
572
573         pid = gdbus_connection_get_sender_pid(conn, sender);
574         if (pid == -1 || kill(pid, 0) == -1) {
575                 _E("Process(%d) does not exist, dbus ignored.", pid);
576                 return -ESRCH;
577         }
578
579         return pid;
580 }
581
582 static GVariant *dbus_power_handler(GDBusConnection *conn,
583         const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
584         GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
585 {
586         int ret;
587         char comm[128] = "Unknown";
588         char *type_str;
589
590         g_variant_get(param, "(s)", &type_str);
591
592         ret = check_sender_process(conn, sender);
593         if (ret < 0)
594                 goto out;
595
596         get_command(ret, comm, sizeof(comm));
597
598         CRITICAL_LOG("Poweroff pid=%d(%s) requests %s.", ret, comm, type_str);
599         ret = __poweroff_trigger_poweroff(type_str, NULL);
600
601 out:
602         g_free(type_str);
603         return g_variant_new("(i)", ret);
604 }
605
606 static GVariant *dbus_power_option_handler(GDBusConnection *conn,
607         const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
608         GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
609 {
610         int ret;
611         char comm[128] = "Unknown";
612         char *type, *option;
613
614         g_variant_get(param, "(ss)", &type, &option);
615
616         ret = check_sender_process(conn, sender);
617         if (ret < 0)
618                 goto out;
619
620         get_command(ret, comm, sizeof(comm));
621
622         CRITICAL_LOG("Poweroff pid=%d(%s) requests type=%s option=%s.", ret, comm, type, option);
623         ret = __poweroff_trigger_poweroff(type, option);
624
625 out:
626         g_free(type);
627         g_free(option);
628         return g_variant_new("(i)", ret);
629 }
630
631 /* timer can be added before the stage POWEROFF_WAIT_OTHERS */
632 static GVariant *add_poweroff_time(GDBusConnection *conn,
633         const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
634         GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
635 {
636         int ret;
637         pid_t pid;
638
639         if (poweroff_stage >= POWEROFF_WAIT_OTHERS) {
640                 _E("It's too late. Poweroff is already in waiting stage.");
641                 ret = -1;
642                 goto out;
643         }
644
645         ret = check_sender_process(conn, sender);
646         if (ret < 0)
647                 goto out;
648
649         pid = (pid_t)ret;
650         ret = poweroff_add_handle(pid);
651
652 out:
653         return g_variant_new("(i)", ret);
654 }
655
656 static GVariant *remove_poweroff_time(GDBusConnection *conn,
657         const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
658         GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
659 {
660         struct poweroff_handle *handle;
661         GList *l;
662         int ret = 0;
663         pid_t pid;
664
665         ret = check_sender_process(conn, sender);
666         if (ret < 0)
667                 goto out;
668
669         pid = (pid_t)ret;
670
671         SYS_G_LIST_FOREACH(poweroff_handles, l, handle) {
672                 if (handle->pid == pid)
673                         break;
674         }
675
676         if (handle) {
677                 if (handle->timeout_id)
678                         g_source_remove(handle->timeout_id);
679                 handle->timeout = 0;
680                 handle->timeout_id = g_timeout_add_seconds(handle->timeout,
681                                 poweroff_wait_timeout_cb,
682                                 (void *)((intptr_t)(handle->pid)));
683         } else {
684                 _E("Invalid pid(%d).", pid);
685                 ret = -1;
686         }
687
688 out:
689         return g_variant_new("(i)", ret);
690 }
691
692 static const dbus_method_s dbus_methods[] = {
693         { "PowerOff"          , "s" , "i", dbus_power_handler },
694         { "PowerOffWithOption", "ss", "i", dbus_power_option_handler },
695         /* Public API device_power_reboot() calls this dbus method. */
696         { "AddPowerOffWait"   , NULL, "i", add_poweroff_time },
697         { "RemovePowerOffWait", NULL, "i", remove_poweroff_time },
698         /* Add methods here */
699 };
700
701 static const dbus_interface_u dbus_interface = {
702         .oh = NULL,
703         .name = DEVICED_INTERFACE_POWEROFF,
704         .methods = dbus_methods,
705         .nr_methods = ARRAY_SIZE(dbus_methods),
706 };
707
708 static int add_poweroff_option(enum poweroff_type type, const char *option)
709 {
710         struct power_option *opt;
711         const char *name;
712
713         name = poweroff_type_to_name(type);
714         if (!name) {
715                 _E("Invalid type(%d).", type);
716                 return -EINVAL;
717         }
718
719         opt = calloc(1, sizeof(struct power_option));
720         if (!opt) {
721                 _E("Failed to calloc().");
722                 return -ENOMEM;
723         }
724
725         opt->type = type;
726         opt->option = (option ? strdup(option) : NULL);
727
728         SYS_G_LIST_APPEND(poweroff_options, opt);
729
730         _D("Add %s option=%s", name, opt->option);
731
732         return 0;
733 }
734
735 int poweroff_add_wait(pid_t pid)
736 {
737         return poweroff_add_handle(pid);
738 }
739
740 void poweroff_remove_wait(pid_t pid)
741 {
742         g_idle_add(poweroff_wait_timeout_cb, (void *)(intptr_t) pid);
743 }
744
745 static int load_config(struct parse_result *result, void *user_data)
746 {
747         enum poweroff_type type;
748
749         if (MATCH(result->section, "PowerOff") && MATCH(result->name, "Option")) {
750                 type = POWEROFF_TYPE_DIRECT;
751                 add_poweroff_option(type, result->value);
752         } else if (MATCH(result->section, "Reboot") && MATCH(result->name, "Option")) {
753                 type = POWEROFF_TYPE_RESTART;
754                 add_poweroff_option(type, result->value);
755         } else if (MATCH(result->section, "PowerState") && MATCH(result->name, "PowerOffDelaySecond")) {
756                 sscanf(result->value, "%d", &poweroff_delay_second);
757         }
758
759         return 0;
760 }
761
762 static int delayed_init_done(void *data)
763 {
764         static int done;
765
766         if (data == NULL)
767                 goto out;
768
769         done = *(int *)data;
770 out:
771         return done;
772 }
773
774 void power_off_init(void)
775 {
776         int ret_val;
777
778         /* init dbus interface */
779         ret_val = gdbus_add_object(NULL, DEVICED_PATH_POWEROFF, &dbus_interface);
780         if (ret_val < 0)
781                 _E("Failed to init dbus method: %d", ret_val);
782
783         add_delayed_init_done_handler(NULL);
784
785         register_notifier(DEVICE_NOTIFIER_DELAYED_INIT, delayed_init_done);
786
787         add_poweroff_option(POWEROFF_TYPE_POWEROFF, NULL);
788         add_poweroff_option(POWEROFF_TYPE_RESTART, NULL);
789         add_poweroff_option(POWEROFF_TYPE_EXIT, NULL);
790
791         ret_val = config_parse(POWER_CONF_FILE, load_config, NULL);
792         if (ret_val < 0)
793                 _E("Failed to load power off config: %d", ret_val);
794
795         poweroff_stage = POWEROFF_DEFAULT;
796 }
797
798 static void __CONSTRUCTOR__ initialize(void)
799 {
800         disp_plgn = get_var_display_plugin();
801         if (!disp_plgn)
802                 _E("Failed to get display plugin variable.");
803 }