diff options
Diffstat (limited to 'src/factory-reset.c')
-rw-r--r-- | src/factory-reset.c | 341 |
1 files changed, 341 insertions, 0 deletions
diff --git a/src/factory-reset.c b/src/factory-reset.c new file mode 100644 index 0000000..a0de792 --- /dev/null +++ b/src/factory-reset.c @@ -0,0 +1,341 @@ +/* + * Copyright (c) 2000 - 2017 Samsung Electronics Co., Ltd. + * + * Contact: MyoungJune Park <mj2004.park@samsung.com> + * Created by Wonil Choi <wonil22.choi@samsung.com> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <linux/reboot.h> +#include <linux/limits.h> +#include <sys/reboot.h> +#include <sys/wait.h> +#include <sys/types.h> +#include <time.h> +#include <getopt.h> +#include <dbus/dbus.h> +#include <glib.h> +#include <dbus/dbus-glib-lowlevel.h> + +#define RESET_FLAG_FILE "/opt/.factoryreset" +static const char RESET_BACKUP_FILE[2][40] = { + "/usr/system/RestoreDir/opt.tar.gz", + "/usr/system/RestoreDir/opt.zip" +}; + +static const char *RUN_SCRIPT_FILE = "/usr/bin/run-factory-reset.sh"; +static const char *LOG_FILE = "/opt/.factoryreset.log"; +static const char *LOG_OLD = "/opt/.factoryreset.log.1"; + +static char *reset_flag; + +void usage() +{ + printf("Options: \n"); + printf(" -b, --dbus Start with dbus signal message\n"); + printf("\n"); + + exit(0); +} + +//extern int csc_svc_config_set_pre_config_for_factory_reset( void ); +/*================================================================================== +* CSC API Code (12/10/11 applied) + - Include header : #include "csc-dispatch.h" + - API : int csc_svc_config_set_pre_config_for_factory_reset( void ); + - Return value : 1 (Success), 0 (Failure, 미리 저장해놓은 거래선 코드가 없을 경우 발생) +====================================================================================*/ +int __system(const char *argv[]) +{ + int status; + pid_t cpid; + + cpid = fork(); + + if (cpid == -1) { + perror("fork"); + return -1; + } + + if (cpid == 0) { + execvp(argv[0], (char *const *)argv); + _exit(-1); + } else { + if (waitpid(cpid, &status, 0) == -1) { + perror("waitpid failed"); + return -1; + } + if (WIFSIGNALED(status)) { + perror("exit by signal"); + return -1; + } + if (!WIFEXITED(status)) { + perror("exit abnormally"); + return -1; + } + if (WIFEXITED(status) && WEXITSTATUS(status)) { + perror("child return error"); + return -1; + } + } + return 0; +} + + +#define RESET_DBUS_SERVICE "org.tizen.factoryreset" +#define RESET_DBUS_INTERFACE RESET_DBUS_SERVICE".start" + +static const char granted_caller[6][16] = { + "setting", + "cscmgr", + "wms", + "bt", /* when the host device is changed */ + "omadmagent", + "testmode" +}; + +static const char list_reset_flags[2][16] = { + "ftrrstcp", + "withoutcp" +}; + + +static GMainLoop* loop; +static DBusConnection *bus_conn = NULL; +static const char *dbus_obj_path = "/org/tizen/factoryreset"; + +static void unregistered_func (DBusConnection *connection, void *user_data) +{ + perror("factory-reset dbus unregistered\n"); +} + +static DBusHandlerResult message_func (DBusConnection *connection, + DBusMessage *message, + void *user_data) +{ + /* store the name of factory reset caller. */ + char caller_name[NAME_MAX]; + FILE *fp = NULL; + int i = 0; + + if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_SIGNAL) { + perror("Not a dbus-signal\n"); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } + + if (strncmp(dbus_message_get_interface(message), RESET_DBUS_INTERFACE, + strlen(RESET_DBUS_INTERFACE)) != 0) { + printf("Not correct interface: \"%s\"\n", + dbus_message_get_interface (message)); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } + + strncpy(caller_name, dbus_message_get_member(message), + sizeof(caller_name)); + caller_name[NAME_MAX - 1] = '\0'; + + while (strncmp(granted_caller[i], caller_name, + strlen(granted_caller[i]))) { + if ((++i) >= sizeof(granted_caller) / sizeof(granted_caller[0])) { + printf("Not a granted caller, %s\n", caller_name); + /* XXX Warning: Comparing granted caller list cannot + * grant good caller or not. Security is and should be + * protected by the SMACK rule. This code is only for + * preventing that a new unknown caller use factory + * reset without confirmation of the factory reset + * developer. + */ + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } + } + fp = fopen(LOG_FILE, "a"); + if (fp != NULL) { + fprintf(fp, "Requested by %s, %s\n", caller_name, + dbus_message_get_sender(message)); + fclose(fp); + } + + /* member name of dbus signal message may contains reset flags */ + for (i = 0; i < sizeof(list_reset_flags) / sizeof(list_reset_flags[0]); + i++) { + if (strstr(caller_name, list_reset_flags[i])) { + snprintf(caller_name, NAME_MAX, "--%s", + list_reset_flags[i]); + reset_flag = strdup(caller_name); + break; + } + } + + g_main_loop_quit(loop); + return DBUS_HANDLER_RESULT_HANDLED; +} + + +static DBusHandlerResult filter_func (DBusConnection *connection, + DBusMessage *message, void *user_data) +{ + if (dbus_message_is_signal (message, DBUS_INTERFACE_LOCAL, + "Disconnected")) { + /* Exit cleanly. */ + printf("Disconnected"); + } + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +static DBusObjectPathVTable dbus_vtable = { + unregistered_func, + message_func, + NULL, +}; + +static int process_dbus(void) +{ + int ret; + DBusError error; + + loop = g_main_loop_new (NULL, FALSE); + + dbus_error_init (&error); + bus_conn = dbus_bus_get(DBUS_BUS_SYSTEM, &error); + if (!bus_conn) { + perror("failed to get dbus system bus"); + dbus_error_free(&error); + return -1; + } + /* Add message filter to handle Disconnected. */ + dbus_connection_add_filter(bus_conn, (DBusHandleMessageFunction) filter_func, + NULL, NULL); + + ret = dbus_bus_request_name(bus_conn, RESET_DBUS_SERVICE, 0, &error); + + /* Should be ret == -1, if error is set */ + if (ret == -1 && dbus_error_is_set(&error)) { + dbus_error_free (&error); + return -1; + } + + if (!dbus_connection_register_object_path(bus_conn, dbus_obj_path, + &dbus_vtable, NULL)) { + return -1; + } + + dbus_connection_setup_with_g_main(bus_conn, NULL); + g_main_loop_run(loop); + return 0; +} + + +int main(int argc, char **argv) +{ + FILE *fp; + int ret, i = 0, c; + const char *reset_cmd[] = {RUN_SCRIPT_FILE, NULL, NULL}; + time_t t = time(NULL); + struct tm tm2 = *localtime(&t); + + static struct option long_options[] = { + {"dbus", no_argument, NULL, 'b'}, + {0, 0, 0, 0} + }; + + ret = setuid(0); + if (ret < 0) { + perror("wrong permission"); + return -1; + } + + /* If there is no factory-reset backup file, don't try to reset. */ + while (!(fp = fopen(RESET_BACKUP_FILE[i++], "r"))) { + if (i >= sizeof(RESET_BACKUP_FILE) / + sizeof(RESET_BACKUP_FILE[0])) { + perror("backup file is not exist"); + return -1; + } + } + if (fp != NULL) fclose(fp); + + if (rename(LOG_FILE, LOG_OLD) < 0) + perror("can't rename the old log file"); + + while (1) { + + int option_index = -1; + c = getopt_long(argc, argv, "b", long_options, &option_index); + if (c == -1) + break; + + switch (c) { + case 'b': + + if (process_dbus() < 0) { + perror("dbus has some errors."); + return -1; + } + break; + + default: + usage(); + break; + } + } + + if (optind < argc) + usage(); + +#if 0 + fp = fopen(RESET_FLAG_FILE, "w"); + if (fp == NULL) { + perror("reset flg file open error"); + return -1; + } + fclose(fp); +#endif + + // Factory Reset Run + reset_cmd[1] = reset_flag; + __system(reset_cmd); + + // open log file (add local time) + fp = fopen(LOG_FILE, "a"); + if (fp == NULL) { + perror("reset log file open error"); + return -2; + } + + // write finish log file + fprintf(fp, "End Factory Reset\n%d-%02d-%02d %02d:%02d:%02d\n", + tm2.tm_year + 1900, tm2.tm_mon + 1, tm2.tm_mday, + tm2.tm_hour, tm2.tm_min, tm2.tm_sec); + fclose(fp); + + // remove reset flag file, sync and reboot +#if 0 + unlink(RESET_FLAG_FILE); +#endif + sync(); + +#ifdef DEBUG_BINARY + reboot(LINUX_REBOOT_CMD_RESTART); +#else + const char *reboot_cmd[] = {"/usr/sbin/reboot", "debug0x4f4c", NULL}; + __system(reboot_cmd); +#endif + + return 0; +} |