18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * tmon.c Thermal Monitor (TMON) main function and entry point 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2012 Intel Corporation. All rights reserved. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Author: Jacob Pan <jacob.jun.pan@linux.intel.com> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <getopt.h> 118c2ecf20Sopenharmony_ci#include <unistd.h> 128c2ecf20Sopenharmony_ci#include <stdio.h> 138c2ecf20Sopenharmony_ci#include <stdlib.h> 148c2ecf20Sopenharmony_ci#include <string.h> 158c2ecf20Sopenharmony_ci#include <sys/types.h> 168c2ecf20Sopenharmony_ci#include <sys/stat.h> 178c2ecf20Sopenharmony_ci#include <ncurses.h> 188c2ecf20Sopenharmony_ci#include <ctype.h> 198c2ecf20Sopenharmony_ci#include <time.h> 208c2ecf20Sopenharmony_ci#include <signal.h> 218c2ecf20Sopenharmony_ci#include <limits.h> 228c2ecf20Sopenharmony_ci#include <sys/time.h> 238c2ecf20Sopenharmony_ci#include <pthread.h> 248c2ecf20Sopenharmony_ci#include <math.h> 258c2ecf20Sopenharmony_ci#include <stdarg.h> 268c2ecf20Sopenharmony_ci#include <syslog.h> 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#include "tmon.h" 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ciunsigned long ticktime = 1; /* seconds */ 318c2ecf20Sopenharmony_ciunsigned long no_control = 1; /* monitoring only or use cooling device for 328c2ecf20Sopenharmony_ci * temperature control. 338c2ecf20Sopenharmony_ci */ 348c2ecf20Sopenharmony_cidouble time_elapsed = 0.0; 358c2ecf20Sopenharmony_ciunsigned long target_temp_user = 65; /* can be select by tui later */ 368c2ecf20Sopenharmony_ciint dialogue_on; 378c2ecf20Sopenharmony_ciint tmon_exit; 388c2ecf20Sopenharmony_cistatic short daemon_mode; 398c2ecf20Sopenharmony_cistatic int logging; /* for recording thermal data to a file */ 408c2ecf20Sopenharmony_cistatic int debug_on; 418c2ecf20Sopenharmony_ciFILE *tmon_log; 428c2ecf20Sopenharmony_ci/*cooling device used for the PID controller */ 438c2ecf20Sopenharmony_cichar ctrl_cdev[CDEV_NAME_SIZE] = "None"; 448c2ecf20Sopenharmony_ciint target_thermal_zone; /* user selected target zone instance */ 458c2ecf20Sopenharmony_cistatic void start_daemon_mode(void); 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cipthread_t event_tid; 488c2ecf20Sopenharmony_cipthread_mutex_t input_lock; 498c2ecf20Sopenharmony_civoid usage(void) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci printf("Usage: tmon [OPTION...]\n"); 528c2ecf20Sopenharmony_ci printf(" -c, --control cooling device in control\n"); 538c2ecf20Sopenharmony_ci printf(" -d, --daemon run as daemon, no TUI\n"); 548c2ecf20Sopenharmony_ci printf(" -g, --debug debug message in syslog\n"); 558c2ecf20Sopenharmony_ci printf(" -h, --help show this help message\n"); 568c2ecf20Sopenharmony_ci printf(" -l, --log log data to /var/tmp/tmon.log\n"); 578c2ecf20Sopenharmony_ci printf(" -t, --time-interval sampling time interval, > 1 sec.\n"); 588c2ecf20Sopenharmony_ci printf(" -T, --target-temp initial target temperature\n"); 598c2ecf20Sopenharmony_ci printf(" -v, --version show version\n"); 608c2ecf20Sopenharmony_ci printf(" -z, --zone target thermal zone id\n"); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci exit(0); 638c2ecf20Sopenharmony_ci} 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_civoid version(void) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci printf("TMON version %s\n", VERSION); 688c2ecf20Sopenharmony_ci exit(EXIT_SUCCESS); 698c2ecf20Sopenharmony_ci} 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistatic void tmon_cleanup(void) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci syslog(LOG_INFO, "TMON exit cleanup\n"); 748c2ecf20Sopenharmony_ci fflush(stdout); 758c2ecf20Sopenharmony_ci refresh(); 768c2ecf20Sopenharmony_ci if (tmon_log) 778c2ecf20Sopenharmony_ci fclose(tmon_log); 788c2ecf20Sopenharmony_ci if (event_tid) { 798c2ecf20Sopenharmony_ci pthread_mutex_lock(&input_lock); 808c2ecf20Sopenharmony_ci pthread_cancel(event_tid); 818c2ecf20Sopenharmony_ci pthread_mutex_unlock(&input_lock); 828c2ecf20Sopenharmony_ci pthread_mutex_destroy(&input_lock); 838c2ecf20Sopenharmony_ci } 848c2ecf20Sopenharmony_ci closelog(); 858c2ecf20Sopenharmony_ci /* relax control knobs, undo throttling */ 868c2ecf20Sopenharmony_ci set_ctrl_state(0); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci keypad(stdscr, FALSE); 898c2ecf20Sopenharmony_ci echo(); 908c2ecf20Sopenharmony_ci nocbreak(); 918c2ecf20Sopenharmony_ci close_windows(); 928c2ecf20Sopenharmony_ci endwin(); 938c2ecf20Sopenharmony_ci free_thermal_data(); 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci exit(1); 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cistatic void tmon_sig_handler(int sig) 998c2ecf20Sopenharmony_ci{ 1008c2ecf20Sopenharmony_ci syslog(LOG_INFO, "TMON caught signal %d\n", sig); 1018c2ecf20Sopenharmony_ci refresh(); 1028c2ecf20Sopenharmony_ci switch (sig) { 1038c2ecf20Sopenharmony_ci case SIGTERM: 1048c2ecf20Sopenharmony_ci printf("sigterm, exit and clean up\n"); 1058c2ecf20Sopenharmony_ci fflush(stdout); 1068c2ecf20Sopenharmony_ci break; 1078c2ecf20Sopenharmony_ci case SIGKILL: 1088c2ecf20Sopenharmony_ci printf("sigkill, exit and clean up\n"); 1098c2ecf20Sopenharmony_ci fflush(stdout); 1108c2ecf20Sopenharmony_ci break; 1118c2ecf20Sopenharmony_ci case SIGINT: 1128c2ecf20Sopenharmony_ci printf("ctrl-c, exit and clean up\n"); 1138c2ecf20Sopenharmony_ci fflush(stdout); 1148c2ecf20Sopenharmony_ci break; 1158c2ecf20Sopenharmony_ci default: 1168c2ecf20Sopenharmony_ci break; 1178c2ecf20Sopenharmony_ci } 1188c2ecf20Sopenharmony_ci tmon_exit = true; 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_cistatic void start_syslog(void) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci if (debug_on) 1248c2ecf20Sopenharmony_ci setlogmask(LOG_UPTO(LOG_DEBUG)); 1258c2ecf20Sopenharmony_ci else 1268c2ecf20Sopenharmony_ci setlogmask(LOG_UPTO(LOG_ERR)); 1278c2ecf20Sopenharmony_ci openlog("tmon.log", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL0); 1288c2ecf20Sopenharmony_ci syslog(LOG_NOTICE, "TMON started by User %d", getuid()); 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cistatic void prepare_logging(void) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci int i; 1348c2ecf20Sopenharmony_ci struct stat logstat; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci if (!logging) 1378c2ecf20Sopenharmony_ci return; 1388c2ecf20Sopenharmony_ci /* open local data log file */ 1398c2ecf20Sopenharmony_ci tmon_log = fopen(TMON_LOG_FILE, "w+"); 1408c2ecf20Sopenharmony_ci if (!tmon_log) { 1418c2ecf20Sopenharmony_ci syslog(LOG_ERR, "failed to open log file %s\n", TMON_LOG_FILE); 1428c2ecf20Sopenharmony_ci return; 1438c2ecf20Sopenharmony_ci } 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci if (lstat(TMON_LOG_FILE, &logstat) < 0) { 1468c2ecf20Sopenharmony_ci syslog(LOG_ERR, "Unable to stat log file %s\n", TMON_LOG_FILE); 1478c2ecf20Sopenharmony_ci fclose(tmon_log); 1488c2ecf20Sopenharmony_ci tmon_log = NULL; 1498c2ecf20Sopenharmony_ci return; 1508c2ecf20Sopenharmony_ci } 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci /* The log file must be a regular file owned by us */ 1538c2ecf20Sopenharmony_ci if (S_ISLNK(logstat.st_mode)) { 1548c2ecf20Sopenharmony_ci syslog(LOG_ERR, "Log file is a symlink. Will not log\n"); 1558c2ecf20Sopenharmony_ci fclose(tmon_log); 1568c2ecf20Sopenharmony_ci tmon_log = NULL; 1578c2ecf20Sopenharmony_ci return; 1588c2ecf20Sopenharmony_ci } 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci if (logstat.st_uid != getuid()) { 1618c2ecf20Sopenharmony_ci syslog(LOG_ERR, "We don't own the log file. Not logging\n"); 1628c2ecf20Sopenharmony_ci fclose(tmon_log); 1638c2ecf20Sopenharmony_ci tmon_log = NULL; 1648c2ecf20Sopenharmony_ci return; 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci fprintf(tmon_log, "#----------- THERMAL SYSTEM CONFIG -------------\n"); 1688c2ecf20Sopenharmony_ci for (i = 0; i < ptdata.nr_tz_sensor; i++) { 1698c2ecf20Sopenharmony_ci char binding_str[33]; /* size of long + 1 */ 1708c2ecf20Sopenharmony_ci int j; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci memset(binding_str, 0, sizeof(binding_str)); 1738c2ecf20Sopenharmony_ci for (j = 0; j < 32; j++) 1748c2ecf20Sopenharmony_ci binding_str[j] = (ptdata.tzi[i].cdev_binding & (1 << j)) ? 1758c2ecf20Sopenharmony_ci '1' : '0'; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci fprintf(tmon_log, "#thermal zone %s%02d cdevs binding: %32s\n", 1788c2ecf20Sopenharmony_ci ptdata.tzi[i].type, 1798c2ecf20Sopenharmony_ci ptdata.tzi[i].instance, 1808c2ecf20Sopenharmony_ci binding_str); 1818c2ecf20Sopenharmony_ci for (j = 0; j < ptdata.tzi[i].nr_trip_pts; j++) { 1828c2ecf20Sopenharmony_ci fprintf(tmon_log, "#\tTP%02d type:%s, temp:%lu\n", j, 1838c2ecf20Sopenharmony_ci trip_type_name[ptdata.tzi[i].tp[j].type], 1848c2ecf20Sopenharmony_ci ptdata.tzi[i].tp[j].temp); 1858c2ecf20Sopenharmony_ci } 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci for (i = 0; i < ptdata.nr_cooling_dev; i++) 1898c2ecf20Sopenharmony_ci fprintf(tmon_log, "#cooling devices%02d: %s\n", 1908c2ecf20Sopenharmony_ci i, ptdata.cdi[i].type); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci fprintf(tmon_log, "#---------- THERMAL DATA LOG STARTED -----------\n"); 1938c2ecf20Sopenharmony_ci fprintf(tmon_log, "Samples TargetTemp "); 1948c2ecf20Sopenharmony_ci for (i = 0; i < ptdata.nr_tz_sensor; i++) { 1958c2ecf20Sopenharmony_ci fprintf(tmon_log, "%s%d ", ptdata.tzi[i].type, 1968c2ecf20Sopenharmony_ci ptdata.tzi[i].instance); 1978c2ecf20Sopenharmony_ci } 1988c2ecf20Sopenharmony_ci for (i = 0; i < ptdata.nr_cooling_dev; i++) 1998c2ecf20Sopenharmony_ci fprintf(tmon_log, "%s%d ", ptdata.cdi[i].type, 2008c2ecf20Sopenharmony_ci ptdata.cdi[i].instance); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci fprintf(tmon_log, "\n"); 2038c2ecf20Sopenharmony_ci} 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_cistatic struct option opts[] = { 2068c2ecf20Sopenharmony_ci { "control", 1, NULL, 'c' }, 2078c2ecf20Sopenharmony_ci { "daemon", 0, NULL, 'd' }, 2088c2ecf20Sopenharmony_ci { "time-interval", 1, NULL, 't' }, 2098c2ecf20Sopenharmony_ci { "target-temp", 1, NULL, 'T' }, 2108c2ecf20Sopenharmony_ci { "log", 0, NULL, 'l' }, 2118c2ecf20Sopenharmony_ci { "help", 0, NULL, 'h' }, 2128c2ecf20Sopenharmony_ci { "version", 0, NULL, 'v' }, 2138c2ecf20Sopenharmony_ci { "debug", 0, NULL, 'g' }, 2148c2ecf20Sopenharmony_ci { 0, 0, NULL, 0 } 2158c2ecf20Sopenharmony_ci}; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ciint main(int argc, char **argv) 2188c2ecf20Sopenharmony_ci{ 2198c2ecf20Sopenharmony_ci int err = 0; 2208c2ecf20Sopenharmony_ci int id2 = 0, c; 2218c2ecf20Sopenharmony_ci double yk = 0.0, temp; /* controller output */ 2228c2ecf20Sopenharmony_ci int target_tz_index; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci if (geteuid() != 0) { 2258c2ecf20Sopenharmony_ci printf("TMON needs to be run as root\n"); 2268c2ecf20Sopenharmony_ci exit(EXIT_FAILURE); 2278c2ecf20Sopenharmony_ci } 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci while ((c = getopt_long(argc, argv, "c:dlht:T:vgz:", opts, &id2)) != -1) { 2308c2ecf20Sopenharmony_ci switch (c) { 2318c2ecf20Sopenharmony_ci case 'c': 2328c2ecf20Sopenharmony_ci no_control = 0; 2338c2ecf20Sopenharmony_ci strncpy(ctrl_cdev, optarg, CDEV_NAME_SIZE); 2348c2ecf20Sopenharmony_ci break; 2358c2ecf20Sopenharmony_ci case 'd': 2368c2ecf20Sopenharmony_ci start_daemon_mode(); 2378c2ecf20Sopenharmony_ci printf("Run TMON in daemon mode\n"); 2388c2ecf20Sopenharmony_ci break; 2398c2ecf20Sopenharmony_ci case 't': 2408c2ecf20Sopenharmony_ci ticktime = strtod(optarg, NULL); 2418c2ecf20Sopenharmony_ci if (ticktime < 1) 2428c2ecf20Sopenharmony_ci ticktime = 1; 2438c2ecf20Sopenharmony_ci break; 2448c2ecf20Sopenharmony_ci case 'T': 2458c2ecf20Sopenharmony_ci temp = strtod(optarg, NULL); 2468c2ecf20Sopenharmony_ci if (temp < 0) { 2478c2ecf20Sopenharmony_ci fprintf(stderr, "error: temperature must be positive\n"); 2488c2ecf20Sopenharmony_ci return 1; 2498c2ecf20Sopenharmony_ci } 2508c2ecf20Sopenharmony_ci target_temp_user = temp; 2518c2ecf20Sopenharmony_ci break; 2528c2ecf20Sopenharmony_ci case 'l': 2538c2ecf20Sopenharmony_ci printf("Logging data to /var/tmp/tmon.log\n"); 2548c2ecf20Sopenharmony_ci logging = 1; 2558c2ecf20Sopenharmony_ci break; 2568c2ecf20Sopenharmony_ci case 'h': 2578c2ecf20Sopenharmony_ci usage(); 2588c2ecf20Sopenharmony_ci break; 2598c2ecf20Sopenharmony_ci case 'v': 2608c2ecf20Sopenharmony_ci version(); 2618c2ecf20Sopenharmony_ci break; 2628c2ecf20Sopenharmony_ci case 'g': 2638c2ecf20Sopenharmony_ci debug_on = 1; 2648c2ecf20Sopenharmony_ci break; 2658c2ecf20Sopenharmony_ci case 'z': 2668c2ecf20Sopenharmony_ci target_thermal_zone = strtod(optarg, NULL); 2678c2ecf20Sopenharmony_ci break; 2688c2ecf20Sopenharmony_ci default: 2698c2ecf20Sopenharmony_ci break; 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci } 2728c2ecf20Sopenharmony_ci if (pthread_mutex_init(&input_lock, NULL) != 0) { 2738c2ecf20Sopenharmony_ci fprintf(stderr, "\n mutex init failed, exit\n"); 2748c2ecf20Sopenharmony_ci return 1; 2758c2ecf20Sopenharmony_ci } 2768c2ecf20Sopenharmony_ci start_syslog(); 2778c2ecf20Sopenharmony_ci if (signal(SIGINT, tmon_sig_handler) == SIG_ERR) 2788c2ecf20Sopenharmony_ci syslog(LOG_DEBUG, "Cannot handle SIGINT\n"); 2798c2ecf20Sopenharmony_ci if (signal(SIGTERM, tmon_sig_handler) == SIG_ERR) 2808c2ecf20Sopenharmony_ci syslog(LOG_DEBUG, "Cannot handle SIGTERM\n"); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci if (probe_thermal_sysfs()) { 2838c2ecf20Sopenharmony_ci pthread_mutex_destroy(&input_lock); 2848c2ecf20Sopenharmony_ci closelog(); 2858c2ecf20Sopenharmony_ci return -1; 2868c2ecf20Sopenharmony_ci } 2878c2ecf20Sopenharmony_ci initialize_curses(); 2888c2ecf20Sopenharmony_ci setup_windows(); 2898c2ecf20Sopenharmony_ci signal(SIGWINCH, resize_handler); 2908c2ecf20Sopenharmony_ci show_title_bar(); 2918c2ecf20Sopenharmony_ci show_sensors_w(); 2928c2ecf20Sopenharmony_ci show_cooling_device(); 2938c2ecf20Sopenharmony_ci update_thermal_data(); 2948c2ecf20Sopenharmony_ci show_data_w(); 2958c2ecf20Sopenharmony_ci prepare_logging(); 2968c2ecf20Sopenharmony_ci init_thermal_controller(); 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci nodelay(stdscr, TRUE); 2998c2ecf20Sopenharmony_ci err = pthread_create(&event_tid, NULL, &handle_tui_events, NULL); 3008c2ecf20Sopenharmony_ci if (err != 0) { 3018c2ecf20Sopenharmony_ci printf("\ncan't create thread :[%s]", strerror(err)); 3028c2ecf20Sopenharmony_ci tmon_cleanup(); 3038c2ecf20Sopenharmony_ci exit(EXIT_FAILURE); 3048c2ecf20Sopenharmony_ci } 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci /* validate range of user selected target zone, default to the first 3078c2ecf20Sopenharmony_ci * instance if out of range 3088c2ecf20Sopenharmony_ci */ 3098c2ecf20Sopenharmony_ci target_tz_index = zone_instance_to_index(target_thermal_zone); 3108c2ecf20Sopenharmony_ci if (target_tz_index < 0) { 3118c2ecf20Sopenharmony_ci target_thermal_zone = ptdata.tzi[0].instance; 3128c2ecf20Sopenharmony_ci syslog(LOG_ERR, "target zone is not found, default to %d\n", 3138c2ecf20Sopenharmony_ci target_thermal_zone); 3148c2ecf20Sopenharmony_ci } 3158c2ecf20Sopenharmony_ci while (1) { 3168c2ecf20Sopenharmony_ci sleep(ticktime); 3178c2ecf20Sopenharmony_ci show_title_bar(); 3188c2ecf20Sopenharmony_ci show_sensors_w(); 3198c2ecf20Sopenharmony_ci update_thermal_data(); 3208c2ecf20Sopenharmony_ci if (!dialogue_on) { 3218c2ecf20Sopenharmony_ci show_data_w(); 3228c2ecf20Sopenharmony_ci show_cooling_device(); 3238c2ecf20Sopenharmony_ci } 3248c2ecf20Sopenharmony_ci time_elapsed += ticktime; 3258c2ecf20Sopenharmony_ci controller_handler(trec[0].temp[target_tz_index] / 1000, &yk); 3268c2ecf20Sopenharmony_ci trec[0].pid_out_pct = yk; 3278c2ecf20Sopenharmony_ci if (!dialogue_on) 3288c2ecf20Sopenharmony_ci show_control_w(); 3298c2ecf20Sopenharmony_ci if (tmon_exit) 3308c2ecf20Sopenharmony_ci break; 3318c2ecf20Sopenharmony_ci } 3328c2ecf20Sopenharmony_ci tmon_cleanup(); 3338c2ecf20Sopenharmony_ci return 0; 3348c2ecf20Sopenharmony_ci} 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_cistatic void start_daemon_mode(void) 3378c2ecf20Sopenharmony_ci{ 3388c2ecf20Sopenharmony_ci daemon_mode = 1; 3398c2ecf20Sopenharmony_ci /* fork */ 3408c2ecf20Sopenharmony_ci pid_t sid, pid = fork(); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci if (pid < 0) 3438c2ecf20Sopenharmony_ci exit(EXIT_FAILURE); 3448c2ecf20Sopenharmony_ci else if (pid > 0) 3458c2ecf20Sopenharmony_ci /* kill parent */ 3468c2ecf20Sopenharmony_ci exit(EXIT_SUCCESS); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci /* disable TUI, it may not be necessary, but saves some resource */ 3498c2ecf20Sopenharmony_ci disable_tui(); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci /* change the file mode mask */ 3528c2ecf20Sopenharmony_ci umask(S_IWGRP | S_IWOTH); 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci /* new SID for the daemon process */ 3558c2ecf20Sopenharmony_ci sid = setsid(); 3568c2ecf20Sopenharmony_ci if (sid < 0) 3578c2ecf20Sopenharmony_ci exit(EXIT_FAILURE); 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci /* change working directory */ 3608c2ecf20Sopenharmony_ci if ((chdir("/")) < 0) 3618c2ecf20Sopenharmony_ci exit(EXIT_FAILURE); 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci sleep(10); 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci close(STDIN_FILENO); 3668c2ecf20Sopenharmony_ci close(STDOUT_FILENO); 3678c2ecf20Sopenharmony_ci close(STDERR_FILENO); 3688c2ecf20Sopenharmony_ci} 369