* limitations under the License.
*/
-
+#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
return r;
}
-int terminate_process(const char *partition, bool force)
+static int terminate_processes_on_partition(const char *partition, bool force)
{
const char *argv[7] = {"/usr/bin/fuser", "-m", "-k", "-s", NULL, NULL, NULL};
int argc;
argv[4] = "-SIGKILL";
else
argv[4] = "-SIGTERM";
+
argv[5] = partition;
argc = sizeof(argv) / sizeof(argv[0]);
+
return run_child(argc, argv);
}
return ret;
}
-int umount_partition(const char *path, const bool force)
+static int get_num_processes_on_partition(const char *part_path)
{
- int retry = 0, ret = -1;
- struct timespec time = {0,};
-
- sync();
- while (ret && retry < 2) {
- switch (retry++) {
- case 0:
- /* Second, kill app with SIGTERM */
- _I("Kill app with SIGTERM");
- terminate_process(path, false);
- time.tv_nsec = 500 * NANO_SECOND_MULTIPLIER;
- nanosleep(&time, NULL);
- ret = umount2(path, 0);
- break;
- case 1:
- /* Last time, kill app with SIGKILL */
- _I("Kill app with SIGKILL");
- terminate_process(path, true);
- time.tv_nsec = 200 * NANO_SECOND_MULTIPLIER;
- nanosleep(&time, NULL);
- ret = umount2(path, 0);
- break;
- }
- _I("ret %d retry %d", ret, retry);
+ FILE *fp;
+ char *cmd = NULL;
+ char *line = NULL;
+ size_t len = 0;
+ int num_processes = 0;
+
+ asprintf(&cmd, "fuser -m %s | grep -o '[0-9]*'", part_path);
+ printf("cmd=%s\n", cmd);
+ fp = popen(cmd, "r");
+ free(cmd);
+ if (fp == NULL)
+ return -1;
+
+ while (getline(&line, &len, fp) != -1) {
+ num_processes++;
}
- if (ret) {
- if (force)
- ret = umount2(path, MNT_DETACH);
- else
- ret = umount2(path, 0);
+
+ free(line);
+ pclose(fp);
+
+ return num_processes;
+}
+
+void umount_partition_by_kill(const char *path, const int max_retry)
+{
+ FILE *fp;
+ char *part_path = NULL;
+ size_t len = 0;
+ int ret = 0, retry = 0;
+ int remain;
+ char *cmd = NULL;
+
+ /* if the path is not a mountpoint, do not perform umounting and killing */
+ if (!mount_check(path))
+ return;
+
+ ret = asprintf(&cmd, "mount | grep \" on %s \" | awk '{print $1}'", path);
+ if (ret == -1)
+ return;
+
+ fp = popen(cmd, "r");
+ free(cmd);
+ if (!fp)
+ return;
+
+ ret = getline(&part_path, &len, fp);
+ if (ret == -1 || !part_path) {
+ pclose(fp);
+ return;
+ } else if (ret > 0 && *(part_path + ret - 1) == '\n') {
+ *(part_path + ret -1) = '\0';
}
- if (ret)
- _I("Failed to unmount %s", path);
- else
- _I("%s unmounted successfully", path);
- return ret;
+
+ umount2(path, MNT_DETACH);
+
+ do {
+ sync();
+
+ /* Kill processes with SIGTERM */
+ terminate_processes_on_partition(part_path, false);
+ usleep((useconds_t)MSEC_TO_USEC(500));
+
+ /* Kill processes with SIGKILL */
+ terminate_processes_on_partition(part_path, true);
+ usleep((useconds_t)MSEC_TO_USEC(200));
+
+ remain = get_num_processes_on_partition(part_path);
+
+ retry++;
+
+ } while (remain > 0 && retry < max_retry);
+
+ pclose(fp);
+ return;
}
void print_time(const char *prefix)
#define POWEROFF_DURATION 2
#define MAX_RETRY 2
-#define POWEROFF_WAIT_RESOURCED (0.5*1000) /* 0.5 seconds */
-#define POWEROFF_WAIT_MAX 10 /* 10 seconds */
+#define POWEROFF_WAIT_RESOURCED (0.5*1000) /* 0.5 seconds */
+#define POWEROFF_WAIT_MAX 10 /* 10 seconds */
-#define SIGNAL_POWEROFF_STATE "ChangeState"
+#define SIGNAL_POWEROFF_STATE "ChangeState"
-#define UMOUNT_RW_PATH "/opt/usr"
+#define UMOUNT_RW_PATH_USER "/opt/usr"
+#define UMOUNT_RW_PATH_SYSTEM "/opt"
+#define MAX_UMOUNT_KILL_RETRY 4
-#define POWER_FLAG_POWEROFF "/run/"POWER_POWEROFF
-#define POWER_FLAG_REBOOT "/run/"POWER_REBOOT
+#define POWER_FLAG_POWEROFF "/run/"POWER_POWEROFF
+#define POWER_FLAG_REBOOT "/run/"POWER_REBOOT
-#define POWER_CONF_FILE "/etc/deviced/power.conf"
+#define POWER_CONF_FILE "/etc/deviced/power.conf"
struct power_flag {
enum poweroff_type type;
/* umount usr data partition */
static void unmount_rw_partition(void)
{
- umount_partition(UMOUNT_RW_PATH, true);
+ umount_partition_by_kill(UMOUNT_RW_PATH_USER, MAX_UMOUNT_KILL_RETRY);
+ umount_partition_by_kill(UMOUNT_RW_PATH_SYSTEM, MAX_UMOUNT_KILL_RETRY);
}
static void powerdown(void)