/* main.c - Part of sensors, a user-space program for hardware monitoring Copyright (c) 1998, 1999 Frodo Looijaard This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include #include #ifndef __UCLIBC__ #include #define HAVE_ICONV #endif #include "lib/sensors.h" #include "lib/error.h" #include "chips.h" #include "version.h" #define PROGRAM "sensors" #define VERSION LM_VERSION #define DEFAULT_CONFIG_FILE_NAME "sensors.conf" FILE *config_file; extern const char *libsensors_version; extern int main(int argc, char *arv[]); static void print_short_help(void); static void print_long_help(void); static void print_version(void); static void do_a_print(sensors_chip_name name); static int do_a_set(sensors_chip_name name); static int do_the_real_work(int *error); static const char *sprintf_chip_name(sensors_chip_name name); #define CHIPS_MAX 20 sensors_chip_name chips[CHIPS_MAX]; int chips_count=0; int do_sets, do_unknown, fahrenheit, show_algorithm, hide_adapter, hide_unknown; char degstr[5]; /* store the correct string to print degrees */ void print_short_help(void) { printf("Try `%s -h' for more information\n",PROGRAM); } void print_long_help(void) { printf("Usage: %s [OPTION]... [CHIP]...\n",PROGRAM); printf(" -c, --config-file Specify a config file (default: " ETCDIR "/" DEFAULT_CONFIG_FILE_NAME ")\n"); printf(" -h, --help Display this help text\n"); printf(" -s, --set Execute `set' statements too (root only)\n"); printf(" -f, --fahrenheit Show temperatures in degrees fahrenheit\n"); printf(" -a, --algorithm Show algorithm for each chip\n"); printf(" -A, --no-adapter Do not show adapter for each chip\n"); printf(" -U, --no-unknown Do not show unknown chips\n"); printf(" -u, --unknown Treat chips as unknown ones (testing only)\n"); printf(" -v, --version Display the program version\n"); printf("\n"); printf("Use `-' after `-c' to read the config file from stdin.\n"); printf("If no chips are specified, all chip info will be printed.\n"); printf("Example chip names:\n"); printf("\tlm78-i2c-0-2d\t*-i2c-0-2d\n"); printf("\tlm78-i2c-0-*\t*-i2c-0-*\n"); printf("\tlm78-i2c-*-2d\t*-i2c-*-2d\n"); printf("\tlm78-i2c-*-*\t*-i2c-*-*\n"); printf("\tlm78-isa-0290\t*-isa-0290\n"); printf("\tlm78-isa-*\t*-isa-*\n"); printf("\tlm78-*\n"); } void print_version(void) { printf("%s version %s with libsensors version %s\n", PROGRAM, VERSION, libsensors_version); } /* This examines global var config_file, and leaves the name there too. It also opens config_file. */ void open_config_file(const char* config_file_name) { if (!strcmp(config_file_name,"-")) { config_file = stdin; return; } config_file = fopen(config_file_name, "r"); if (!config_file) { fprintf(stderr, "Could not open config file\n"); perror(config_file_name); exit(1); } } void close_config_file(const char* config_file_name) { if (fclose(config_file) == EOF) { fprintf(stderr,"Could not close config file\n"); perror(config_file_name); } } static void set_degstr(void) { const char *deg_default_text[2] = {" C", " F"}; #ifdef HAVE_ICONV /* Size hardcoded for better performance. Don't forget to count the trailing \0! */ size_t deg_latin1_size = 3; char *deg_latin1_text[2] = {"\260C", "\260F"}; size_t nconv; size_t degstr_size = sizeof(degstr); char *degstr_ptr = degstr; iconv_t cd = iconv_open(nl_langinfo(CODESET), "ISO-8859-1"); if (cd != (iconv_t) -1) { nconv = iconv(cd, &(deg_latin1_text[fahrenheit]), °_latin1_size, °str_ptr, °str_size); iconv_close(cd); if (nconv != (size_t) -1) return; } #endif /* HAVE_ICONV */ /* There was an error during the conversion, use the default text */ strcpy(degstr, deg_default_text[fahrenheit]); } int main (int argc, char *argv[]) { int c,res,i,error; char *config_file_name = NULL; struct option long_opts[] = { { "help", no_argument, NULL, 'h' }, { "set", no_argument, NULL, 's' }, { "version", no_argument, NULL, 'v'}, { "fahrenheit", no_argument, NULL, 'f' }, { "algorithm", no_argument, NULL, 'a' }, { "no-adapter", no_argument, NULL, 'A' }, { "no-unknown", no_argument, NULL, 'U' }, { "config-file", required_argument, NULL, 'c' }, { "unknown", no_argument, NULL, 'u' }, { 0,0,0,0 } }; setlocale(LC_CTYPE, ""); do_unknown = 0; do_sets = 0; show_algorithm = 0; hide_adapter = 0; hide_unknown = 0; while (1) { c = getopt_long(argc,argv,"hsvfaAUc:u",long_opts,NULL); if (c == EOF) break; switch(c) { case ':': case '?': print_short_help(); exit(1); case 'h': print_long_help(); exit(0); case 'v': print_version(); exit(0); case 'c': config_file_name = strdup(optarg); break; case 's': do_sets = 1; break; case 'f': fahrenheit = 1; break; case 'a': show_algorithm = 1; break; case 'A': hide_adapter = 1; break; case 'U': hide_unknown = 1; break; case 'u': do_unknown = 1; break; default: fprintf(stderr,"Internal error while parsing options!\n"); exit(1); } } if (optind == argc) { chips[0].prefix = SENSORS_CHIP_NAME_PREFIX_ANY; chips[0].bus = SENSORS_CHIP_NAME_BUS_ANY; chips[0].addr = SENSORS_CHIP_NAME_ADDR_ANY; chips_count = 1; } else for(i = optind; i < argc; i++) if ((res = sensors_parse_chip_name(argv[i],chips+chips_count))) { fprintf(stderr,"Parse error in chip name `%s'\n",argv[i]); print_short_help(); exit(1); } else if (++chips_count == CHIPS_MAX) { fprintf(stderr,"Too many chips on command line!\n"); exit(1); } if (config_file_name == NULL) config_file_name = strdup(ETCDIR "/" DEFAULT_CONFIG_FILE_NAME); open_config_file(config_file_name); if ((res = sensors_init(config_file))) { fprintf(stderr,"%s\n",sensors_strerror(res)); if (res == -SENSORS_ERR_PROC) fprintf(stderr, "Kernel interface access error\n" "For 2.6 kernels, make sure you have mounted sysfs and libsensors\n" "was compiled with sysfs support!\n"); exit(1); } close_config_file(config_file_name); free(config_file_name); /* build the degrees string */ set_degstr(); if(do_the_real_work(&error)) { sensors_cleanup(); exit(error); } else { if(chips[0].prefix == SENSORS_CHIP_NAME_PREFIX_ANY) fprintf(stderr, "No sensors found!\n" "Make sure you loaded all the kernel drivers you need.\n" "Try sensors-detect to find out which these are.\n"); else fprintf(stderr,"Specified sensor(s) not found!\n"); sensors_cleanup(); exit(1); } } /* returns number of chips found */ int do_the_real_work(int *error) { const sensors_chip_name *chip; int chip_nr,i; int cnt = 0; *error = 0; for (chip_nr = 0; (chip = sensors_get_detected_chips(&chip_nr));) for(i = 0; i < chips_count; i++) if (sensors_match_chip(*chip,chips[i])) { if(do_sets) { if (do_a_set(*chip)) *error = 1; } else do_a_print(*chip); i = chips_count; cnt++; } return(cnt); } /* returns 1 on error */ int do_a_set(sensors_chip_name name) { int res; if ((res = sensors_do_chip_sets(name))) { if (res == -SENSORS_ERR_PROC) { fprintf(stderr,"%s: %s for writing;\n",sprintf_chip_name(name), sensors_strerror(res)); fprintf(stderr,"Run as root?\n"); return 1; } else if (res == -SENSORS_ERR_ACCESS_W) { fprintf(stderr, "%s: At least one \"set\" statement failed\n", sprintf_chip_name(name)); } else { fprintf(stderr,"%s: %s\n",sprintf_chip_name(name), sensors_strerror(res)); } } return 0; } const char *sprintf_chip_name(sensors_chip_name name) { #define BUF_SIZE 200 static char buf[BUF_SIZE]; if (name.bus == SENSORS_CHIP_NAME_BUS_ISA) snprintf(buf,BUF_SIZE,"%s-isa-%04x",name.prefix,name.addr); else if (name.bus == SENSORS_CHIP_NAME_BUS_PCI) snprintf(buf,BUF_SIZE,"%s-pci-%04x",name.prefix,name.addr); else if (name.bus == SENSORS_CHIP_NAME_BUS_DUMMY) snprintf(buf,BUF_SIZE,"%s-%s-%04x",name.prefix,name.busname,name.addr); else snprintf(buf,BUF_SIZE,"%s-i2c-%d-%02x",name.prefix,name.bus,name.addr); return buf; } struct match { const char * prefix; void (*fn) (const sensors_chip_name *name); }; struct match matches[] = { { "ds1621", print_ds1621 }, { "lm75", print_lm75 }, { "adm1021", print_adm1021 }, { "max1617", print_adm1021 }, { "max1617a", print_adm1021 }, { "thmc10", print_adm1021 }, { "lm84", print_adm1021 }, { "gl523", print_adm1021 }, { "adm1023", print_adm1021 }, { "mc1066", print_adm1021 }, { "adm9240", print_adm9240 }, { "ds1780", print_adm9240 }, { "lm81", print_adm9240 }, { "lm78", print_lm78 }, { "lm78-j", print_lm78 }, { "lm79", print_lm78 }, { "mtp008", print_mtp008 }, { "sis5595", print_sis5595 }, { "via686a", print_via686a }, { "lm80", print_lm80 }, { "lm85", print_lm85 }, { "lm85b", print_lm85 }, { "lm85c", print_lm85 }, { "adm1027", print_lm85 }, { "adt7463", print_lm85 }, { "emc6d100", print_lm85 }, { "emc6d102", print_lm85 }, { "lm87", print_lm87 }, { "gl518sm", print_gl518 }, { "gl520sm", print_gl520 }, { "adm1025", print_adm1025 }, { "ne1619", print_adm1025 }, { "adm1024", print_adm1024 }, { "w83781d", print_w83781d }, { "w83782d", print_w83781d }, { "w83783d", print_w83781d }, { "w83627hf", print_w83781d }, { "w83627thf", print_w83781d }, { "w83637hf", print_w83781d }, { "w83697hf", print_w83781d }, { "w83687thf", print_w83781d }, { "w83627ehf", print_w83627ehf }, { "w83791d", print_w83781d }, { "w83792d", print_w83792d }, { "w83793", print_w83793 }, { "w83l785ts", print_w83l785ts }, { "as99127f", print_w83781d }, { "maxilife", print_maxilife }, { "maxilife-cg", print_maxilife }, { "maxilife-co", print_maxilife }, { "maxilife-as", print_maxilife }, { "maxilife-nba", print_maxilife }, { "it87", print_it87 }, { "it8712", print_it87 }, { "it8716", print_it87 }, { "it8718", print_it87 }, { "ddcmon", print_ddcmon }, { "eeprom", print_eeprom }, { "fscpos", print_fscpos }, { "fscscy", print_fscscy }, { "fscher", print_fscher }, { "pcf8591", print_pcf8591 }, { "vt1211", print_vt1211 }, { "smsc47m192", print_smsc47m192 }, { "smsc47m1", print_smsc47m1 }, { "pc87360", print_pc87360 }, { "pc87363", print_pc87360 }, { "pc87364", print_pc87364 }, { "pc87365", print_pc87366 }, { "pc87366", print_pc87366 }, { "lm92", print_lm92 }, { "vt8231", print_vt8231 }, { "bmc", print_bmc }, { "adm1026", print_adm1026 }, { "lm83", print_lm83 }, { "lm90", print_lm90 }, { "adm1032", print_lm90 }, { "lm99", print_lm90 }, { "lm86", print_lm90 }, { "max6657", print_lm90 }, { "adt7461", print_lm90 }, { "lm63", print_lm63 }, { "xeontemp", print_xeontemp }, { "max6650", print_max6650 }, { "asb100", print_asb100 }, { "adm1030", print_adm1031 }, { "adm1031", print_adm1031 }, { "lm93", print_lm93 }, { "smsc47b397", print_smsc47b397 }, { "f71805f", print_f71805f }, { "abituguru", print_abituguru }, { "k8temp", print_k8temp }, { NULL, NULL } }; void do_a_print(sensors_chip_name name) { const char *algo,*adap; struct match *m; /* do we know how to display it? */ for(m = matches; m->prefix != NULL; m++) { if(!strcmp(name.prefix, m->prefix)) break; } if(m->prefix==NULL && hide_unknown) return; printf("%s\n",sprintf_chip_name(name)); adap = sensors_get_adapter_name(name.bus); if (adap && !hide_adapter) printf("Adapter: %s\n",adap); algo = sensors_get_algorithm_name(name.bus); if (algo && show_algorithm) printf("Algorithm: %s\n",algo); if (!algo || !adap) printf(" ERROR: Can't get adapter or algorithm?!?\n"); if (do_unknown) print_unknown_chip(&name); else { if(m->prefix == NULL) print_unknown_chip(&name); else m->fn(&name); } printf("\n"); }