int npfctl_remove_rule(u_long cmd, void *data) { struct plistref *pref = data; prop_dictionary_t dict, errdict; prop_object_t obj; const char *name; int error, numrules; /* Retrieve and construct the rule. */ error = prop_dictionary_copyin_ioctl(pref, cmd, &dict); if (error) { return error; } /* Dictionary for error reporting. */ errdict = prop_dictionary_create(); obj = prop_dictionary_get(dict, "name"); name = prop_string_cstring_nocopy(obj); npf_rule_t *rl; error = npf_mk_singlerule(dict, prop_array_create(), &rl, errdict); npf_core_enter(); numrules = npf_named_ruleset_remove(name, npf_core_ruleset(), rl); npf_core_exit(); prop_object_release(dict); /* Error report. */ prop_dictionary_set_int32(errdict, "errno", error); prop_dictionary_set_int32(errdict, "numrules", numrules); prop_dictionary_copyout_ioctl(pref, cmd, errdict); prop_object_release(errdict); return error; }
static void dispatch_power_event_state_change(int fd, power_event_t *pev) { prop_dictionary_t dict; prop_object_t obj; const char *argv[6]; char *buf = NULL; int error; error = prop_dictionary_recv_ioctl(fd, POWER_EVENT_RECVDICT, &dict); if (error) { if (debug) printf("%s: prop_dictionary_recv_ioctl error=%d\n", __func__, error); return; } if (debug) { buf = prop_dictionary_externalize(dict); printf("%s", buf); free(buf); } obj = prop_dictionary_get(dict, "powerd-script-name"); argv[0] = prop_string_cstring_nocopy(obj); obj = prop_dictionary_get(dict, "driver-name"); argv[1] = prop_string_cstring_nocopy(obj); obj = prop_dictionary_get(dict, "powerd-event-name"); argv[2] = prop_string_cstring_nocopy(obj); obj = prop_dictionary_get(dict, "sensor-name"); argv[3] = prop_string_cstring_nocopy(obj); obj = prop_dictionary_get(dict, "state-description"); argv[4] = prop_string_cstring_nocopy(obj); argv[5] = NULL; run_script(argv); }
/* * npfctl_update_rule: reload a specific rule identified by the name. */ int npfctl_update_rule(u_long cmd, void *data) { struct plistref *pref = data; prop_dictionary_t dict, errdict; prop_array_t subrules; prop_object_t obj; npf_ruleset_t *rlset; const char *name; int error; /* Retrieve and construct the rule. */ error = prop_dictionary_copyin_ioctl(pref, cmd, &dict); if (error) { return error; } /* Dictionary for error reporting. */ errdict = prop_dictionary_create(); /* Create the ruleset and construct sub-rules. */ rlset = npf_ruleset_create(); subrules = prop_dictionary_get(dict, "subrules"); error = npf_mk_subrules(rlset, subrules, NULL, errdict); if (error) { goto out; } /* Lookup the rule by name, and replace its subset (sub-rules). */ obj = prop_dictionary_get(dict, "name"); name = prop_string_cstring_nocopy(obj); if (npf_ruleset_replace(name, rlset) == NULL) { /* Not found. */ error = ENOENT; out: /* Error path. */ npf_ruleset_destroy(rlset); } prop_object_release(dict); /* Error report. */ prop_dictionary_set_int32(errdict, "errno", error); prop_dictionary_copyout_ioctl(pref, cmd, errdict); prop_object_release(errdict); return error; }
/* ARGSUSED */ int setcarpdev(prop_dictionary_t env, prop_dictionary_t oenv) { struct carpreq carpr; prop_string_t s; s = (prop_string_t)prop_dictionary_get(env, "carpdev"); if (s == NULL) { errno = ENOENT; return -1; } carp_get(env, &carpr); strlcpy(carpr.carpr_carpdev, prop_string_cstring_nocopy(s), sizeof(carpr.carpr_carpdev)); carp_set(env, &carpr); return 0; }
static int bthub_print(void *aux, const char *pnp) { prop_dictionary_t dict = aux; prop_object_t obj; const bdaddr_t *raddr; if (pnp != NULL) { obj = prop_dictionary_get(dict, BTDEVtype); aprint_normal("%s: %s '%s',", pnp, BTDEVtype, prop_string_cstring_nocopy(obj)); } obj = prop_dictionary_get(dict, BTDEVraddr); raddr = prop_data_data_nocopy(obj); aprint_verbose(" %s %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x", BTDEVraddr, raddr->b[5], raddr->b[4], raddr->b[3], raddr->b[2], raddr->b[1], raddr->b[0]); return UNCONF; }
static void bthidev_attach(device_t parent, device_t self, void *aux) { struct bthidev_softc *sc = device_private(self); prop_dictionary_t dict = aux; prop_object_t obj; device_t dev; struct bthidev_attach_args bha; struct bthidev *hidev; struct hid_data *d; struct hid_item h; const void *desc; int locs[BTHIDBUSCF_NLOCS]; int maxid, rep, dlen; /* * Init softc */ sc->sc_dev = self; LIST_INIT(&sc->sc_list); callout_init(&sc->sc_reconnect, 0); callout_setfunc(&sc->sc_reconnect, bthidev_timeout, sc); sc->sc_state = BTHID_CLOSED; sc->sc_flags = BTHID_CONNECTING; sc->sc_ctlpsm = L2CAP_PSM_HID_CNTL; sc->sc_intpsm = L2CAP_PSM_HID_INTR; sockopt_init(&sc->sc_mode, BTPROTO_L2CAP, SO_L2CAP_LM, 0); /* * extract config from proplist */ obj = prop_dictionary_get(dict, BTDEVladdr); bdaddr_copy(&sc->sc_laddr, prop_data_data_nocopy(obj)); obj = prop_dictionary_get(dict, BTDEVraddr); bdaddr_copy(&sc->sc_raddr, prop_data_data_nocopy(obj)); obj = prop_dictionary_get(dict, BTDEVmode); if (prop_object_type(obj) == PROP_TYPE_STRING) { if (prop_string_equals_cstring(obj, BTDEVauth)) sockopt_setint(&sc->sc_mode, L2CAP_LM_AUTH); else if (prop_string_equals_cstring(obj, BTDEVencrypt)) sockopt_setint(&sc->sc_mode, L2CAP_LM_ENCRYPT); else if (prop_string_equals_cstring(obj, BTDEVsecure)) sockopt_setint(&sc->sc_mode, L2CAP_LM_SECURE); else { aprint_error(" unknown %s\n", BTDEVmode); return; } aprint_verbose(" %s %s", BTDEVmode, prop_string_cstring_nocopy(obj)); } obj = prop_dictionary_get(dict, BTHIDEVcontrolpsm); if (prop_object_type(obj) == PROP_TYPE_NUMBER) { sc->sc_ctlpsm = prop_number_integer_value(obj); if (L2CAP_PSM_INVALID(sc->sc_ctlpsm)) { aprint_error(" invalid %s\n", BTHIDEVcontrolpsm); return; } } obj = prop_dictionary_get(dict, BTHIDEVinterruptpsm); if (prop_object_type(obj) == PROP_TYPE_NUMBER) { sc->sc_intpsm = prop_number_integer_value(obj); if (L2CAP_PSM_INVALID(sc->sc_intpsm)) { aprint_error(" invalid %s\n", BTHIDEVinterruptpsm); return; } } obj = prop_dictionary_get(dict, BTHIDEVdescriptor); if (prop_object_type(obj) == PROP_TYPE_DATA) { dlen = prop_data_size(obj); desc = prop_data_data_nocopy(obj); } else { aprint_error(" no %s\n", BTHIDEVdescriptor); return; } obj = prop_dictionary_get(dict, BTHIDEVreconnect); if (prop_object_type(obj) == PROP_TYPE_BOOL && !prop_bool_true(obj)) sc->sc_flags |= BTHID_RECONNECT; /* * Parse the descriptor and attach child devices, one per report. */ maxid = -1; h.report_ID = 0; d = hid_start_parse(desc, dlen, hid_none); while (hid_get_item(d, &h)) { if (h.report_ID > maxid) maxid = h.report_ID; } hid_end_parse(d); if (maxid < 0) { aprint_error(" no reports found\n"); return; } aprint_normal("\n"); for (rep = 0 ; rep <= maxid ; rep++) { if (hid_report_size(desc, dlen, hid_feature, rep) == 0 && hid_report_size(desc, dlen, hid_input, rep) == 0 && hid_report_size(desc, dlen, hid_output, rep) == 0) continue; bha.ba_desc = desc; bha.ba_dlen = dlen; bha.ba_input = bthidev_null; bha.ba_feature = bthidev_null; bha.ba_output = bthidev_output; bha.ba_id = rep; locs[BTHIDBUSCF_REPORTID] = rep; dev = config_found_sm_loc(self, "bthidbus", locs, &bha, bthidev_print, config_stdsubmatch); if (dev != NULL) { hidev = device_private(dev); hidev->sc_dev = dev; hidev->sc_parent = self; hidev->sc_id = rep; hidev->sc_input = bha.ba_input; hidev->sc_feature = bha.ba_feature; LIST_INSERT_HEAD(&sc->sc_list, hidev, sc_next); } } /* * start bluetooth connections */ mutex_enter(bt_lock); if ((sc->sc_flags & BTHID_RECONNECT) == 0) bthidev_listen(sc); if (sc->sc_flags & BTHID_CONNECTING) bthidev_connect(sc); mutex_exit(bt_lock); }
static int swsensor_init(void *arg) { int error, val = 0; const char *key, *str; prop_dictionary_t pd = (prop_dictionary_t)arg; prop_object_t po, obj; prop_object_iterator_t iter; prop_type_t type; const struct sme_descr_entry *descr; swsensor_sme = sysmon_envsys_create(); if (swsensor_sme == NULL) return ENOTTY; swsensor_sme->sme_name = "swsensor"; swsensor_sme->sme_cookie = &swsensor_edata; swsensor_sme->sme_refresh = swsensor_refresh; swsensor_sme->sme_set_limits = NULL; swsensor_sme->sme_get_limits = NULL; /* Set defaults in case no prop dictionary given */ swsensor_edata.units = ENVSYS_INTEGER; swsensor_edata.flags = 0; sw_sensor_mode = 0; sw_sensor_value = 0; sw_sensor_limit = 0; /* Iterate over the provided dictionary, if any */ if (pd != NULL) { iter = prop_dictionary_iterator(pd); if (iter == NULL) return ENOMEM; while ((obj = prop_object_iterator_next(iter)) != NULL) { key = prop_dictionary_keysym_cstring_nocopy(obj); po = prop_dictionary_get_keysym(pd, obj); type = prop_object_type(po); if (type == PROP_TYPE_NUMBER) val = prop_number_integer_value(po); /* Sensor type/units */ if (strcmp(key, "type") == 0) { if (type == PROP_TYPE_NUMBER) { descr = sme_find_table_entry( SME_DESC_UNITS, val); if (descr == NULL) return EINVAL; swsensor_edata.units = descr->type; continue; } if (type != PROP_TYPE_STRING) return EINVAL; str = prop_string_cstring_nocopy(po); descr = sme_find_table_desc(SME_DESC_UNITS, str); if (descr == NULL) return EINVAL; swsensor_edata.units = descr->type; continue; } /* Sensor flags */ if (strcmp(key, "flags") == 0) { if (type != PROP_TYPE_NUMBER) return EINVAL; swsensor_edata.flags = val; continue; } /* Sensor limit behavior * 0 - simple sensor, no hw limits * 1 - simple sensor, hw provides initial limit * 2 - complex sensor, hw provides settable * limits and does its own limit checking */ if (strcmp(key, "mode") == 0) { if (type != PROP_TYPE_NUMBER) return EINVAL; sw_sensor_mode = val; if (sw_sensor_mode > 2) sw_sensor_mode = 2; else if (sw_sensor_mode < 0) sw_sensor_mode = 0; continue; } /* Grab any limit that might be specified */ if (strcmp(key, "limit") == 0) { if (type != PROP_TYPE_NUMBER) return EINVAL; sw_sensor_limit = val; continue; } /* Grab the initial value */ if (strcmp(key, "value") == 0) { if (type != PROP_TYPE_NUMBER) return EINVAL; sw_sensor_value = val; continue; } /* Grab value_min and value_max */ if (strcmp(key, "value_min") == 0) { if (type != PROP_TYPE_NUMBER) return EINVAL; swsensor_edata.value_min = val; swsensor_edata.flags |= ENVSYS_FVALID_MIN; continue; } if (strcmp(key, "value_max") == 0) { if (type != PROP_TYPE_NUMBER) return EINVAL; swsensor_edata.value_max = val; swsensor_edata.flags |= ENVSYS_FVALID_MAX; continue; } /* See if sensor reports percentages vs raw values */ if (strcmp(key, "percentage") == 0) { if (type != PROP_TYPE_BOOL) return EINVAL; if (prop_bool_true(po)) swsensor_edata.flags |= ENVSYS_FPERCENT; continue; } /* Unrecognized dicttionary object */ #ifdef DEBUG printf("%s: unknown attribute %s\n", __func__, key); #endif return EINVAL; } /* while */ prop_object_iterator_release(iter); } /* Initialize limit processing */ if (sw_sensor_mode >= 1) swsensor_sme->sme_get_limits = swsensor_get_limits; if (sw_sensor_mode == 2) swsensor_sme->sme_set_limits = swsensor_set_limits; if (sw_sensor_mode != 0) { swsensor_edata.flags |= ENVSYS_FMONLIMITS; swsensor_get_limits(swsensor_sme, &swsensor_edata, &sw_sensor_deflims, &sw_sensor_defprops); } strlcpy(swsensor_edata.desc, "sensor", ENVSYS_DESCLEN); /* Wait for refresh to validate the sensor value */ swsensor_edata.state = ENVSYS_SINVALID; sw_sensor_state = ENVSYS_SVALID; error = sysmon_envsys_sensor_attach(swsensor_sme, &swsensor_edata); if (error != 0) { aprint_error("sysmon_envsys_sensor_attach failed: %d\n", error); return error; } error = sysmon_envsys_register(swsensor_sme); if (error != 0) { aprint_error("sysmon_envsys_register failed: %d\n", error); return error; } sysctl_swsensor_setup(); aprint_normal("swsensor: initialized\n"); return 0; }
static bool slurp_battery_info(struct battery_info *batt_info, yajl_gen json_gen, char *buffer, int number, const char *path, const char *format_down) { char *outwalk = buffer; #if defined(LINUX) char buf[1024]; memset(buf, 0, 1024); const char *walk, *last; bool watt_as_unit = false; int voltage = -1; char batpath[512]; sprintf(batpath, path, number); INSTANCE(batpath); if (!slurp(batpath, buf, sizeof(buf))) { OUTPUT_FULL_TEXT(format_down); return false; } for (walk = buf, last = buf; (walk - buf) < 1024; walk++) { if (*walk == '\n') { last = walk + 1; continue; } if (*walk != '=') continue; if (BEGINS_WITH(last, "POWER_SUPPLY_ENERGY_NOW=")) { watt_as_unit = true; batt_info->remaining = atoi(walk + 1); batt_info->percentage_remaining = -1; } else if (BEGINS_WITH(last, "POWER_SUPPLY_CHARGE_NOW=")) { watt_as_unit = false; batt_info->remaining = atoi(walk + 1); batt_info->percentage_remaining = -1; } else if (BEGINS_WITH(last, "POWER_SUPPLY_CAPACITY=") && batt_info->remaining == -1) { batt_info->percentage_remaining = atoi(walk + 1); } else if (BEGINS_WITH(last, "POWER_SUPPLY_CURRENT_NOW=")) batt_info->present_rate = abs(atoi(walk + 1)); else if (BEGINS_WITH(last, "POWER_SUPPLY_VOLTAGE_NOW=")) voltage = abs(atoi(walk + 1)); /* on some systems POWER_SUPPLY_POWER_NOW does not exist, but actually * it is the same as POWER_SUPPLY_CURRENT_NOW but with μWh as * unit instead of μAh. We will calculate it as we need it * later. */ else if (BEGINS_WITH(last, "POWER_SUPPLY_POWER_NOW=")) batt_info->present_rate = abs(atoi(walk + 1)); else if (BEGINS_WITH(last, "POWER_SUPPLY_STATUS=Charging")) batt_info->status = CS_CHARGING; else if (BEGINS_WITH(last, "POWER_SUPPLY_STATUS=Full")) batt_info->status = CS_FULL; else if (BEGINS_WITH(last, "POWER_SUPPLY_STATUS=Discharging")) batt_info->status = CS_DISCHARGING; else if (BEGINS_WITH(last, "POWER_SUPPLY_STATUS=")) batt_info->status = CS_UNKNOWN; else if (BEGINS_WITH(last, "POWER_SUPPLY_CHARGE_FULL_DESIGN=") || BEGINS_WITH(last, "POWER_SUPPLY_ENERGY_FULL_DESIGN=")) batt_info->full_design = atoi(walk + 1); else if (BEGINS_WITH(last, "POWER_SUPPLY_ENERGY_FULL=") || BEGINS_WITH(last, "POWER_SUPPLY_CHARGE_FULL=")) batt_info->full_last = atoi(walk + 1); } /* the difference between POWER_SUPPLY_ENERGY_NOW and * POWER_SUPPLY_CHARGE_NOW is the unit of measurement. The energy is * given in mWh, the charge in mAh. So calculate every value given in * ampere to watt */ if (!watt_as_unit && voltage >= 0) { if (batt_info->present_rate > 0) { batt_info->present_rate = (((float)voltage / 1000.0) * ((float)batt_info->present_rate / 1000.0)); } if (batt_info->remaining > 0) { batt_info->remaining = (((float)voltage / 1000.0) * ((float)batt_info->remaining / 1000.0)); } if (batt_info->full_design > 0) { batt_info->full_design = (((float)voltage / 1000.0) * ((float)batt_info->full_design / 1000.0)); } if (batt_info->full_last > 0) { batt_info->full_last = (((float)voltage / 1000.0) * ((float)batt_info->full_last / 1000.0)); } } #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) int state; int sysctl_rslt; size_t sysctl_size = sizeof(sysctl_rslt); if (sysctlbyname(BATT_LIFE, &sysctl_rslt, &sysctl_size, NULL, 0) != 0) { OUTPUT_FULL_TEXT(format_down); return false; } batt_info->percentage_remaining = sysctl_rslt; if (sysctlbyname(BATT_TIME, &sysctl_rslt, &sysctl_size, NULL, 0) != 0) { OUTPUT_FULL_TEXT(format_down); return false; } batt_info->seconds_remaining = sysctl_rslt * 60; if (sysctlbyname(BATT_STATE, &sysctl_rslt, &sysctl_size, NULL, 0) != 0) { OUTPUT_FULL_TEXT(format_down); return false; } state = sysctl_rslt; if (state == 0 && batt_info->percentage_remaining == 100) batt_info->status = CS_FULL; else if ((state & ACPI_BATT_STAT_CHARGING) && batt_info->percentage_remaining < 100) batt_info->status = CS_CHARGING; else batt_info->status = CS_DISCHARGING; #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 false; } 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 false; } switch (apm_info.ac_state) { case APM_AC_OFF: batt_info->status = CS_DISCHARGING; break; case APM_AC_ON: batt_info->status = CS_CHARGING; break; default: /* If we don't know what's going on, just assume we're discharging. */ batt_info->status = CS_DISCHARGING; break; } batt_info->percentage_remaining = apm_info.battery_life; /* Can't give a meaningful value for remaining minutes if we're charging. */ if (batt_info->status != CS_CHARGING) { batt_info->seconds_remaining = apm_info.minutes_left * 60; } #elif defined(__NetBSD__) /* * Using envsys(4) via sysmon(4). */ int fd, rval; bool is_found = false; char sensor_desc[16]; 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; if (number >= 0) (void)snprintf(sensor_desc, sizeof(sensor_desc), "acpibat%d", number); fd = open("/dev/sysmon", O_RDONLY); if (fd < 0) { OUTPUT_FULL_TEXT("can't open /dev/sysmon"); return false; } rval = prop_dictionary_recv_ioctl(fd, ENVSYS_GETDICTIONARY, &dict); if (rval == -1) { close(fd); return false; } if (prop_dictionary_count(dict) == 0) { prop_object_release(dict); close(fd); return false; } 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 (number < 0) { /* we want all batteries */ if (!BEGINS_WITH(prop_dictionary_keysym_cstring_nocopy(obj), "acpibat")) continue; } else { /* we want a specific battery */ if (strcmp(sensor_desc, prop_dictionary_keysym_cstring_nocopy(obj)) != 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 false; } iter2 = prop_array_iterator(array); if (!iter2) { prop_object_iterator_release(iter); prop_object_release(dict); close(fd); return false; } struct battery_info batt_buf = { .full_design = 0, .full_last = 0, .remaining = 0, .present_rate = 0, .status = CS_UNKNOWN, }; int voltage = -1; bool watt_as_unit = false; /* 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 == NULL) continue; if (strcmp("charging", prop_string_cstring_nocopy(obj3)) == 0) { obj3 = prop_dictionary_get(obj2, "cur-value"); if (prop_number_integer_value(obj3)) batt_buf.status = CS_CHARGING; else batt_buf.status = CS_DISCHARGING; } else if (strcmp("charge", prop_string_cstring_nocopy(obj3)) == 0) { obj3 = prop_dictionary_get(obj2, "cur-value"); obj4 = prop_dictionary_get(obj2, "max-value"); obj5 = prop_dictionary_get(obj2, "type"); batt_buf.remaining = prop_number_integer_value(obj3); batt_buf.full_design = prop_number_integer_value(obj4); if (strcmp("Ampere hour", prop_string_cstring_nocopy(obj5)) == 0) watt_as_unit = false; else watt_as_unit = true; } else if (strcmp("discharge rate", prop_string_cstring_nocopy(obj3)) == 0) { obj3 = prop_dictionary_get(obj2, "cur-value"); batt_buf.present_rate = prop_number_integer_value(obj3); } else if (strcmp("charge rate", prop_string_cstring_nocopy(obj3)) == 0) { obj3 = prop_dictionary_get(obj2, "cur-value"); batt_info->present_rate = prop_number_integer_value(obj3); } else if (strcmp("last full cap", prop_string_cstring_nocopy(obj3)) == 0) { obj3 = prop_dictionary_get(obj2, "cur-value"); batt_buf.full_last = prop_number_integer_value(obj3); } else if (strcmp("voltage", prop_string_cstring_nocopy(obj3)) == 0) { obj3 = prop_dictionary_get(obj2, "cur-value"); voltage = prop_number_integer_value(obj3); } } prop_object_iterator_release(iter2); if (!watt_as_unit && voltage != -1) { batt_buf.present_rate = (((float)voltage / 1000.0) * ((float)batt_buf.present_rate / 1000.0)); batt_buf.remaining = (((float)voltage / 1000.0) * ((float)batt_buf.remaining / 1000.0)); batt_buf.full_design = (((float)voltage / 1000.0) * ((float)batt_buf.full_design / 1000.0)); batt_buf.full_last = (((float)voltage / 1000.0) * ((float)batt_buf.full_last / 1000.0)); } if (batt_buf.remaining == batt_buf.full_design) batt_buf.status = CS_FULL; add_battery_info(batt_info, &batt_buf); } prop_object_iterator_release(iter); prop_object_release(dict); close(fd); if (!is_found) { OUTPUT_FULL_TEXT(format_down); return false; } batt_info->present_rate = abs(batt_info->present_rate); #endif return true; } /* * Populate batt_info with aggregate information about all batteries. * Returns false on error, and an error message will have been written. */ static bool slurp_all_batteries(struct battery_info *batt_info, yajl_gen json_gen, char *buffer, const char *path, const char *format_down) { #if defined(LINUX) char *outwalk = buffer; bool is_found = false; char *placeholder; char *globpath = sstrdup(path); if ((placeholder = strstr(path, "%d")) != NULL) { char *globplaceholder = globpath + (placeholder - path); *globplaceholder = '*'; strcpy(globplaceholder + 1, placeholder + 2); } if (!strcmp(globpath, path)) { OUTPUT_FULL_TEXT("no '%d' in battery path"); return false; } glob_t globbuf; if (glob(globpath, 0, NULL, &globbuf) == 0) { for (size_t i = 0; i < globbuf.gl_pathc; i++) { /* Probe to see if there is such a battery. */ struct battery_info batt_buf = { .full_design = 0, .full_last = 0, .remaining = 0, .present_rate = 0, .status = CS_UNKNOWN, }; if (!slurp_battery_info(&batt_buf, json_gen, buffer, i, globbuf.gl_pathv[i], format_down)) return false; is_found = true; add_battery_info(batt_info, &batt_buf); } } globfree(&globbuf); free(globpath); if (!is_found) { OUTPUT_FULL_TEXT(format_down); return false; } batt_info->present_rate = abs(batt_info->present_rate); #else /* FreeBSD and OpenBSD only report aggregates. NetBSD always * iterates through all batteries, so it's more efficient to * aggregate in slurp_battery_info. */ return slurp_battery_info(batt_info, json_gen, buffer, -1, path, format_down); #endif return true; } void print_battery_info(yajl_gen json_gen, char *buffer, int number, const char *path, const char *format, const char *format_down, const char *status_chr, const char *status_bat, const char *status_unk, const char *status_full, int low_threshold, char *threshold_type, bool last_full_capacity, bool integer_battery_capacity, bool hide_seconds) { const char *walk; char *outwalk = buffer; struct battery_info batt_info = { .full_design = -1, .full_last = -1, .remaining = -1, .present_rate = -1, .seconds_remaining = -1, .percentage_remaining = -1, .status = CS_UNKNOWN, }; bool colorful_output = false; #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) || defined(__OpenBSD__) /* These OSes report battery stats in whole percent. */ integer_battery_capacity = true; #endif #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) || defined(__OpenBSD__) /* These OSes report battery time in minutes. */ hide_seconds = true; #endif if (number < 0) { if (!slurp_all_batteries(&batt_info, json_gen, buffer, path, format_down)) return; } else { if (!slurp_battery_info(&batt_info, json_gen, buffer, number, path, format_down)) return; } // *Choose* a measure of the 'full' battery. It is whichever is better of // the battery's (hardware-given) design capacity (batt_info.full_design) // and the battery's last known good charge (batt_info.full_last). // We prefer the design capacity, but use the last capacity if we don't have it, // or if we are asked to (last_full_capacity == true); but similarly we use // the design capacity if we don't have the last capacity. // If we don't have either then both full_design and full_last <= 0, // which implies full <= 0, which bails out on the following line. int full = batt_info.full_design; if (full <= 0 || (last_full_capacity && batt_info.full_last > 0)) { full = batt_info.full_last; } if (full <= 0 && batt_info.remaining < 0 && batt_info.percentage_remaining < 0) { /* We have no physical measurements and no estimates. Nothing * much we can report, then. */ OUTPUT_FULL_TEXT(format_down); return; } if (batt_info.percentage_remaining < 0) { batt_info.percentage_remaining = (((float)batt_info.remaining / (float)full) * 100); /* Some batteries report POWER_SUPPLY_CHARGE_NOW=<full_design> when fully * charged, even though that’s plainly wrong. For people who chose to see * the percentage calculated based on the last full capacity, we clamp the * value to 100%, as that makes more sense. * See http://bugs.debian.org/785398 */ if (last_full_capacity && batt_info.percentage_remaining > 100) { batt_info.percentage_remaining = 100; } } if (batt_info.seconds_remaining < 0 && batt_info.present_rate > 0 && batt_info.status != CS_FULL) { if (batt_info.status == CS_CHARGING) batt_info.seconds_remaining = 3600.0 * (full - batt_info.remaining) / batt_info.present_rate; else if (batt_info.status == CS_DISCHARGING) batt_info.seconds_remaining = 3600.0 * batt_info.remaining / batt_info.present_rate; else batt_info.seconds_remaining = 0; } if (batt_info.status == CS_DISCHARGING && low_threshold > 0) { if (batt_info.percentage_remaining >= 0 && strcasecmp(threshold_type, "percentage") == 0 && batt_info.percentage_remaining < low_threshold) { START_COLOR("color_bad"); colorful_output = true; } else if (batt_info.seconds_remaining >= 0 && strcasecmp(threshold_type, "time") == 0 && batt_info.seconds_remaining < 60 * low_threshold) { START_COLOR("color_bad"); colorful_output = true; } } #define EAT_SPACE_FROM_OUTPUT_IF_NO_OUTPUT() \ do { \ if (outwalk == prevoutwalk) { \ if (outwalk > buffer && isspace((int)outwalk[-1])) \ outwalk--; \ else if (isspace((int)*(walk + 1))) \ walk++; \ } \ } while (0) for (walk = format; *walk != '\0'; walk++) { char *prevoutwalk = outwalk; if (*walk != '%') { *(outwalk++) = *walk; continue; } if (BEGINS_WITH(walk + 1, "status")) { const char *statusstr; switch (batt_info.status) { case CS_CHARGING: statusstr = status_chr; break; case CS_DISCHARGING: statusstr = status_bat; break; case CS_FULL: statusstr = status_full; break; default: statusstr = status_unk; } outwalk += sprintf(outwalk, "%s", statusstr); walk += strlen("status"); } else if (BEGINS_WITH(walk + 1, "percentage")) { if (integer_battery_capacity) { outwalk += sprintf(outwalk, "%.00f%s", batt_info.percentage_remaining, pct_mark); } else { outwalk += sprintf(outwalk, "%.02f%s", batt_info.percentage_remaining, pct_mark); } walk += strlen("percentage"); } else if (BEGINS_WITH(walk + 1, "remaining")) { if (batt_info.seconds_remaining >= 0) { int seconds, hours, minutes; hours = batt_info.seconds_remaining / 3600; seconds = batt_info.seconds_remaining - (hours * 3600); minutes = seconds / 60; seconds -= (minutes * 60); if (hide_seconds) outwalk += sprintf(outwalk, "%02d:%02d", max(hours, 0), max(minutes, 0)); else outwalk += sprintf(outwalk, "%02d:%02d:%02d", max(hours, 0), max(minutes, 0), max(seconds, 0)); } walk += strlen("remaining"); EAT_SPACE_FROM_OUTPUT_IF_NO_OUTPUT(); } else if (BEGINS_WITH(walk + 1, "emptytime")) { if (batt_info.seconds_remaining >= 0) { time_t empty_time = time(NULL) + batt_info.seconds_remaining; set_timezone(NULL); /* Use local time. */ struct tm *empty_tm = localtime(&empty_time); if (hide_seconds) outwalk += sprintf(outwalk, "%02d:%02d", max(empty_tm->tm_hour, 0), max(empty_tm->tm_min, 0)); else outwalk += sprintf(outwalk, "%02d:%02d:%02d", max(empty_tm->tm_hour, 0), max(empty_tm->tm_min, 0), max(empty_tm->tm_sec, 0)); } walk += strlen("emptytime"); EAT_SPACE_FROM_OUTPUT_IF_NO_OUTPUT(); } else if (BEGINS_WITH(walk + 1, "consumption")) { if (batt_info.present_rate >= 0) outwalk += sprintf(outwalk, "%1.2fW", batt_info.present_rate / 1e6); walk += strlen("consumption"); EAT_SPACE_FROM_OUTPUT_IF_NO_OUTPUT(); } } if (colorful_output) END_COLOR; OUTPUT_FULL_TEXT(buffer); }
void udev_read_event(int fd) { struct pdev_array_entry *pae; prop_dictionary_t dict, evdict, devdict; prop_number_t pn; prop_string_t ps; prop_object_t po; prop_array_t pa; char *xml; int n, idx, evtype; size_t sz; sz = 4096 * 1024; xml = malloc(sz); /* 4 MB */ again: if ((n = read(fd, xml, sz)) <= 0) { if (errno == ENOMEM) { sz <<= 2; if ((xml = realloc(xml, sz)) == NULL) { syslog(LOG_ERR, "could not realloc xml memory"); return; } goto again; } free(xml); return; } dict = prop_dictionary_internalize(xml); free(xml); if (dict == NULL) { syslog(LOG_ERR, "internalization of xml failed"); return; } pn = prop_dictionary_get(dict, "evtype"); if (pn == NULL) { syslog(LOG_ERR, "read_event: no key evtype"); goto out; } evtype = prop_number_integer_value(pn); evdict = prop_dictionary_get(dict, "evdict"); if (evdict == NULL) { syslog(LOG_ERR, "read_event: no key evdict"); goto out; } switch (evtype) { case UDEV_EVENT_ATTACH: monitor_queue_event(dict); pae = pdev_array_entry_get_last(); pa = prop_array_copy(pae->pdev_array); pdev_array_entry_unref(pae); if (pa == NULL) goto out; prop_array_add(pa, evdict); pdev_array_entry_insert(pa); break; case UDEV_EVENT_DETACH: monitor_queue_event(dict); if ((devdict = find_dev_dict(-1, evdict, &idx)) == NULL) goto out; pae = pdev_array_entry_get_last(); pa = prop_array_copy(pae->pdev_array); pdev_array_entry_unref(pae); if (pa == NULL) goto out; prop_array_remove(pa, idx); pdev_array_entry_insert(pa); break; case UDEV_EV_KEY_UPDATE: if ((devdict = find_dev_dict(-1, evdict, NULL)) == NULL) goto out; if ((ps = prop_dictionary_get(evdict, "key")) == NULL) goto out; if ((po = prop_dictionary_get(evdict, "value")) == NULL) goto out; /* prop_object_retain(po); */ /* not necessary afaik */ prop_dictionary_set(devdict, prop_string_cstring_nocopy(ps), po); break; case UDEV_EV_KEY_REMOVE: if ((devdict = find_dev_dict(-1, evdict, NULL)) == NULL) goto out; if ((ps = prop_dictionary_get(evdict, "key")) == NULL) goto out; prop_dictionary_remove(devdict, prop_string_cstring_nocopy(ps)); break; default: syslog(LOG_ERR, "read_event: unknown evtype %d", evtype); } out: prop_object_release(dict); return; }