989 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/* IIO - useful set of util functionality3 *4 * Copyright (c) 2008 Jonathan Cameron5 */6#include <string.h>7#include <stdlib.h>8#include <stdio.h>9#include <stdint.h>10#include <dirent.h>11#include <errno.h>12#include <ctype.h>13#include "iio_utils.h"14 15const char *iio_dir = "/sys/bus/iio/devices/";16 17static char * const iio_direction[] = {18 "in",19 "out",20};21 22/**23 * iioutils_break_up_name() - extract generic name from full channel name24 * @full_name: the full channel name25 * @generic_name: the output generic channel name26 *27 * Returns 0 on success, or a negative error code if string extraction failed.28 **/29int iioutils_break_up_name(const char *full_name, char **generic_name)30{31 char *current;32 char *w, *r;33 char *working, *prefix = "";34 int i, ret;35 36 for (i = 0; i < ARRAY_SIZE(iio_direction); i++)37 if (!strncmp(full_name, iio_direction[i],38 strlen(iio_direction[i]))) {39 prefix = iio_direction[i];40 break;41 }42 43 current = strdup(full_name + strlen(prefix) + 1);44 if (!current)45 return -ENOMEM;46 47 working = strtok(current, "_\0");48 if (!working) {49 free(current);50 return -EINVAL;51 }52 53 w = working;54 r = working;55 56 while (*r != '\0') {57 if (!isdigit(*r)) {58 *w = *r;59 w++;60 }61 62 r++;63 }64 *w = '\0';65 ret = asprintf(generic_name, "%s_%s", prefix, working);66 free(current);67 68 return (ret == -1) ? -ENOMEM : 0;69}70 71/**72 * iioutils_get_type() - find and process _type attribute data73 * @is_signed: output whether channel is signed74 * @bytes: output how many bytes the channel storage occupies75 * @bits_used: output number of valid bits of data76 * @shift: output amount of bits to shift right data before applying bit mask77 * @mask: output a bit mask for the raw data78 * @be: output if data in big endian79 * @device_dir: the IIO device directory80 * @buffer_idx: the IIO buffer index81 * @name: the channel name82 * @generic_name: the channel type name83 *84 * Returns a value >= 0 on success, otherwise a negative error code.85 **/86static int iioutils_get_type(unsigned int *is_signed, unsigned int *bytes,87 unsigned int *bits_used, unsigned int *shift,88 uint64_t *mask, unsigned int *be,89 const char *device_dir, int buffer_idx,90 const char *name, const char *generic_name)91{92 FILE *sysfsfp;93 int ret;94 DIR *dp;95 char *scan_el_dir, *builtname, *builtname_generic, *filename = 0;96 char signchar, endianchar;97 unsigned padint;98 const struct dirent *ent;99 100 ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir, buffer_idx);101 if (ret < 0)102 return -ENOMEM;103 104 ret = asprintf(&builtname, FORMAT_TYPE_FILE, name);105 if (ret < 0) {106 ret = -ENOMEM;107 goto error_free_scan_el_dir;108 }109 ret = asprintf(&builtname_generic, FORMAT_TYPE_FILE, generic_name);110 if (ret < 0) {111 ret = -ENOMEM;112 goto error_free_builtname;113 }114 115 dp = opendir(scan_el_dir);116 if (!dp) {117 ret = -errno;118 goto error_free_builtname_generic;119 }120 121 ret = -ENOENT;122 while (ent = readdir(dp), ent)123 if ((strcmp(builtname, ent->d_name) == 0) ||124 (strcmp(builtname_generic, ent->d_name) == 0)) {125 ret = asprintf(&filename,126 "%s/%s", scan_el_dir, ent->d_name);127 if (ret < 0) {128 ret = -ENOMEM;129 goto error_closedir;130 }131 132 sysfsfp = fopen(filename, "r");133 if (!sysfsfp) {134 ret = -errno;135 fprintf(stderr, "failed to open %s\n",136 filename);137 goto error_free_filename;138 }139 140 ret = fscanf(sysfsfp,141 "%ce:%c%u/%u>>%u",142 &endianchar,143 &signchar,144 bits_used,145 &padint, shift);146 if (ret < 0) {147 ret = -errno;148 fprintf(stderr,149 "failed to pass scan type description\n");150 goto error_close_sysfsfp;151 } else if (ret != 5) {152 ret = -EIO;153 fprintf(stderr,154 "scan type description didn't match\n");155 goto error_close_sysfsfp;156 }157 158 *be = (endianchar == 'b');159 *bytes = padint / 8;160 if (*bits_used == 64)161 *mask = ~(0ULL);162 else163 *mask = (1ULL << *bits_used) - 1ULL;164 165 *is_signed = (signchar == 's');166 if (fclose(sysfsfp)) {167 ret = -errno;168 fprintf(stderr, "Failed to close %s\n",169 filename);170 goto error_free_filename;171 }172 173 sysfsfp = 0;174 free(filename);175 filename = 0;176 177 /*178 * Avoid having a more generic entry overwriting179 * the settings.180 */181 if (strcmp(builtname, ent->d_name) == 0)182 break;183 }184 185error_close_sysfsfp:186 if (sysfsfp)187 if (fclose(sysfsfp))188 perror("iioutils_get_type(): Failed to close file");189 190error_free_filename:191 if (filename)192 free(filename);193 194error_closedir:195 if (closedir(dp) == -1)196 perror("iioutils_get_type(): Failed to close directory");197 198error_free_builtname_generic:199 free(builtname_generic);200error_free_builtname:201 free(builtname);202error_free_scan_el_dir:203 free(scan_el_dir);204 205 return ret;206}207 208/**209 * iioutils_get_param_float() - read a float value from a channel parameter210 * @output: output the float value211 * @param_name: the parameter name to read212 * @device_dir: the IIO device directory in sysfs213 * @name: the channel name214 * @generic_name: the channel type name215 *216 * Returns a value >= 0 on success, otherwise a negative error code.217 **/218int iioutils_get_param_float(float *output, const char *param_name,219 const char *device_dir, const char *name,220 const char *generic_name)221{222 FILE *sysfsfp;223 int ret;224 DIR *dp;225 char *builtname, *builtname_generic;226 char *filename = NULL;227 const struct dirent *ent;228 229 ret = asprintf(&builtname, "%s_%s", name, param_name);230 if (ret < 0)231 return -ENOMEM;232 233 ret = asprintf(&builtname_generic,234 "%s_%s", generic_name, param_name);235 if (ret < 0) {236 ret = -ENOMEM;237 goto error_free_builtname;238 }239 240 dp = opendir(device_dir);241 if (!dp) {242 ret = -errno;243 goto error_free_builtname_generic;244 }245 246 ret = -ENOENT;247 while (ent = readdir(dp), ent)248 if ((strcmp(builtname, ent->d_name) == 0) ||249 (strcmp(builtname_generic, ent->d_name) == 0)) {250 ret = asprintf(&filename,251 "%s/%s", device_dir, ent->d_name);252 if (ret < 0) {253 ret = -ENOMEM;254 goto error_closedir;255 }256 257 sysfsfp = fopen(filename, "r");258 if (!sysfsfp) {259 ret = -errno;260 goto error_free_filename;261 }262 263 errno = 0;264 if (fscanf(sysfsfp, "%f", output) != 1)265 ret = errno ? -errno : -ENODATA;266 267 fclose(sysfsfp);268 break;269 }270error_free_filename:271 if (filename)272 free(filename);273 274error_closedir:275 if (closedir(dp) == -1)276 perror("iioutils_get_param_float(): Failed to close directory");277 278error_free_builtname_generic:279 free(builtname_generic);280error_free_builtname:281 free(builtname);282 283 return ret;284}285 286/**287 * bsort_channel_array_by_index() - sort the array in index order288 * @ci_array: the iio_channel_info array to be sorted289 * @cnt: the amount of array elements290 **/291 292void bsort_channel_array_by_index(struct iio_channel_info *ci_array, int cnt)293{294 struct iio_channel_info temp;295 int x, y;296 297 for (x = 0; x < cnt; x++)298 for (y = 0; y < (cnt - 1); y++)299 if (ci_array[y].index > ci_array[y + 1].index) {300 temp = ci_array[y + 1];301 ci_array[y + 1] = ci_array[y];302 ci_array[y] = temp;303 }304}305 306/**307 * build_channel_array() - function to figure out what channels are present308 * @device_dir: the IIO device directory in sysfs309 * @buffer_idx: the IIO buffer for this channel array310 * @ci_array: output the resulting array of iio_channel_info311 * @counter: output the amount of array elements312 *313 * Returns 0 on success, otherwise a negative error code.314 **/315int build_channel_array(const char *device_dir, int buffer_idx,316 struct iio_channel_info **ci_array, int *counter)317{318 DIR *dp;319 FILE *sysfsfp;320 int count = 0, i;321 struct iio_channel_info *current;322 int ret;323 const struct dirent *ent;324 char *scan_el_dir;325 char *filename;326 327 *counter = 0;328 ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir, buffer_idx);329 if (ret < 0)330 return -ENOMEM;331 332 dp = opendir(scan_el_dir);333 if (!dp) {334 ret = -errno;335 goto error_free_name;336 }337 338 while (ent = readdir(dp), ent)339 if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"),340 "_en") == 0) {341 ret = asprintf(&filename,342 "%s/%s", scan_el_dir, ent->d_name);343 if (ret < 0) {344 ret = -ENOMEM;345 goto error_close_dir;346 }347 348 sysfsfp = fopen(filename, "r");349 free(filename);350 if (!sysfsfp) {351 ret = -errno;352 goto error_close_dir;353 }354 355 errno = 0;356 if (fscanf(sysfsfp, "%i", &ret) != 1) {357 ret = errno ? -errno : -ENODATA;358 if (fclose(sysfsfp))359 perror("build_channel_array(): Failed to close file");360 361 goto error_close_dir;362 }363 if (ret == 1)364 (*counter)++;365 366 if (fclose(sysfsfp)) {367 ret = -errno;368 goto error_close_dir;369 }370 371 }372 373 *ci_array = malloc(sizeof(**ci_array) * (*counter));374 if (!*ci_array) {375 ret = -ENOMEM;376 goto error_close_dir;377 }378 379 rewinddir(dp);380 while (ent = readdir(dp), ent) {381 if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"),382 "_en") == 0) {383 int current_enabled = 0;384 385 current = &(*ci_array)[count++];386 ret = asprintf(&filename,387 "%s/%s", scan_el_dir, ent->d_name);388 if (ret < 0) {389 ret = -ENOMEM;390 /* decrement count to avoid freeing name */391 count--;392 goto error_cleanup_array;393 }394 395 sysfsfp = fopen(filename, "r");396 free(filename);397 if (!sysfsfp) {398 ret = -errno;399 count--;400 goto error_cleanup_array;401 }402 403 errno = 0;404 if (fscanf(sysfsfp, "%i", ¤t_enabled) != 1) {405 ret = errno ? -errno : -ENODATA;406 count--;407 goto error_cleanup_array;408 }409 410 if (fclose(sysfsfp)) {411 ret = -errno;412 count--;413 goto error_cleanup_array;414 }415 416 if (!current_enabled) {417 count--;418 continue;419 }420 421 current->scale = 1.0;422 current->offset = 0;423 current->name = strndup(ent->d_name,424 strlen(ent->d_name) -425 strlen("_en"));426 if (!current->name) {427 ret = -ENOMEM;428 count--;429 goto error_cleanup_array;430 }431 432 /* Get the generic and specific name elements */433 ret = iioutils_break_up_name(current->name,434 ¤t->generic_name);435 if (ret) {436 free(current->name);437 count--;438 goto error_cleanup_array;439 }440 441 ret = asprintf(&filename,442 "%s/%s_index",443 scan_el_dir,444 current->name);445 if (ret < 0) {446 ret = -ENOMEM;447 goto error_cleanup_array;448 }449 450 sysfsfp = fopen(filename, "r");451 free(filename);452 if (!sysfsfp) {453 ret = -errno;454 fprintf(stderr, "failed to open %s/%s_index\n",455 scan_el_dir, current->name);456 goto error_cleanup_array;457 }458 459 errno = 0;460 if (fscanf(sysfsfp, "%u", ¤t->index) != 1) {461 ret = errno ? -errno : -ENODATA;462 if (fclose(sysfsfp))463 perror("build_channel_array(): Failed to close file");464 465 goto error_cleanup_array;466 }467 468 if (fclose(sysfsfp)) {469 ret = -errno;470 goto error_cleanup_array;471 }472 473 /* Find the scale */474 ret = iioutils_get_param_float(¤t->scale,475 "scale",476 device_dir,477 current->name,478 current->generic_name);479 if ((ret < 0) && (ret != -ENOENT))480 goto error_cleanup_array;481 482 ret = iioutils_get_param_float(¤t->offset,483 "offset",484 device_dir,485 current->name,486 current->generic_name);487 if ((ret < 0) && (ret != -ENOENT))488 goto error_cleanup_array;489 490 ret = iioutils_get_type(¤t->is_signed,491 ¤t->bytes,492 ¤t->bits_used,493 ¤t->shift,494 ¤t->mask,495 ¤t->be,496 device_dir,497 buffer_idx,498 current->name,499 current->generic_name);500 if (ret < 0)501 goto error_cleanup_array;502 }503 }504 505 if (closedir(dp) == -1) {506 ret = -errno;507 goto error_cleanup_array;508 }509 510 free(scan_el_dir);511 /* reorder so that the array is in index order */512 bsort_channel_array_by_index(*ci_array, *counter);513 514 return 0;515 516error_cleanup_array:517 for (i = count - 1; i >= 0; i--) {518 free((*ci_array)[i].name);519 free((*ci_array)[i].generic_name);520 }521 free(*ci_array);522 *ci_array = NULL;523 *counter = 0;524error_close_dir:525 if (dp)526 if (closedir(dp) == -1)527 perror("build_channel_array(): Failed to close dir");528 529error_free_name:530 free(scan_el_dir);531 532 return ret;533}534 535static int calc_digits(int num)536{537 int count = 0;538 539 /* It takes a digit to represent zero */540 if (!num)541 return 1;542 543 while (num != 0) {544 num /= 10;545 count++;546 }547 548 return count;549}550 551/**552 * find_type_by_name() - function to match top level types by name553 * @name: top level type instance name554 * @type: the type of top level instance being searched555 *556 * Returns the device number of a matched IIO device on success, otherwise a557 * negative error code.558 * Typical types this is used for are device and trigger.559 **/560int find_type_by_name(const char *name, const char *type)561{562 const struct dirent *ent;563 int number, numstrlen, ret;564 565 FILE *namefp;566 DIR *dp;567 char thisname[IIO_MAX_NAME_LENGTH];568 char *filename;569 570 dp = opendir(iio_dir);571 if (!dp) {572 fprintf(stderr, "No industrialio devices available\n");573 return -ENODEV;574 }575 576 while (ent = readdir(dp), ent) {577 if (strcmp(ent->d_name, ".") != 0 &&578 strcmp(ent->d_name, "..") != 0 &&579 strlen(ent->d_name) > strlen(type) &&580 strncmp(ent->d_name, type, strlen(type)) == 0) {581 errno = 0;582 ret = sscanf(ent->d_name + strlen(type), "%d", &number);583 if (ret < 0) {584 ret = -errno;585 fprintf(stderr,586 "failed to read element number\n");587 goto error_close_dir;588 } else if (ret != 1) {589 ret = -EIO;590 fprintf(stderr,591 "failed to match element number\n");592 goto error_close_dir;593 }594 595 numstrlen = calc_digits(number);596 /* verify the next character is not a colon */597 if (strncmp(ent->d_name + strlen(type) + numstrlen,598 ":", 1) != 0) {599 filename = malloc(strlen(iio_dir) + strlen(type)600 + numstrlen + 6);601 if (!filename) {602 ret = -ENOMEM;603 goto error_close_dir;604 }605 606 ret = sprintf(filename, "%s%s%d/name", iio_dir,607 type, number);608 if (ret < 0) {609 free(filename);610 goto error_close_dir;611 }612 613 namefp = fopen(filename, "r");614 if (!namefp) {615 free(filename);616 continue;617 }618 619 free(filename);620 errno = 0;621 if (fscanf(namefp, "%s", thisname) != 1) {622 ret = errno ? -errno : -ENODATA;623 goto error_close_dir;624 }625 626 if (fclose(namefp)) {627 ret = -errno;628 goto error_close_dir;629 }630 631 if (strcmp(name, thisname) == 0) {632 if (closedir(dp) == -1)633 return -errno;634 635 return number;636 }637 }638 }639 }640 if (closedir(dp) == -1)641 return -errno;642 643 return -ENODEV;644 645error_close_dir:646 if (closedir(dp) == -1)647 perror("find_type_by_name(): Failed to close directory");648 649 return ret;650}651 652static int _write_sysfs_int(const char *filename, const char *basedir, int val,653 int verify)654{655 int ret = 0;656 FILE *sysfsfp;657 int test;658 char *temp = malloc(strlen(basedir) + strlen(filename) + 2);659 660 if (!temp)661 return -ENOMEM;662 663 ret = sprintf(temp, "%s/%s", basedir, filename);664 if (ret < 0)665 goto error_free;666 667 sysfsfp = fopen(temp, "w");668 if (!sysfsfp) {669 ret = -errno;670 fprintf(stderr, "failed to open %s\n", temp);671 goto error_free;672 }673 674 ret = fprintf(sysfsfp, "%d", val);675 if (ret < 0) {676 if (fclose(sysfsfp))677 perror("_write_sysfs_int(): Failed to close dir");678 679 goto error_free;680 }681 682 if (fclose(sysfsfp)) {683 ret = -errno;684 goto error_free;685 }686 687 if (verify) {688 sysfsfp = fopen(temp, "r");689 if (!sysfsfp) {690 ret = -errno;691 fprintf(stderr, "failed to open %s\n", temp);692 goto error_free;693 }694 695 if (fscanf(sysfsfp, "%d", &test) != 1) {696 ret = errno ? -errno : -ENODATA;697 if (fclose(sysfsfp))698 perror("_write_sysfs_int(): Failed to close dir");699 700 goto error_free;701 }702 703 if (fclose(sysfsfp)) {704 ret = -errno;705 goto error_free;706 }707 708 if (test != val) {709 fprintf(stderr,710 "Possible failure in int write %d to %s/%s\n",711 val, basedir, filename);712 ret = -1;713 }714 }715 716error_free:717 free(temp);718 return ret;719}720 721/**722 * write_sysfs_int() - write an integer value to a sysfs file723 * @filename: name of the file to write to724 * @basedir: the sysfs directory in which the file is to be found725 * @val: integer value to write to file726 *727 * Returns a value >= 0 on success, otherwise a negative error code.728 **/729int write_sysfs_int(const char *filename, const char *basedir, int val)730{731 return _write_sysfs_int(filename, basedir, val, 0);732}733 734/**735 * write_sysfs_int_and_verify() - write an integer value to a sysfs file736 * and verify737 * @filename: name of the file to write to738 * @basedir: the sysfs directory in which the file is to be found739 * @val: integer value to write to file740 *741 * Returns a value >= 0 on success, otherwise a negative error code.742 **/743int write_sysfs_int_and_verify(const char *filename, const char *basedir,744 int val)745{746 return _write_sysfs_int(filename, basedir, val, 1);747}748 749static int _write_sysfs_string(const char *filename, const char *basedir,750 const char *val, int verify)751{752 int ret = 0;753 FILE *sysfsfp;754 char *temp = malloc(strlen(basedir) + strlen(filename) + 2);755 756 if (!temp) {757 fprintf(stderr, "Memory allocation failed\n");758 return -ENOMEM;759 }760 761 ret = sprintf(temp, "%s/%s", basedir, filename);762 if (ret < 0)763 goto error_free;764 765 sysfsfp = fopen(temp, "w");766 if (!sysfsfp) {767 ret = -errno;768 fprintf(stderr, "Could not open %s\n", temp);769 goto error_free;770 }771 772 ret = fprintf(sysfsfp, "%s", val);773 if (ret < 0) {774 if (fclose(sysfsfp))775 perror("_write_sysfs_string(): Failed to close dir");776 777 goto error_free;778 }779 780 if (fclose(sysfsfp)) {781 ret = -errno;782 goto error_free;783 }784 785 if (verify) {786 sysfsfp = fopen(temp, "r");787 if (!sysfsfp) {788 ret = -errno;789 fprintf(stderr, "Could not open file to verify\n");790 goto error_free;791 }792 793 if (fscanf(sysfsfp, "%s", temp) != 1) {794 ret = errno ? -errno : -ENODATA;795 if (fclose(sysfsfp))796 perror("_write_sysfs_string(): Failed to close dir");797 798 goto error_free;799 }800 801 if (fclose(sysfsfp)) {802 ret = -errno;803 goto error_free;804 }805 806 if (strcmp(temp, val) != 0) {807 fprintf(stderr,808 "Possible failure in string write of %s "809 "Should be %s written to %s/%s\n", temp, val,810 basedir, filename);811 ret = -1;812 }813 }814 815error_free:816 free(temp);817 818 return ret;819}820 821/**822 * write_sysfs_string_and_verify() - string write, readback and verify823 * @filename: name of file to write to824 * @basedir: the sysfs directory in which the file is to be found825 * @val: the string to write826 *827 * Returns a value >= 0 on success, otherwise a negative error code.828 **/829int write_sysfs_string_and_verify(const char *filename, const char *basedir,830 const char *val)831{832 return _write_sysfs_string(filename, basedir, val, 1);833}834 835/**836 * write_sysfs_string() - write string to a sysfs file837 * @filename: name of file to write to838 * @basedir: the sysfs directory in which the file is to be found839 * @val: the string to write840 *841 * Returns a value >= 0 on success, otherwise a negative error code.842 **/843int write_sysfs_string(const char *filename, const char *basedir,844 const char *val)845{846 return _write_sysfs_string(filename, basedir, val, 0);847}848 849/**850 * read_sysfs_posint() - read an integer value from file851 * @filename: name of file to read from852 * @basedir: the sysfs directory in which the file is to be found853 *854 * Returns the read integer value >= 0 on success, otherwise a negative error855 * code.856 **/857int read_sysfs_posint(const char *filename, const char *basedir)858{859 int ret;860 FILE *sysfsfp;861 char *temp = malloc(strlen(basedir) + strlen(filename) + 2);862 863 if (!temp) {864 fprintf(stderr, "Memory allocation failed");865 return -ENOMEM;866 }867 868 ret = sprintf(temp, "%s/%s", basedir, filename);869 if (ret < 0)870 goto error_free;871 872 sysfsfp = fopen(temp, "r");873 if (!sysfsfp) {874 ret = -errno;875 goto error_free;876 }877 878 errno = 0;879 if (fscanf(sysfsfp, "%d\n", &ret) != 1) {880 ret = errno ? -errno : -ENODATA;881 if (fclose(sysfsfp))882 perror("read_sysfs_posint(): Failed to close dir");883 884 goto error_free;885 }886 887 if (fclose(sysfsfp))888 ret = -errno;889 890error_free:891 free(temp);892 893 return ret;894}895 896/**897 * read_sysfs_float() - read a float value from file898 * @filename: name of file to read from899 * @basedir: the sysfs directory in which the file is to be found900 * @val: output the read float value901 *902 * Returns a value >= 0 on success, otherwise a negative error code.903 **/904int read_sysfs_float(const char *filename, const char *basedir, float *val)905{906 int ret = 0;907 FILE *sysfsfp;908 char *temp = malloc(strlen(basedir) + strlen(filename) + 2);909 910 if (!temp) {911 fprintf(stderr, "Memory allocation failed");912 return -ENOMEM;913 }914 915 ret = sprintf(temp, "%s/%s", basedir, filename);916 if (ret < 0)917 goto error_free;918 919 sysfsfp = fopen(temp, "r");920 if (!sysfsfp) {921 ret = -errno;922 goto error_free;923 }924 925 errno = 0;926 if (fscanf(sysfsfp, "%f\n", val) != 1) {927 ret = errno ? -errno : -ENODATA;928 if (fclose(sysfsfp))929 perror("read_sysfs_float(): Failed to close dir");930 931 goto error_free;932 }933 934 if (fclose(sysfsfp))935 ret = -errno;936 937error_free:938 free(temp);939 940 return ret;941}942 943/**944 * read_sysfs_string() - read a string from file945 * @filename: name of file to read from946 * @basedir: the sysfs directory in which the file is to be found947 * @str: output the read string948 *949 * Returns a value >= 0 on success, otherwise a negative error code.950 **/951int read_sysfs_string(const char *filename, const char *basedir, char *str)952{953 int ret = 0;954 FILE *sysfsfp;955 char *temp = malloc(strlen(basedir) + strlen(filename) + 2);956 957 if (!temp) {958 fprintf(stderr, "Memory allocation failed");959 return -ENOMEM;960 }961 962 ret = sprintf(temp, "%s/%s", basedir, filename);963 if (ret < 0)964 goto error_free;965 966 sysfsfp = fopen(temp, "r");967 if (!sysfsfp) {968 ret = -errno;969 goto error_free;970 }971 972 errno = 0;973 if (fscanf(sysfsfp, "%s\n", str) != 1) {974 ret = errno ? -errno : -ENODATA;975 if (fclose(sysfsfp))976 perror("read_sysfs_string(): Failed to close dir");977 978 goto error_free;979 }980 981 if (fclose(sysfsfp))982 ret = -errno;983 984error_free:985 free(temp);986 987 return ret;988}989