1// SPDX-License-Identifier: GPL-2.0-only
2/* IIO - useful set of util functionality
3 *
4 * Copyright (c) 2008 Jonathan Cameron
5 */
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 name
24 * @full_name: the full channel name
25 * @generic_name: the output generic channel name
26 *
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 data
73 * @is_signed: output whether channel is signed
74 * @bytes: output how many bytes the channel storage occupies
75 * @bits_used: output number of valid bits of data
76 * @shift: output amount of bits to shift right data before applying bit mask
77 * @mask: output a bit mask for the raw data
78 * @be: output if data in big endian
79 * @device_dir: the IIO device directory
80 * @buffer_idx: the IIO buffer index
81 * @name: the channel name
82 * @generic_name: the channel type name
83 *
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			else
163				*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 overwriting
179			 * 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 parameter
210 * @output: output the float value
211 * @param_name: the parameter name to read
212 * @device_dir: the IIO device directory in sysfs
213 * @name: the channel name
214 * @generic_name: the channel type name
215 *
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 order
288 * @ci_array: the iio_channel_info array to be sorted
289 * @cnt: the amount of array elements
290 **/
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 present
308 * @device_dir: the IIO device directory in sysfs
309 * @buffer_idx: the IIO buffer for this channel array
310 * @ci_array: output the resulting array of iio_channel_info
311 * @counter: output the amount of array elements
312 *
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 name
553 * @name: top level type instance name
554 * @type: the type of top level instance being searched
555 *
556 * Returns the device number of a matched IIO device on success, otherwise a
557 * 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 file
723 * @filename: name of the file to write to
724 * @basedir: the sysfs directory in which the file is to be found
725 * @val: integer value to write to file
726 *
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 file
736 *				  and verify
737 * @filename: name of the file to write to
738 * @basedir: the sysfs directory in which the file is to be found
739 * @val: integer value to write to file
740 *
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 verify
823 * @filename: name of file to write to
824 * @basedir: the sysfs directory in which the file is to be found
825 * @val: the string to write
826 *
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 file
837 * @filename: name of file to write to
838 * @basedir: the sysfs directory in which the file is to be found
839 * @val: the string to write
840 *
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 file
851 * @filename: name of file to read from
852 * @basedir: the sysfs directory in which the file is to be found
853 *
854 * Returns the read integer value >= 0 on success, otherwise a negative error
855 * 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 file
898 * @filename: name of file to read from
899 * @basedir: the sysfs directory in which the file is to be found
900 * @val: output the read float value
901 *
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 file
945 * @filename: name of file to read from
946 * @basedir: the sysfs directory in which the file is to be found
947 * @str: output the read string
948 *
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