Index: sbin/sysctl/sysctl.c =================================================================== --- sbin/sysctl/sysctl.c +++ sbin/sysctl/sysctl.c @@ -81,7 +81,7 @@ static int sysctl_all(int *oid, int len); static int name2oid(const char *, int *); -static int strIKtoi(const char *, char **); +static int strIKtoi(const char *, char **, const char *); static int ctl_sign[CTLTYPE+1] = { [CTLTYPE_INT] = 1, @@ -336,8 +336,8 @@ switch (kind & CTLTYPE) { case CTLTYPE_INT: - if (strcmp(fmt, "IK") == 0) - intval = strIKtoi(newvalstr, &endptr); + if (strncmp(fmt, "IK", 2) == 0) + intval = strIKtoi(newvalstr, &endptr, fmt); else intval = (int)strtol(newvalstr, &endptr, 0); @@ -666,12 +666,13 @@ #endif static int -strIKtoi(const char *str, char **endptrp) +strIKtoi(const char *str, char **endptrp, const char *fmt) { int kelv; float temp; size_t len; const char *p; + int prec, i; assert(errno == 0); @@ -679,16 +680,36 @@ /* caller already checked this */ assert(len > 0); + /* + * A format of "IK" is in deciKelvin. A format of "IK3" is in + * milliKelvin. The single digit following IK is log10 of the + * multiplying factor to convert Kelvin into the untis of this sysctl, + * or the dividing factor to convert the sysctl value to Kelvin. Numbers + * larger than 6 will run into precision issues with 32-bit integers. + * Characters that aren't ASCII digits after the 'K' are ignored. No + * localization is present because this is an interface from the kernel + * to this program (eg not an end-user interface), so isdigit() isn't + * used here. + */ + if (fmt[2] != '\0' && fmt[2] >= '0' && fmt[2] <= '9') + prec = fmt[2] - '0'; + else + prec = 1; p = &str[len - 1]; - if (*p == 'C' || *p == 'F') { + if (*p == 'C' || *p == 'F' || *p == 'K') { temp = strtof(str, endptrp); if (*endptrp != str && *endptrp == p && errno == 0) { if (*p == 'F') temp = (temp - 32) * 5 / 9; *endptrp = NULL; - return (temp * 10 + 2732); + if (*p != 'K') + temp += 273.15; + for (i = 0; i < prec; i++) + temp *= 10.0; + return ((int)(temp + 0.5)); } } else { + /* No unit specified -> treat it as a raw number */ kelv = (int)strtol(str, endptrp, 10); if (*endptrp != str && *endptrp == p && errno == 0) { *endptrp = NULL; @@ -772,7 +793,9 @@ size_t intlen; size_t j, len; u_int kind; + float base; int (*func)(size_t, void *); + int prec; /* Silence GCC. */ umv = mv = intlen = 0; @@ -893,8 +916,19 @@ else if (fmt[1] == 'K') { if (mv < 0) printf("%jd", mv); - else - printf("%.1fC", (mv - 2732.0) / 10); + else { + /* + * See strIKtoi for details on fmt. + */ + prec = 1; + if (fmt[2] != '\0') + prec = fmt[2] - '0'; + base = 1.0; + for (int i = 0; i < prec; i++) + base *= 10.0; + printf("%.*fC", prec, + (float)mv / base - 273.15); + } } else printf(hflag ? "%'jd" : "%jd", mv); sep1 = " "; Index: share/man/man9/sysctl.9 =================================================================== --- share/man/man9/sysctl.9 +++ share/man/man9/sysctl.9 @@ -318,35 +318,33 @@ This format is used as a hint by .Xr sysctl 8 to apply proper data formatting for display purposes. -Currently used format names are: -.Dq N -for node, -.Dq A -for -.Li "char *" , -.Dq I -for -.Li "int" , -.Dq IU -for -.Li "unsigned int" , -.Dq L -for -.Li "long" , -.Dq LU -for -.Li "unsigned long" , -.Dq Q -for -.Li "quad_t" , -.Dq QU -for +.Pp +Current formats: +.Bl -tag -width "S,TYPE" -compact -offset indent +.It Cm N +node +.It Cm A +.Li "char *" +.It Cm I +.Li "int" +.It Cm IK Ns Op Ar n +temperature in Kelvin, multiplied by an optional single digit +power of ten scaling factor: 1 (default) gives deciKelvin, 0 gives Kelvin, 3 +gives milliKelvin +.It Cm IU +.Li "unsigned int" +.It Cm L +.Li "long" +.It Cm LU +.Li "unsigned long" +.It Cm Q +.Li "quad_t" +.It Cm QU .Li "u_quad_t" -and -.Dq S,TYPE -for +.It Cm "S,TYPE" .Li "struct TYPE" -structures. +structures +.El .It Fa descr A pointer to a textual description of the OID. .El