0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <getopt.h>
0011 #include <unistd.h>
0012 #include <stdio.h>
0013 #include <stdlib.h>
0014 #include <string.h>
0015 #include <sys/types.h>
0016 #include <sys/stat.h>
0017 #include <ncurses.h>
0018 #include <ctype.h>
0019 #include <time.h>
0020 #include <signal.h>
0021 #include <limits.h>
0022 #include <sys/time.h>
0023 #include <pthread.h>
0024 #include <math.h>
0025 #include <stdarg.h>
0026 #include <syslog.h>
0027
0028 #include "tmon.h"
0029
0030 unsigned long ticktime = 1;
0031 unsigned long no_control = 1;
0032
0033
0034 double time_elapsed = 0.0;
0035 unsigned long target_temp_user = 65;
0036 int dialogue_on;
0037 int tmon_exit;
0038 static short daemon_mode;
0039 static int logging;
0040 static int debug_on;
0041 FILE *tmon_log;
0042
0043 char ctrl_cdev[CDEV_NAME_SIZE] = "None";
0044 int target_thermal_zone;
0045 static void start_daemon_mode(void);
0046
0047 pthread_t event_tid;
0048 pthread_mutex_t input_lock;
0049 void usage(void)
0050 {
0051 printf("Usage: tmon [OPTION...]\n");
0052 printf(" -c, --control cooling device in control\n");
0053 printf(" -d, --daemon run as daemon, no TUI\n");
0054 printf(" -g, --debug debug message in syslog\n");
0055 printf(" -h, --help show this help message\n");
0056 printf(" -l, --log log data to /var/tmp/tmon.log\n");
0057 printf(" -t, --time-interval sampling time interval, > 1 sec.\n");
0058 printf(" -T, --target-temp initial target temperature\n");
0059 printf(" -v, --version show version\n");
0060 printf(" -z, --zone target thermal zone id\n");
0061
0062 exit(0);
0063 }
0064
0065 void version(void)
0066 {
0067 printf("TMON version %s\n", VERSION);
0068 exit(EXIT_SUCCESS);
0069 }
0070
0071 static void tmon_cleanup(void)
0072 {
0073 syslog(LOG_INFO, "TMON exit cleanup\n");
0074 fflush(stdout);
0075 refresh();
0076 if (tmon_log)
0077 fclose(tmon_log);
0078 if (event_tid) {
0079 pthread_mutex_lock(&input_lock);
0080 pthread_cancel(event_tid);
0081 pthread_mutex_unlock(&input_lock);
0082 pthread_mutex_destroy(&input_lock);
0083 }
0084 closelog();
0085
0086 set_ctrl_state(0);
0087
0088 keypad(stdscr, FALSE);
0089 echo();
0090 nocbreak();
0091 close_windows();
0092 endwin();
0093 free_thermal_data();
0094
0095 exit(1);
0096 }
0097
0098 static void tmon_sig_handler(int sig)
0099 {
0100 syslog(LOG_INFO, "TMON caught signal %d\n", sig);
0101 refresh();
0102 switch (sig) {
0103 case SIGTERM:
0104 printf("sigterm, exit and clean up\n");
0105 fflush(stdout);
0106 break;
0107 case SIGKILL:
0108 printf("sigkill, exit and clean up\n");
0109 fflush(stdout);
0110 break;
0111 case SIGINT:
0112 printf("ctrl-c, exit and clean up\n");
0113 fflush(stdout);
0114 break;
0115 default:
0116 break;
0117 }
0118 tmon_exit = true;
0119 }
0120
0121 static void start_syslog(void)
0122 {
0123 if (debug_on)
0124 setlogmask(LOG_UPTO(LOG_DEBUG));
0125 else
0126 setlogmask(LOG_UPTO(LOG_ERR));
0127 openlog("tmon.log", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL0);
0128 syslog(LOG_NOTICE, "TMON started by User %d", getuid());
0129 }
0130
0131 static void prepare_logging(void)
0132 {
0133 int i;
0134 struct stat logstat;
0135
0136 if (!logging)
0137 return;
0138
0139 tmon_log = fopen(TMON_LOG_FILE, "w+");
0140 if (!tmon_log) {
0141 syslog(LOG_ERR, "failed to open log file %s\n", TMON_LOG_FILE);
0142 return;
0143 }
0144
0145 if (lstat(TMON_LOG_FILE, &logstat) < 0) {
0146 syslog(LOG_ERR, "Unable to stat log file %s\n", TMON_LOG_FILE);
0147 fclose(tmon_log);
0148 tmon_log = NULL;
0149 return;
0150 }
0151
0152
0153 if (S_ISLNK(logstat.st_mode)) {
0154 syslog(LOG_ERR, "Log file is a symlink. Will not log\n");
0155 fclose(tmon_log);
0156 tmon_log = NULL;
0157 return;
0158 }
0159
0160 if (logstat.st_uid != getuid()) {
0161 syslog(LOG_ERR, "We don't own the log file. Not logging\n");
0162 fclose(tmon_log);
0163 tmon_log = NULL;
0164 return;
0165 }
0166
0167 fprintf(tmon_log, "#----------- THERMAL SYSTEM CONFIG -------------\n");
0168 for (i = 0; i < ptdata.nr_tz_sensor; i++) {
0169 char binding_str[33];
0170 int j;
0171
0172 memset(binding_str, 0, sizeof(binding_str));
0173 for (j = 0; j < 32; j++)
0174 binding_str[j] = (ptdata.tzi[i].cdev_binding & (1 << j)) ?
0175 '1' : '0';
0176
0177 fprintf(tmon_log, "#thermal zone %s%02d cdevs binding: %32s\n",
0178 ptdata.tzi[i].type,
0179 ptdata.tzi[i].instance,
0180 binding_str);
0181 for (j = 0; j < ptdata.tzi[i].nr_trip_pts; j++) {
0182 fprintf(tmon_log, "#\tTP%02d type:%s, temp:%lu\n", j,
0183 trip_type_name[ptdata.tzi[i].tp[j].type],
0184 ptdata.tzi[i].tp[j].temp);
0185 }
0186 }
0187
0188 for (i = 0; i < ptdata.nr_cooling_dev; i++)
0189 fprintf(tmon_log, "#cooling devices%02d: %s\n",
0190 i, ptdata.cdi[i].type);
0191
0192 fprintf(tmon_log, "#---------- THERMAL DATA LOG STARTED -----------\n");
0193 fprintf(tmon_log, "Samples TargetTemp ");
0194 for (i = 0; i < ptdata.nr_tz_sensor; i++) {
0195 fprintf(tmon_log, "%s%d ", ptdata.tzi[i].type,
0196 ptdata.tzi[i].instance);
0197 }
0198 for (i = 0; i < ptdata.nr_cooling_dev; i++)
0199 fprintf(tmon_log, "%s%d ", ptdata.cdi[i].type,
0200 ptdata.cdi[i].instance);
0201
0202 fprintf(tmon_log, "\n");
0203 }
0204
0205 static struct option opts[] = {
0206 { "control", 1, NULL, 'c' },
0207 { "daemon", 0, NULL, 'd' },
0208 { "time-interval", 1, NULL, 't' },
0209 { "target-temp", 1, NULL, 'T' },
0210 { "log", 0, NULL, 'l' },
0211 { "help", 0, NULL, 'h' },
0212 { "version", 0, NULL, 'v' },
0213 { "debug", 0, NULL, 'g' },
0214 { 0, 0, NULL, 0 }
0215 };
0216
0217 int main(int argc, char **argv)
0218 {
0219 int err = 0;
0220 int id2 = 0, c;
0221 double yk = 0.0, temp;
0222 int target_tz_index;
0223
0224 if (geteuid() != 0) {
0225 printf("TMON needs to be run as root\n");
0226 exit(EXIT_FAILURE);
0227 }
0228
0229 while ((c = getopt_long(argc, argv, "c:dlht:T:vgz:", opts, &id2)) != -1) {
0230 switch (c) {
0231 case 'c':
0232 no_control = 0;
0233 strncpy(ctrl_cdev, optarg, CDEV_NAME_SIZE);
0234 break;
0235 case 'd':
0236 start_daemon_mode();
0237 printf("Run TMON in daemon mode\n");
0238 break;
0239 case 't':
0240 ticktime = strtod(optarg, NULL);
0241 if (ticktime < 1)
0242 ticktime = 1;
0243 break;
0244 case 'T':
0245 temp = strtod(optarg, NULL);
0246 if (temp < 0) {
0247 fprintf(stderr, "error: temperature must be positive\n");
0248 return 1;
0249 }
0250 target_temp_user = temp;
0251 break;
0252 case 'l':
0253 printf("Logging data to /var/tmp/tmon.log\n");
0254 logging = 1;
0255 break;
0256 case 'h':
0257 usage();
0258 break;
0259 case 'v':
0260 version();
0261 break;
0262 case 'g':
0263 debug_on = 1;
0264 break;
0265 case 'z':
0266 target_thermal_zone = strtod(optarg, NULL);
0267 break;
0268 default:
0269 break;
0270 }
0271 }
0272 if (pthread_mutex_init(&input_lock, NULL) != 0) {
0273 fprintf(stderr, "\n mutex init failed, exit\n");
0274 return 1;
0275 }
0276 start_syslog();
0277 if (signal(SIGINT, tmon_sig_handler) == SIG_ERR)
0278 syslog(LOG_DEBUG, "Cannot handle SIGINT\n");
0279 if (signal(SIGTERM, tmon_sig_handler) == SIG_ERR)
0280 syslog(LOG_DEBUG, "Cannot handle SIGTERM\n");
0281
0282 if (probe_thermal_sysfs()) {
0283 pthread_mutex_destroy(&input_lock);
0284 closelog();
0285 return -1;
0286 }
0287 initialize_curses();
0288 setup_windows();
0289 signal(SIGWINCH, resize_handler);
0290 show_title_bar();
0291 show_sensors_w();
0292 show_cooling_device();
0293 update_thermal_data();
0294 show_data_w();
0295 prepare_logging();
0296 init_thermal_controller();
0297
0298 nodelay(stdscr, TRUE);
0299 err = pthread_create(&event_tid, NULL, &handle_tui_events, NULL);
0300 if (err != 0) {
0301 printf("\ncan't create thread :[%s]", strerror(err));
0302 tmon_cleanup();
0303 exit(EXIT_FAILURE);
0304 }
0305
0306
0307
0308
0309 target_tz_index = zone_instance_to_index(target_thermal_zone);
0310 if (target_tz_index < 0) {
0311 target_thermal_zone = ptdata.tzi[0].instance;
0312 syslog(LOG_ERR, "target zone is not found, default to %d\n",
0313 target_thermal_zone);
0314 }
0315 while (1) {
0316 sleep(ticktime);
0317 show_title_bar();
0318 show_sensors_w();
0319 update_thermal_data();
0320 if (!dialogue_on) {
0321 show_data_w();
0322 show_cooling_device();
0323 }
0324 time_elapsed += ticktime;
0325 controller_handler(trec[0].temp[target_tz_index] / 1000, &yk);
0326 trec[0].pid_out_pct = yk;
0327 if (!dialogue_on)
0328 show_control_w();
0329 if (tmon_exit)
0330 break;
0331 }
0332 tmon_cleanup();
0333 return 0;
0334 }
0335
0336 static void start_daemon_mode(void)
0337 {
0338 daemon_mode = 1;
0339
0340 pid_t sid, pid = fork();
0341
0342 if (pid < 0)
0343 exit(EXIT_FAILURE);
0344 else if (pid > 0)
0345
0346 exit(EXIT_SUCCESS);
0347
0348
0349 disable_tui();
0350
0351
0352 umask(S_IWGRP | S_IWOTH);
0353
0354
0355 sid = setsid();
0356 if (sid < 0)
0357 exit(EXIT_FAILURE);
0358
0359
0360 if ((chdir("/")) < 0)
0361 exit(EXIT_FAILURE);
0362
0363 sleep(10);
0364
0365 close(STDIN_FILENO);
0366 close(STDOUT_FILENO);
0367 close(STDERR_FILENO);
0368 }