brintos

brintos / linux-shallow public Read only

0
0
Text · 21.3 KiB · c5c5082 Raw
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", &current_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						     &current->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", &current->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(&current->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(&current->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(&current->is_signed,491						&current->bytes,492						&current->bits_used,493						&current->shift,494						&current->mask,495						&current->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