+ if (strcasecmp(threshold_type, "percentage") == 0
+ && present_rate < low_threshold) {
+ START_COLOR("color_bad");
+ colorful_output = true;
+ } else if (strcasecmp(threshold_type, "time") == 0
+ && remaining < (u_int) low_threshold) {
+ START_COLOR("color_bad");
+ colorful_output = true;
+ }
+ }
+#elif defined(__OpenBSD__)
+ /*
+ * We're using apm(4) here, which is the interface to acpi(4) on amd64/i386 and
+ * the generic interface on macppc/sparc64/zaurus, instead of using sysctl(3) and
+ * probing acpi(4) devices.
+ */
+ struct apm_power_info apm_info;
+ int apm_fd;
+
+ apm_fd = open("/dev/apm", O_RDONLY);
+ if (apm_fd < 0) {
+ OUTPUT_FULL_TEXT("can't open /dev/apm");
+ return;
+ }
+ if (ioctl(apm_fd, APM_IOC_GETPOWER, &apm_info) < 0)
+ OUTPUT_FULL_TEXT("can't read power info");
+
+ close(apm_fd);
+
+ /* Don't bother to go further if there's no battery present. */
+ if ((apm_info.battery_state == APM_BATTERY_ABSENT) ||
+ (apm_info.battery_state == APM_BATT_UNKNOWN)) {
+ OUTPUT_FULL_TEXT(format_down);
+ return;
+ }
+
+ switch(apm_info.ac_state) {
+ case APM_AC_OFF:
+ status = CS_DISCHARGING;
+ break;
+ case APM_AC_ON:
+ status = CS_CHARGING;
+ break;
+ default:
+ /* If we don't know what's going on, just assume we're discharging. */
+ status = CS_DISCHARGING;
+ break;
+ }
+
+ (void)snprintf(statusbuf, sizeof(statusbuf), "%s", BATT_STATUS_NAME(status));
+ /* integer_battery_capacity is implied as battery_life is already in whole numbers. */
+ (void)snprintf(percentagebuf, sizeof(percentagebuf), "%.00d%%", apm_info.battery_life);
+
+ if (status == CS_DISCHARGING && low_threshold > 0) {
+ if (strcasecmp(threshold_type, "percentage") == 0
+ && apm_info.battery_life < low_threshold) {
+ START_COLOR("color_bad");
+ colorful_output = true;
+ } else if (strcasecmp(threshold_type, "time") == 0
+ && apm_info.minutes_left < (u_int) low_threshold) {
+ START_COLOR("color_bad");
+ colorful_output = true;
+ }
+ }
+
+ /* Can't give a meaningful value for remaining minutes if we're charging. */
+ if (status != CS_CHARGING) {
+ (void)snprintf(remainingbuf, sizeof(remainingbuf), "%d", apm_info.minutes_left);
+ } else {
+ (void)snprintf(remainingbuf, sizeof(remainingbuf), "%s", "(CHR)");
+ }
+
+ if (colorful_output)
+ END_COLOR;
+#elif defined(__NetBSD__)
+ /*
+ * Using envsys(4) via sysmon(4).
+ */
+ int fd, rval, last_full_cap;
+ bool is_found = false;
+ char *sensor_desc;
+ bool is_full = false;
+
+ prop_dictionary_t dict;
+ prop_array_t array;
+ prop_object_iterator_t iter;
+ prop_object_iterator_t iter2;
+ prop_object_t obj, obj2, obj3, obj4, obj5;
+
+ asprintf(&sensor_desc, "acpibat%d", number);
+
+ fd = open("/dev/sysmon", O_RDONLY);
+ if (fd < 0) {
+ OUTPUT_FULL_TEXT("can't open /dev/sysmon");
+ return;
+ }
+
+ rval = prop_dictionary_recv_ioctl(fd, ENVSYS_GETDICTIONARY, &dict);
+ if (rval == -1) {
+ close(fd);
+ return;
+ }
+
+ if (prop_dictionary_count(dict) == 0) {
+ prop_object_release(dict);
+ close(fd);
+ return;
+ }
+
+ iter = prop_dictionary_iterator(dict);
+ if (iter == NULL) {
+ prop_object_release(dict);
+ close(fd);
+ }
+
+ /* iterate over the dictionary returned by the kernel */
+ while ((obj = prop_object_iterator_next(iter)) != NULL) {
+ /* skip this dict if it's not what we're looking for */
+ if ((strlen(prop_dictionary_keysym_cstring_nocopy(obj)) == strlen(sensor_desc)) &&
+ (strncmp(sensor_desc,
+ prop_dictionary_keysym_cstring_nocopy(obj),
+ strlen(sensor_desc)) != 0))
+ continue;
+
+ is_found = true;
+
+ array = prop_dictionary_get_keysym(dict, obj);
+ if (prop_object_type(array) != PROP_TYPE_ARRAY) {
+ prop_object_iterator_release(iter);
+ prop_object_release(dict);
+ close(fd);
+ return;
+ }
+
+ iter2 = prop_array_iterator(array);
+ if (!iter2) {
+ prop_object_iterator_release(iter);
+ prop_object_release(dict);
+ close(fd);
+ return;
+ }
+
+ /* iterate over array of dicts specific to target battery */
+ while ((obj2 = prop_object_iterator_next(iter2)) != NULL) {
+ obj3 = prop_dictionary_get(obj2, "description");
+
+ if (obj3 &&
+ strlen(prop_string_cstring_nocopy(obj3)) == 8 &&
+ strncmp("charging",
+ prop_string_cstring_nocopy(obj3),
+ 8) == 0)
+ {
+ obj3 = prop_dictionary_get(obj2, "cur-value");
+
+ if (prop_number_integer_value(obj3))
+ status = CS_CHARGING;
+ else
+ status = CS_DISCHARGING;
+
+ continue;
+ }
+
+ if (obj3 &&
+ strlen(prop_string_cstring_nocopy(obj3)) == 6 &&
+ strncmp("charge",
+ prop_string_cstring_nocopy(obj3),
+ 6) == 0)
+ {
+ obj3 = prop_dictionary_get(obj2, "cur-value");
+ obj4 = prop_dictionary_get(obj2, "max-value");
+ obj5 = prop_dictionary_get(obj2, "type");
+
+ remaining = prop_number_integer_value(obj3);
+ full_design = prop_number_integer_value(obj4);
+
+ if (remaining == full_design)
+ is_full = true;
+
+ if (strncmp("Ampere hour",
+ prop_string_cstring_nocopy(obj5),
+ 11) == 0)
+ watt_as_unit = false;
+ else
+ watt_as_unit = true;
+
+ continue;
+ }
+
+ if (obj3 &&
+ strlen(prop_string_cstring_nocopy(obj3)) == 14 &&
+ strncmp("discharge rate",
+ prop_string_cstring_nocopy(obj3),
+ 14) == 0)
+ {
+ obj3 = prop_dictionary_get(obj2, "cur-value");
+ present_rate = prop_number_integer_value(obj3);
+ continue;
+ }
+
+ if (obj3 &&
+ strlen(prop_string_cstring_nocopy(obj3)) == 13 &&
+ strncmp("last full cap",
+ prop_string_cstring_nocopy(obj3),
+ 13) == 0)
+ {
+ obj3 = prop_dictionary_get(obj2, "cur-value");
+ last_full_cap = prop_number_integer_value(obj3);
+ continue;
+ }
+
+ if (obj3 &&
+ strlen(prop_string_cstring_nocopy(obj3)) == 7 &&
+ strncmp("voltage",
+ prop_string_cstring_nocopy(obj3),
+ 7) == 0)
+ {
+ obj3 = prop_dictionary_get(obj2, "cur-value");
+ voltage = prop_number_integer_value(obj3);
+ continue;
+ }
+ }
+ prop_object_iterator_release(iter2);
+ }
+
+ prop_object_iterator_release(iter);
+ prop_object_release(dict);
+ close(fd);
+
+ if (! is_found) {
+ OUTPUT_FULL_TEXT(format_down);
+ return;
+ }
+
+ if (last_full_capacity)
+ full_design = last_full_cap;
+
+ if (! watt_as_unit) {
+ present_rate = (((float)voltage / 1000.0) * ((float)present_rate / 1000.0));
+ remaining = (((float)voltage / 1000.0) * ((float)remaining / 1000.0));
+ full_design = (((float)voltage / 1000.0) * ((float)full_design / 1000.0));