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