1 /* $OpenBSD: sensors.c,v 1.43 2009/02/08 23:57:08 stevesk Exp $ */ 2 3 /* 4 * Copyright (c) 2006 Henning Brauer <henning@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/param.h> 20 #include <sys/queue.h> 21 #include <sys/sensors.h> 22 #include <sys/sysctl.h> 23 #include <sys/device.h> 24 #include <sys/hotplug.h> 25 26 #include <errno.h> 27 #include <fcntl.h> 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <string.h> 31 #include <unistd.h> 32 33 #include "ntpd.h" 34 35 #define MAXDEVNAMLEN 16 36 #define _PATH_DEV_HOTPLUG "/dev/hotplug" 37 38 int sensor_probe(int, char *, struct sensor *); 39 void sensor_add(int, char *); 40 void sensor_remove(struct ntp_sensor *); 41 void sensor_update(struct ntp_sensor *); 42 43 void 44 sensor_init(void) 45 { 46 TAILQ_INIT(&conf->ntp_sensors); 47 } 48 49 int 50 sensor_scan(void) 51 { 52 int i, n; 53 char d[MAXDEVNAMLEN]; 54 struct sensor s; 55 56 n = 0; 57 for (i = 0; i < MAXSENSORDEVICES; i++) 58 if (sensor_probe(i, d, &s)) { 59 sensor_add(i, d); 60 n++; 61 } 62 63 return n; 64 } 65 66 int 67 sensor_probe(int devid, char *dxname, struct sensor *sensor) 68 { 69 int mib[5]; 70 size_t slen, sdlen; 71 struct sensordev sensordev; 72 73 mib[0] = CTL_HW; 74 mib[1] = HW_SENSORS; 75 mib[2] = devid; 76 mib[3] = SENSOR_TIMEDELTA; 77 mib[4] = 0; 78 79 sdlen = sizeof(sensordev); 80 if (sysctl(mib, 3, &sensordev, &sdlen, NULL, 0) == -1) { 81 if (errno != ENOENT) 82 log_warn("sensor_probe sysctl"); 83 return (0); 84 } 85 86 if (sensordev.maxnumt[SENSOR_TIMEDELTA] == 0) 87 return (0); 88 89 strlcpy(dxname, sensordev.xname, MAXDEVNAMLEN); 90 91 slen = sizeof(*sensor); 92 if (sysctl(mib, 5, sensor, &slen, NULL, 0) == -1) { 93 if (errno != ENOENT) 94 log_warn("sensor_probe sysctl"); 95 return (0); 96 } 97 98 return (1); 99 } 100 101 void 102 sensor_add(int sensordev, char *dxname) 103 { 104 struct ntp_sensor *s; 105 struct ntp_conf_sensor *cs; 106 107 /* check whether it is already there */ 108 TAILQ_FOREACH(s, &conf->ntp_sensors, entry) 109 if (!strcmp(s->device, dxname)) 110 return; 111 112 /* check whether it is requested in the config file */ 113 for (cs = TAILQ_FIRST(&conf->ntp_conf_sensors); cs != NULL && 114 strcmp(cs->device, dxname) && strcmp(cs->device, "*"); 115 cs = TAILQ_NEXT(cs, entry)) 116 ; /* nothing */ 117 if (cs == NULL) 118 return; 119 120 if ((s = calloc(1, sizeof(*s))) == NULL) 121 fatal("sensor_add calloc"); 122 123 s->next = getmonotime(); 124 s->weight = cs->weight; 125 s->correction = cs->correction; 126 if ((s->device = strdup(dxname)) == NULL) 127 fatal("sensor_add strdup"); 128 s->sensordevid = sensordev; 129 130 if (cs->refstr == NULL) 131 memcpy(&s->refid, "HARD", sizeof(s->refid)); 132 else { 133 s->refid = 0; 134 strncpy((char *)&s->refid, cs->refstr, sizeof(s->refid)); 135 } 136 137 TAILQ_INSERT_TAIL(&conf->ntp_sensors, s, entry); 138 139 log_debug("sensor %s added (weight %d, correction %.6f, refstr %.4s)", 140 s->device, s->weight, s->correction / 1e6, &s->refid); 141 } 142 143 void 144 sensor_remove(struct ntp_sensor *s) 145 { 146 TAILQ_REMOVE(&conf->ntp_sensors, s, entry); 147 free(s->device); 148 free(s); 149 } 150 151 void 152 sensor_query(struct ntp_sensor *s) 153 { 154 char dxname[MAXDEVNAMLEN]; 155 struct sensor sensor; 156 157 s->next = getmonotime() + SENSOR_QUERY_INTERVAL; 158 159 /* rcvd is walltime here, monotime in client.c. not used elsewhere */ 160 if (s->update.rcvd < time(NULL) - SENSOR_DATA_MAXAGE) 161 s->update.good = 0; 162 163 if (!sensor_probe(s->sensordevid, dxname, &sensor)) { 164 sensor_remove(s); 165 return; 166 } 167 168 if (sensor.flags & SENSOR_FINVALID || 169 sensor.status != SENSOR_S_OK) 170 return; 171 172 if (strcmp(dxname, s->device)) { 173 sensor_remove(s); 174 return; 175 } 176 177 if (sensor.tv.tv_sec == s->last) /* already seen */ 178 return; 179 180 s->last = sensor.tv.tv_sec; 181 /* 182 * TD = device time 183 * TS = system time 184 * sensor.value = TS - TD in ns 185 * if value is positive, system time is ahead 186 */ 187 s->offsets[s->shift].offset = (sensor.value / -1e9) - getoffset() + 188 (s->correction / 1e6); 189 s->offsets[s->shift].rcvd = sensor.tv.tv_sec; 190 s->offsets[s->shift].good = 1; 191 192 s->offsets[s->shift].status.send_refid = s->refid; 193 s->offsets[s->shift].status.stratum = 0; /* increased when sent out */ 194 s->offsets[s->shift].status.rootdelay = 0; 195 s->offsets[s->shift].status.rootdispersion = 0; 196 s->offsets[s->shift].status.reftime = sensor.tv.tv_sec; 197 s->offsets[s->shift].status.synced = 1; 198 199 log_debug("sensor %s: offset %f", s->device, 200 s->offsets[s->shift].offset); 201 202 if (++s->shift >= SENSOR_OFFSETS) { 203 s->shift = 0; 204 sensor_update(s); 205 } 206 207 } 208 209 void 210 sensor_update(struct ntp_sensor *s) 211 { 212 struct ntp_offset **offsets; 213 int i; 214 215 if ((offsets = calloc(SENSOR_OFFSETS, sizeof(struct ntp_offset *))) == 216 NULL) 217 fatal("calloc sensor_update"); 218 219 for (i = 0; i < SENSOR_OFFSETS; i++) 220 offsets[i] = &s->offsets[i]; 221 222 qsort(offsets, SENSOR_OFFSETS, sizeof(struct ntp_offset *), 223 offset_compare); 224 225 i = SENSOR_OFFSETS / 2; 226 memcpy(&s->update, offsets[i], sizeof(s->update)); 227 if (SENSOR_OFFSETS % 2 == 0) { 228 s->update.offset = 229 (offsets[i - 1]->offset + offsets[i]->offset) / 2; 230 } 231 free(offsets); 232 233 log_debug("sensor update %s: offset %f", s->device, s->update.offset); 234 priv_adjtime(); 235 } 236 237 int 238 sensor_hotplugfd(void) 239 { 240 #ifdef notyet 241 int fd, flags; 242 243 if ((fd = open(_PATH_DEV_HOTPLUG, O_RDONLY, 0)) == -1) { 244 log_warn("open %s", _PATH_DEV_HOTPLUG); 245 return (-1); 246 } 247 248 if ((flags = fcntl(fd, F_GETFL, 0)) == -1) 249 fatal("fcntl F_GETFL"); 250 flags |= O_NONBLOCK; 251 if ((flags = fcntl(fd, F_SETFL, flags)) == -1) 252 fatal("fcntl F_SETFL"); 253 254 return (fd); 255 #else 256 return (-1); 257 #endif 258 } 259 260 void 261 sensor_hotplugevent(int fd) 262 { 263 struct hotplug_event he; 264 ssize_t n; 265 266 do { 267 if ((n = read(fd, &he, sizeof(he))) == -1 && 268 errno != EINTR && errno != EAGAIN) 269 fatal("sensor_hotplugevent read"); 270 271 if (n == sizeof(he)) 272 switch (he.he_type) { 273 case HOTPLUG_DEVAT: 274 if (he.he_devclass == DV_DULL && 275 !strcmp(he.he_devname, "sensordev")) 276 sensor_scan(); 277 break; 278 default: /* ignore */ 279 break; 280 } 281 else if (n > 0) 282 fatal("sensor_hotplugevent: short read"); 283 } while (n > 0 || (n == -1 && errno == EINTR)); 284 } 285