12f3213f9SYi Li /**
22f3213f9SYi Li * Copyright © 2016 IBM Corporation
32f3213f9SYi Li *
42f3213f9SYi Li * Licensed under the Apache License, Version 2.0 (the "License");
52f3213f9SYi Li * you may not use this file except in compliance with the License.
62f3213f9SYi Li * You may obtain a copy of the License at
72f3213f9SYi Li *
82f3213f9SYi Li * http://www.apache.org/licenses/LICENSE-2.0
92f3213f9SYi Li *
102f3213f9SYi Li * Unless required by applicable law or agreed to in writing, software
112f3213f9SYi Li * distributed under the License is distributed on an "AS IS" BASIS,
122f3213f9SYi Li * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
132f3213f9SYi Li * See the License for the specific language governing permissions and
142f3213f9SYi Li * limitations under the License.
152f3213f9SYi Li */
162f3213f9SYi Li #include <stdio.h>
172f3213f9SYi Li #include <stdlib.h>
182f3213f9SYi Li #include <limits.h>
192f3213f9SYi Li #include <errno.h>
202f3213f9SYi Li #include <string.h>
212f3213f9SYi Li #include <getopt.h>
222f3213f9SYi Li #include <systemd/sd-bus.h>
232f3213f9SYi Li
242f3213f9SYi Li #define DBUS_MAX_NAME_LEN 256
252f3213f9SYi Li
26e87cc29cSBrad Bishop const char *objectmapper_service_name = "xyz.openbmc_project.ObjectMapper";
27e1e2e6dcSLeonel Gonzalez const char *objectmapper_object_name = "/xyz/openbmc_project/object_mapper";
28e87cc29cSBrad Bishop const char *objectmapper_intf_name = "xyz.openbmc_project.ObjectMapper";
292f3213f9SYi Li
302f3213f9SYi Li typedef struct {
312f3213f9SYi Li int fan_num;
322f3213f9SYi Li int cpu_num;
332f3213f9SYi Li int core_num;
342f3213f9SYi Li int dimm_num;
352f3213f9SYi Li sd_bus *bus;
362f3213f9SYi Li char sensor_service[DBUS_MAX_NAME_LEN];
372f3213f9SYi Li char inventory_service[DBUS_MAX_NAME_LEN];
382f3213f9SYi Li } fan_info_t;
392f3213f9SYi Li
402f3213f9SYi Li /* Get an object's bus name from ObjectMapper */
get_connection(sd_bus * bus,char * connection,const char * obj_path)412f3213f9SYi Li int get_connection(sd_bus *bus, char *connection, const char *obj_path)
422f3213f9SYi Li {
432f3213f9SYi Li sd_bus_error bus_error = SD_BUS_ERROR_NULL;
442f3213f9SYi Li sd_bus_message *m = NULL;
452f3213f9SYi Li char *temp_buf = NULL, *intf = NULL;
462f3213f9SYi Li int rc;
472f3213f9SYi Li
482f3213f9SYi Li rc = sd_bus_call_method(bus,
492f3213f9SYi Li objectmapper_service_name,
502f3213f9SYi Li objectmapper_object_name,
512f3213f9SYi Li objectmapper_intf_name,
522f3213f9SYi Li "GetObject",
532f3213f9SYi Li &bus_error,
542f3213f9SYi Li &m,
55*c6fa1dddSAdriana Kobylak "ss",
56*c6fa1dddSAdriana Kobylak obj_path,
57*c6fa1dddSAdriana Kobylak "");
582f3213f9SYi Li if (rc < 0) {
592f3213f9SYi Li fprintf(stderr,
602f3213f9SYi Li "Failed to GetObject: %s\n", bus_error.message);
612f3213f9SYi Li goto finish;
622f3213f9SYi Li }
632f3213f9SYi Li
642f3213f9SYi Li /* Get the key, aka, the bus name */
652f3213f9SYi Li sd_bus_message_read(m, "a{sas}", 1, &temp_buf, 1, &intf);
662f3213f9SYi Li strncpy(connection, temp_buf, DBUS_MAX_NAME_LEN);
672f3213f9SYi Li
682f3213f9SYi Li finish:
692f3213f9SYi Li sd_bus_error_free(&bus_error);
702f3213f9SYi Li sd_bus_message_unref(m);
712f3213f9SYi Li sd_bus_flush(bus);
722f3213f9SYi Li
732f3213f9SYi Li return rc;
742f3213f9SYi Li }
752f3213f9SYi Li
762f3213f9SYi Li
set_dbus_sensor(sd_bus * bus,const char * obj_path,int val)772f3213f9SYi Li int set_dbus_sensor(sd_bus *bus, const char *obj_path, int val)
782f3213f9SYi Li {
792f3213f9SYi Li char connection[DBUS_MAX_NAME_LEN];
802f3213f9SYi Li sd_bus_error bus_error = SD_BUS_ERROR_NULL;
812f3213f9SYi Li sd_bus_message *response = NULL;
822f3213f9SYi Li int rc;
832f3213f9SYi Li
842f3213f9SYi Li if (!bus || !obj_path)
852f3213f9SYi Li return -1;
862f3213f9SYi Li
872f3213f9SYi Li rc = get_connection(bus, connection, obj_path);
882f3213f9SYi Li if (rc < 0) {
892f3213f9SYi Li fprintf(stderr,
902f3213f9SYi Li "fanctl: Failed to get bus name for %s\n", obj_path);
912f3213f9SYi Li goto finish;
922f3213f9SYi Li }
932f3213f9SYi Li
94*c6fa1dddSAdriana Kobylak rc = sd_bus_set_property(bus,
952f3213f9SYi Li connection,
962f3213f9SYi Li obj_path,
97*c6fa1dddSAdriana Kobylak "xyz.openbmc_project.Control.FanSpeed",
98*c6fa1dddSAdriana Kobylak "Target",
992f3213f9SYi Li &bus_error,
1002f3213f9SYi Li "i",
1012f3213f9SYi Li val);
1022f3213f9SYi Li if (rc < 0)
1032f3213f9SYi Li fprintf(stderr,
1042f3213f9SYi Li "fanctl: Failed to set sensor %s:[%s]\n",
1052f3213f9SYi Li obj_path, strerror(-rc));
1062f3213f9SYi Li
1072f3213f9SYi Li finish:
1082f3213f9SYi Li sd_bus_error_free(&bus_error);
1092f3213f9SYi Li sd_bus_message_unref(response);
1102f3213f9SYi Li sd_bus_flush(bus);
1112f3213f9SYi Li
1122f3213f9SYi Li return rc;
1132f3213f9SYi Li }
1142f3213f9SYi Li
115*c6fa1dddSAdriana Kobylak /* Read sensor value from "xyz.openbmc_projects.Sensors" */
read_dbus_sensor(sd_bus * bus,const char * obj_path,const char * property)116*c6fa1dddSAdriana Kobylak int read_dbus_sensor(sd_bus *bus, const char *obj_path, const char *property)
1172f3213f9SYi Li {
1182f3213f9SYi Li char connection[DBUS_MAX_NAME_LEN];
1192f3213f9SYi Li sd_bus_error bus_error = SD_BUS_ERROR_NULL;
1202f3213f9SYi Li sd_bus_message *response = NULL;
1212f3213f9SYi Li int rc;
1222f3213f9SYi Li int val = 0;
1232f3213f9SYi Li
1242f3213f9SYi Li if (!bus || !obj_path)
1252f3213f9SYi Li return 0;
1262f3213f9SYi Li
1272f3213f9SYi Li rc = get_connection(bus, connection, obj_path);
1282f3213f9SYi Li if (rc < 0) {
1292f3213f9SYi Li val = 0;
1302f3213f9SYi Li fprintf(stderr,
1312f3213f9SYi Li "fanctl: Failed to get bus name for %s\n", obj_path);
1322f3213f9SYi Li goto finish;
1332f3213f9SYi Li }
1342f3213f9SYi Li
135*c6fa1dddSAdriana Kobylak rc = sd_bus_get_property(bus,
1362f3213f9SYi Li connection,
1372f3213f9SYi Li obj_path,
138*c6fa1dddSAdriana Kobylak "xyz.openbmc_project.Sensor.Value",
139*c6fa1dddSAdriana Kobylak property,
1402f3213f9SYi Li &bus_error,
1412f3213f9SYi Li &response,
142*c6fa1dddSAdriana Kobylak "i");
1432f3213f9SYi Li if (rc < 0) {
1442f3213f9SYi Li val = 0;
1452f3213f9SYi Li fprintf(stderr,
1462f3213f9SYi Li "fanctl: Failed to read sensor value from %s:[%s]\n",
1472f3213f9SYi Li obj_path, strerror(-rc));
1482f3213f9SYi Li goto finish;
1492f3213f9SYi Li }
1502f3213f9SYi Li
151*c6fa1dddSAdriana Kobylak rc = sd_bus_message_read(response, "i", &val);
1522f3213f9SYi Li if (rc < 0) {
1532f3213f9SYi Li val = 0;
1542f3213f9SYi Li fprintf(stderr,
1552f3213f9SYi Li "fanctl: Failed to parse sensor value "
1562f3213f9SYi Li "response message from %s:[%s]\n",
1572f3213f9SYi Li obj_path, strerror(-rc));
1582f3213f9SYi Li }
1592f3213f9SYi Li
1602f3213f9SYi Li finish:
1612f3213f9SYi Li sd_bus_error_free(&bus_error);
1622f3213f9SYi Li sd_bus_message_unref(response);
1632f3213f9SYi Li sd_bus_flush(bus);
1642f3213f9SYi Li
1652f3213f9SYi Li return val;
1662f3213f9SYi Li }
1672f3213f9SYi Li
168*c6fa1dddSAdriana Kobylak /* set fan speed with /xyz/openbmc_project/sensors/fan_tach/fan* object */
fan_set_speed(sd_bus * bus,int fan_id,uint8_t fan_speed)1692f3213f9SYi Li static int fan_set_speed(sd_bus *bus, int fan_id, uint8_t fan_speed)
1702f3213f9SYi Li {
1712f3213f9SYi Li char obj_path[DBUS_MAX_NAME_LEN];
1722f3213f9SYi Li int rc;
1732f3213f9SYi Li
1742f3213f9SYi Li if (!bus)
1752f3213f9SYi Li return -1;
1762f3213f9SYi Li
1772f3213f9SYi Li snprintf(obj_path, sizeof(obj_path),
178*c6fa1dddSAdriana Kobylak "/xyz/openbmc_project/sensors/fan_tach/fan%d_0", fan_id);
1792f3213f9SYi Li rc = set_dbus_sensor(bus, obj_path, fan_speed);
1802f3213f9SYi Li if (rc < 0)
1812f3213f9SYi Li fprintf(stderr, "fanctl: Failed to set fan[%d] speed[%d]\n",
1822f3213f9SYi Li fan_id, fan_speed);
1832f3213f9SYi Li
1842f3213f9SYi Li return rc;
1852f3213f9SYi Li }
1862f3213f9SYi Li
fan_set_max_speed(fan_info_t * info)1872f3213f9SYi Li static int fan_set_max_speed(fan_info_t *info)
1882f3213f9SYi Li {
1892f3213f9SYi Li int i;
1902f3213f9SYi Li int rc = -1;
1912f3213f9SYi Li
1922f3213f9SYi Li if (!info)
1932f3213f9SYi Li return -1;
1942f3213f9SYi Li for (i = 0; i < info->fan_num; i++) {
1952f3213f9SYi Li rc = fan_set_speed(info->bus, i, 255);
1962f3213f9SYi Li if (rc < 0)
1972f3213f9SYi Li break;
1982f3213f9SYi Li fprintf(stderr, "fanctl: Set fan%d to max speed\n", i);
1992f3213f9SYi Li }
2002f3213f9SYi Li
2012f3213f9SYi Li return rc;
2022f3213f9SYi Li }
2032f3213f9SYi Li /*
2042f3213f9SYi Li * FAN_TACH_OFFSET is specific to Barreleye.
2052f3213f9SYi Li * Barreleye uses NTC7904D HW Monitor as Fan tachometoer.
206aa4c3103SGunnar Mills * The 13-bit FANIN value is made up Higher part: [12:5],
2072f3213f9SYi Li * and Lower part: [4:0], which are read from two sensors.
2082f3213f9SYi Li * see: https://www.nuvoton.com/resource-files/NCT7904D_Datasheet_V1.44.pdf
2092f3213f9SYi Li */
2102f3213f9SYi Li #define FAN_TACH_OFFSET 5
fan_get_speed(sd_bus * bus,int fan_id)2112f3213f9SYi Li static int fan_get_speed(sd_bus *bus, int fan_id)
2122f3213f9SYi Li {
2132f3213f9SYi Li int fan_tach_H = 0, fan_tach_L = 0;
2142f3213f9SYi Li char obj_path[DBUS_MAX_NAME_LEN];
2152f3213f9SYi Li int fan_speed;
2162f3213f9SYi Li
2172f3213f9SYi Li /* get fan tach */
2182f3213f9SYi Li snprintf(obj_path, sizeof(obj_path),
219*c6fa1dddSAdriana Kobylak "/xyz/openbmc_project/sensors/fan_tach/fan%d_0", fan_id);
220*c6fa1dddSAdriana Kobylak fan_tach_H = read_dbus_sensor(bus, obj_path, "MaxValue");
221*c6fa1dddSAdriana Kobylak fan_tach_L = read_dbus_sensor(bus, obj_path, "MinValue");
2222f3213f9SYi Li
2232f3213f9SYi Li /* invalid sensor value is -1 */
2242f3213f9SYi Li if (fan_tach_H <= 0 || fan_tach_L <= 0)
2252f3213f9SYi Li fan_speed = 0;
2262f3213f9SYi Li else
2272f3213f9SYi Li fan_speed = fan_tach_H << FAN_TACH_OFFSET | fan_tach_L;
2282f3213f9SYi Li
2292f3213f9SYi Li fprintf(stderr, "fan%d speed: %d\n", fan_id, fan_speed);
2302f3213f9SYi Li return fan_speed;
2312f3213f9SYi Li }
2322f3213f9SYi Li
2332f3213f9SYi Li /* set Fan Inventory 'Present' status */
fan_set_present(sd_bus * bus,int fan_id,int val)2342f3213f9SYi Li int fan_set_present(sd_bus *bus, int fan_id, int val)
2352f3213f9SYi Li {
2362f3213f9SYi Li sd_bus_error bus_error = SD_BUS_ERROR_NULL;
2372f3213f9SYi Li sd_bus_message *response = NULL;
2382f3213f9SYi Li int rc;
2392f3213f9SYi Li char obj_path[DBUS_MAX_NAME_LEN];
2402f3213f9SYi Li char connection[DBUS_MAX_NAME_LEN];
2412f3213f9SYi Li
2422f3213f9SYi Li snprintf(obj_path, sizeof(obj_path),
243*c6fa1dddSAdriana Kobylak "/xyz/openbmc_project/inventory/system/chassis/motherboard/fan%d",
244*c6fa1dddSAdriana Kobylak fan_id);
2452f3213f9SYi Li
2462f3213f9SYi Li rc = get_connection(bus, connection, obj_path);
2472f3213f9SYi Li if (rc < 0) {
2482f3213f9SYi Li fprintf(stderr,
2492f3213f9SYi Li "fanctl: Failed to get bus name for %s\n", obj_path);
2502f3213f9SYi Li goto finish;
2512f3213f9SYi Li }
2522f3213f9SYi Li
253*c6fa1dddSAdriana Kobylak rc = sd_bus_set_property(bus,
2542f3213f9SYi Li connection,
2552f3213f9SYi Li obj_path,
256*c6fa1dddSAdriana Kobylak "xyz.openbmc_project.Inventory.Item",
257*c6fa1dddSAdriana Kobylak "Present",
2582f3213f9SYi Li &bus_error,
259*c6fa1dddSAdriana Kobylak "b",
260*c6fa1dddSAdriana Kobylak val);
2612f3213f9SYi Li if(rc < 0)
2622f3213f9SYi Li fprintf(stderr,
2632f3213f9SYi Li "fanctl: Failed to update fan presence via dbus: %s\n",
2642f3213f9SYi Li bus_error.message);
2652f3213f9SYi Li
2662f3213f9SYi Li fprintf(stderr, "fanctl: Set fan%d present status to: %s\n",
2672f3213f9SYi Li fan_id, (val == 1 ? "True" : "False"));
2682f3213f9SYi Li
2692f3213f9SYi Li finish:
2702f3213f9SYi Li sd_bus_error_free(&bus_error);
2712f3213f9SYi Li sd_bus_message_unref(response);
2722f3213f9SYi Li sd_bus_flush(bus);
2732f3213f9SYi Li
2742f3213f9SYi Li return rc;
2752f3213f9SYi Li }
2762f3213f9SYi Li
2772f3213f9SYi Li /*
2782f3213f9SYi Li * Update Fan Invertory 'Present' status by first reading fan speed.
2792f3213f9SYi Li * If fan speed is '0', the fan is considerred not 'Present'.
2802f3213f9SYi Li */
fan_update_present(fan_info_t * info)2812f3213f9SYi Li static int fan_update_present(fan_info_t *info)
2822f3213f9SYi Li {
2832f3213f9SYi Li int i;
2842f3213f9SYi Li int rc = -1;
2852f3213f9SYi Li int fan_speed;
2862f3213f9SYi Li
2872f3213f9SYi Li if (!info)
2882f3213f9SYi Li return -1;
2892f3213f9SYi Li
2902f3213f9SYi Li for (i = 0; i < info->fan_num; i++) {
2912f3213f9SYi Li fan_speed = fan_get_speed(info->bus, i);
2922f3213f9SYi Li if (fan_speed > 0)
2932f3213f9SYi Li rc = fan_set_present(info->bus, i, 1);
2942f3213f9SYi Li else
2952f3213f9SYi Li rc = fan_set_present(info->bus, i, 0);
2962f3213f9SYi Li
2972f3213f9SYi Li if (rc < 0) {
2982f3213f9SYi Li fprintf(stderr,
2992f3213f9SYi Li "fanctl: Failed to set fan present status\n");
3002f3213f9SYi Li break;
3012f3213f9SYi Li }
3022f3213f9SYi Li }
3032f3213f9SYi Li
3042f3213f9SYi Li return rc;
3052f3213f9SYi Li }
3062f3213f9SYi Li /*
3072f3213f9SYi Li * Router function for any FAN operations that come via dbus
3082f3213f9SYi Li */
fan_function_router(sd_bus_message * msg,void * user_data,sd_bus_error * ret_error)3092f3213f9SYi Li static int fan_function_router(sd_bus_message *msg, void *user_data,
3102f3213f9SYi Li sd_bus_error *ret_error)
3112f3213f9SYi Li {
3122f3213f9SYi Li /* Generic error reporter. */
3132f3213f9SYi Li int rc = -1;
3142f3213f9SYi Li fan_info_t *info = user_data;
3152f3213f9SYi Li
3162f3213f9SYi Li /* Get the Operation. */
3172f3213f9SYi Li const char *fan_function = sd_bus_message_get_member(msg);
3182f3213f9SYi Li if (fan_function == NULL) {
3199d572eb3SGunnar Mills fprintf(stderr, "fanctl: Null FAN function specified\n");
3202f3213f9SYi Li return sd_bus_reply_method_return(msg, "i", rc);
3212f3213f9SYi Li }
3222f3213f9SYi Li
3232f3213f9SYi Li /* Route the user action to appropriate handlers. */
3242f3213f9SYi Li if ((strcmp(fan_function, "setMax") == 0)) {
3252f3213f9SYi Li rc = fan_set_max_speed(info);
3262f3213f9SYi Li return sd_bus_reply_method_return(msg, "i", rc);
3272f3213f9SYi Li }
3282f3213f9SYi Li if ((strcmp(fan_function, "updatePresent") == 0)) {
3292f3213f9SYi Li rc = fan_update_present(info);
3302f3213f9SYi Li return sd_bus_reply_method_return(msg, "i", rc);
3312f3213f9SYi Li }
3322f3213f9SYi Li
3332f3213f9SYi Li return sd_bus_reply_method_return(msg, "i", rc);
3342f3213f9SYi Li }
3352f3213f9SYi Li
3362f3213f9SYi Li /* Dbus Services offered by this FAN controller */
3372f3213f9SYi Li static const sd_bus_vtable fan_control_vtable[] =
3382f3213f9SYi Li {
3392f3213f9SYi Li SD_BUS_VTABLE_START(0),
3402f3213f9SYi Li SD_BUS_METHOD("setMax", "", "i", &fan_function_router,
3412f3213f9SYi Li SD_BUS_VTABLE_UNPRIVILEGED),
3422f3213f9SYi Li SD_BUS_METHOD("updatePresent", "", "i", &fan_function_router,
3432f3213f9SYi Li SD_BUS_VTABLE_UNPRIVILEGED),
3442f3213f9SYi Li SD_BUS_VTABLE_END,
3452f3213f9SYi Li };
3462f3213f9SYi Li
start_fan_services(fan_info_t * info)3472f3213f9SYi Li int start_fan_services(fan_info_t *info)
3482f3213f9SYi Li {
3492f3213f9SYi Li /* Generic error reporter. */
3502f3213f9SYi Li int rc = -1;
3512f3213f9SYi Li /* slot where we are offering the FAN dbus service. */
3522f3213f9SYi Li sd_bus_slot *fan_slot = NULL;
3532f3213f9SYi Li const char *fan_object = "/org/openbmc/control/fans";
3542f3213f9SYi Li
3552f3213f9SYi Li info->bus = NULL;
3562f3213f9SYi Li /* Get a hook onto system bus. */
3572f3213f9SYi Li rc = sd_bus_open_system(&info->bus);
3582f3213f9SYi Li if (rc < 0) {
3592f3213f9SYi Li fprintf(stderr,"fanctl: Error opening system bus.\n");
3602f3213f9SYi Li return rc;
3612f3213f9SYi Li }
3622f3213f9SYi Li
3632f3213f9SYi Li /* Install the object */
3642f3213f9SYi Li rc = sd_bus_add_object_vtable(info->bus,
3652f3213f9SYi Li &fan_slot,
3662f3213f9SYi Li fan_object, /* object path */
3672f3213f9SYi Li "org.openbmc.control.Fans", /* interface name */
3682f3213f9SYi Li fan_control_vtable,
3692f3213f9SYi Li info);
3702f3213f9SYi Li if (rc < 0) {
3712f3213f9SYi Li fprintf(stderr, "fanctl: Failed to add object to dbus: %s\n",
3722f3213f9SYi Li strerror(-rc));
3732f3213f9SYi Li return rc;
3742f3213f9SYi Li }
3752f3213f9SYi Li
3762f3213f9SYi Li /* If we had success in adding the providers, request for a bus name. */
3772f3213f9SYi Li rc = sd_bus_request_name(info->bus,
3782f3213f9SYi Li "org.openbmc.control.Fans", 0);
3792f3213f9SYi Li if (rc < 0) {
3802f3213f9SYi Li fprintf(stderr, "fanctl: Failed to acquire service name: %s\n",
3812f3213f9SYi Li strerror(-rc));
3822f3213f9SYi Li return rc;
3832f3213f9SYi Li }
3842f3213f9SYi Li
3852f3213f9SYi Li for (;;) {
3862f3213f9SYi Li /* Process requests */
3872f3213f9SYi Li rc = sd_bus_process(info->bus, NULL);
3882f3213f9SYi Li if (rc < 0) {
3892f3213f9SYi Li fprintf(stderr, "fanctl: Failed to process bus: %s\n",
3902f3213f9SYi Li strerror(-rc));
3912f3213f9SYi Li break;
3922f3213f9SYi Li }
3932f3213f9SYi Li if (rc > 0) {
3942f3213f9SYi Li continue;
3952f3213f9SYi Li }
3962f3213f9SYi Li
3972f3213f9SYi Li rc = sd_bus_wait(info->bus, (uint64_t) - 1);
3982f3213f9SYi Li if (rc < 0) {
3992f3213f9SYi Li fprintf(stderr, "fanctl: Failed to wait on bus: %s\n",
4002f3213f9SYi Li strerror(-rc));
4012f3213f9SYi Li break;
4022f3213f9SYi Li }
4032f3213f9SYi Li }
4042f3213f9SYi Li
4052f3213f9SYi Li sd_bus_slot_unref(fan_slot);
4062f3213f9SYi Li sd_bus_unref(info->bus);
4072f3213f9SYi Li
4082f3213f9SYi Li return rc;
4092f3213f9SYi Li }
4102f3213f9SYi Li
str_to_int(char * str)4112f3213f9SYi Li static int str_to_int(char *str)
4122f3213f9SYi Li {
4132f3213f9SYi Li long val;
4142f3213f9SYi Li char *temp;
4152f3213f9SYi Li
4162f3213f9SYi Li val = strtol(str, &temp, 10);
4172f3213f9SYi Li if (temp == str || *temp != '\0' ||
4182f3213f9SYi Li ((val == LONG_MIN || val == LONG_MAX) && errno == ERANGE))
4192f3213f9SYi Li return -1;
4202f3213f9SYi Li if (val < 0)
4212f3213f9SYi Li return -1;
4222f3213f9SYi Li
4232f3213f9SYi Li return (int)val;
4242f3213f9SYi Li }
4252f3213f9SYi Li
parse_argument(int argc,char ** argv,fan_info_t * info)4262f3213f9SYi Li static int parse_argument(int argc, char **argv, fan_info_t *info)
4272f3213f9SYi Li {
4282f3213f9SYi Li int c;
4292f3213f9SYi Li struct option long_options[] =
4302f3213f9SYi Li {
4312f3213f9SYi Li {"fan_num", required_argument, 0, 'f'},
4322f3213f9SYi Li {"core_num", required_argument, 0, 'c'},
4332f3213f9SYi Li {"cpu_num", required_argument, 0, 'p'},
4342f3213f9SYi Li {"dimm_num", required_argument, 0, 'd'},
4352f3213f9SYi Li {0, 0, 0, 0}
4362f3213f9SYi Li };
4372f3213f9SYi Li
4382f3213f9SYi Li while (1) {
4392f3213f9SYi Li c = getopt_long (argc, argv, "c:d:f:p:", long_options, NULL);
4402f3213f9SYi Li
4412f3213f9SYi Li /* Detect the end of the options. */
4422f3213f9SYi Li if (c == -1)
4432f3213f9SYi Li break;
4442f3213f9SYi Li
4452f3213f9SYi Li switch (c) {
4462f3213f9SYi Li case 'f':
4472f3213f9SYi Li info->fan_num = str_to_int(optarg);
4482f3213f9SYi Li if (info->fan_num == -1) {
4492f3213f9SYi Li fprintf(stderr, "fanctl: Wrong fan_num: %s\n", optarg);
4502f3213f9SYi Li return -1;
4512f3213f9SYi Li }
4522f3213f9SYi Li break;
4532f3213f9SYi Li case 'c':
4542f3213f9SYi Li info->core_num = str_to_int(optarg);
4552f3213f9SYi Li if (info->core_num == -1) {
4562f3213f9SYi Li fprintf(stderr, "fanctl: Wrong core_num: %s\n", optarg);
4572f3213f9SYi Li return -1;
4582f3213f9SYi Li }
4592f3213f9SYi Li break;
4602f3213f9SYi Li case 'p':
4612f3213f9SYi Li info->cpu_num = str_to_int(optarg);
4622f3213f9SYi Li if (info->cpu_num == -1) {
4632f3213f9SYi Li fprintf(stderr, "fanctl: Wrong cpu_num: %s\n", optarg);
4642f3213f9SYi Li return -1;
4652f3213f9SYi Li }
4662f3213f9SYi Li break;
4672f3213f9SYi Li case 'd':
4682f3213f9SYi Li info->dimm_num = str_to_int(optarg);
4692f3213f9SYi Li if (info->dimm_num == -1) {
4702f3213f9SYi Li fprintf(stderr, "fanctl: Wrong dimm_num: %s\n", optarg);
4712f3213f9SYi Li return -1;
4722f3213f9SYi Li }
4732f3213f9SYi Li break;
4742f3213f9SYi Li default:
4752f3213f9SYi Li fprintf(stderr, "fanctl: Wrong argument\n");
4762f3213f9SYi Li return -1;
4772f3213f9SYi Li }
4782f3213f9SYi Li }
4792f3213f9SYi Li
4802f3213f9SYi Li return 0;
4812f3213f9SYi Li }
4822f3213f9SYi Li
main(int argc,char ** argv)4832f3213f9SYi Li int main(int argc, char **argv)
4842f3213f9SYi Li {
4852f3213f9SYi Li int rc = 0;
4862f3213f9SYi Li fan_info_t fan_info;
4872f3213f9SYi Li
4882f3213f9SYi Li memset(&fan_info, 0, sizeof(fan_info));
4892f3213f9SYi Li rc = parse_argument(argc, argv, &fan_info);
4902f3213f9SYi Li if (rc < 0) {
4912f3213f9SYi Li fprintf(stderr, "fanctl: Error parse argument\n");
4922f3213f9SYi Li return rc;
4932f3213f9SYi Li }
4942f3213f9SYi Li /* This call is not supposed to return. If it does, then an error */
4952f3213f9SYi Li rc = start_fan_services(&fan_info);
4962f3213f9SYi Li if (rc < 0) {
4972f3213f9SYi Li fprintf(stderr, "fanctl: Error starting FAN Services. Exiting");
4982f3213f9SYi Li }
4992f3213f9SYi Li
5002f3213f9SYi Li return rc;
5012f3213f9SYi Li }
502