/* * Copyright (c) 2000 - 2017 Samsung Electronics Co., Ltd. * * Contact: MyoungJune Park * Created by Wonil Choi * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #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; }