]> Pileus Git - ~andy/linux/blob - drivers/staging/iio/Documentation/iio_utils.h
UBI: fix some use after free bugs
[~andy/linux] / drivers / staging / iio / Documentation / iio_utils.h
1 /* IIO - useful set of util functionality
2  *
3  * Copyright (c) 2008 Jonathan Cameron
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 as published by
7  * the Free Software Foundation.
8  */
9
10 #include <string.h>
11 #include <stdlib.h>
12 #include <ctype.h>
13 #include <stdio.h>
14 #include <stdint.h>
15 #include <dirent.h>
16 #include <errno.h>
17
18 /* Made up value to limit allocation sizes */
19 #define IIO_MAX_NAME_LENGTH 30
20
21 #define FORMAT_SCAN_ELEMENTS_DIR "%s/scan_elements"
22 #define FORMAT_TYPE_FILE "%s_type"
23
24 const char *iio_dir = "/sys/bus/iio/devices/";
25
26 /**
27  * iioutils_break_up_name() - extract generic name from full channel name
28  * @full_name: the full channel name
29  * @generic_name: the output generic channel name
30  **/
31 inline int iioutils_break_up_name(const char *full_name,
32                                   char **generic_name)
33 {
34         char *current;
35         char *w, *r;
36         char *working;
37         current = strdup(full_name);
38         working = strtok(current, "_\0");
39         w = working;
40         r = working;
41
42         while (*r != '\0') {
43                 if (!isdigit(*r)) {
44                         *w = *r;
45                         w++;
46                 }
47                 r++;
48         }
49         *w = '\0';
50         *generic_name = strdup(working);
51         free(current);
52
53         return 0;
54 }
55
56 /**
57  * struct iio_channel_info - information about a given channel
58  * @name: channel name
59  * @generic_name: general name for channel type
60  * @scale: scale factor to be applied for conversion to si units
61  * @offset: offset to be applied for conversion to si units
62  * @index: the channel index in the buffer output
63  * @bytes: number of bytes occupied in buffer output
64  * @mask: a bit mask for the raw output
65  * @is_signed: is the raw value stored signed
66  * @enabled: is this channel enabled
67  **/
68 struct iio_channel_info {
69         char *name;
70         char *generic_name;
71         float scale;
72         float offset;
73         unsigned index;
74         unsigned bytes;
75         unsigned bits_used;
76         unsigned shift;
77         uint64_t mask;
78         unsigned be;
79         unsigned is_signed;
80         unsigned enabled;
81         unsigned location;
82 };
83
84 /**
85  * iioutils_get_type() - find and process _type attribute data
86  * @is_signed: output whether channel is signed
87  * @bytes: output how many bytes the channel storage occupies
88  * @mask: output a bit mask for the raw data
89  * @be: big endian
90  * @device_dir: the iio device directory
91  * @name: the channel name
92  * @generic_name: the channel type name
93  **/
94 inline int iioutils_get_type(unsigned *is_signed,
95                              unsigned *bytes,
96                              unsigned *bits_used,
97                              unsigned *shift,
98                              uint64_t *mask,
99                              unsigned *be,
100                              const char *device_dir,
101                              const char *name,
102                              const char *generic_name)
103 {
104         FILE *sysfsfp;
105         int ret;
106         DIR *dp;
107         char *scan_el_dir, *builtname, *builtname_generic, *filename = 0;
108         char signchar, endianchar;
109         unsigned padint;
110         const struct dirent *ent;
111
112         ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir);
113         if (ret < 0) {
114                 ret = -ENOMEM;
115                 goto error_ret;
116         }
117         ret = asprintf(&builtname, FORMAT_TYPE_FILE, name);
118         if (ret < 0) {
119                 ret = -ENOMEM;
120                 goto error_free_scan_el_dir;
121         }
122         ret = asprintf(&builtname_generic, FORMAT_TYPE_FILE, generic_name);
123         if (ret < 0) {
124                 ret = -ENOMEM;
125                 goto error_free_builtname;
126         }
127
128         dp = opendir(scan_el_dir);
129         if (dp == NULL) {
130                 ret = -errno;
131                 goto error_free_builtname_generic;
132         }
133         while (ent = readdir(dp), ent != NULL)
134                 /*
135                  * Do we allow devices to override a generic name with
136                  * a specific one?
137                  */
138                 if ((strcmp(builtname, ent->d_name) == 0) ||
139                     (strcmp(builtname_generic, ent->d_name) == 0)) {
140                         ret = asprintf(&filename,
141                                        "%s/%s", scan_el_dir, ent->d_name);
142                         if (ret < 0) {
143                                 ret = -ENOMEM;
144                                 goto error_closedir;
145                         }
146                         sysfsfp = fopen(filename, "r");
147                         if (sysfsfp == NULL) {
148                                 printf("failed to open %s\n", filename);
149                                 ret = -errno;
150                                 goto error_free_filename;
151                         }
152
153                         ret = fscanf(sysfsfp,
154                                      "%ce:%c%u/%u>>%u",
155                                      &endianchar,
156                                      &signchar,
157                                      bits_used,
158                                      &padint, shift);
159                         if (ret < 0) {
160                                 printf("failed to pass scan type description\n");
161                                 ret = -errno;
162                                 goto error_close_sysfsfp;
163                         }
164                         *be = (endianchar == 'b');
165                         *bytes = padint / 8;
166                         if (*bits_used == 64)
167                                 *mask = ~0;
168                         else
169                                 *mask = (1 << *bits_used) - 1;
170                         if (signchar == 's')
171                                 *is_signed = 1;
172                         else
173                                 *is_signed = 0;
174                         fclose(sysfsfp);
175                         free(filename);
176
177                         filename = 0;
178                         sysfsfp = 0;
179                 }
180 error_close_sysfsfp:
181         if (sysfsfp)
182                 fclose(sysfsfp);
183 error_free_filename:
184         if (filename)
185                 free(filename);
186 error_closedir:
187         closedir(dp);
188 error_free_builtname_generic:
189         free(builtname_generic);
190 error_free_builtname:
191         free(builtname);
192 error_free_scan_el_dir:
193         free(scan_el_dir);
194 error_ret:
195         return ret;
196 }
197
198 inline int iioutils_get_param_float(float *output,
199                                     const char *param_name,
200                                     const char *device_dir,
201                                     const char *name,
202                                     const char *generic_name)
203 {
204         FILE *sysfsfp;
205         int ret;
206         DIR *dp;
207         char *builtname, *builtname_generic;
208         char *filename = NULL;
209         const struct dirent *ent;
210
211         ret = asprintf(&builtname, "%s_%s", name, param_name);
212         if (ret < 0) {
213                 ret = -ENOMEM;
214                 goto error_ret;
215         }
216         ret = asprintf(&builtname_generic,
217                        "%s_%s", generic_name, param_name);
218         if (ret < 0) {
219                 ret = -ENOMEM;
220                 goto error_free_builtname;
221         }
222         dp = opendir(device_dir);
223         if (dp == NULL) {
224                 ret = -errno;
225                 goto error_free_builtname_generic;
226         }
227         while (ent = readdir(dp), ent != NULL)
228                 if ((strcmp(builtname, ent->d_name) == 0) ||
229                     (strcmp(builtname_generic, ent->d_name) == 0)) {
230                         ret = asprintf(&filename,
231                                        "%s/%s", device_dir, ent->d_name);
232                         if (ret < 0) {
233                                 ret = -ENOMEM;
234                                 goto error_closedir;
235                         }
236                         sysfsfp = fopen(filename, "r");
237                         if (!sysfsfp) {
238                                 ret = -errno;
239                                 goto error_free_filename;
240                         }
241                         fscanf(sysfsfp, "%f", output);
242                         break;
243                 }
244 error_free_filename:
245         if (filename)
246                 free(filename);
247 error_closedir:
248         closedir(dp);
249 error_free_builtname_generic:
250         free(builtname_generic);
251 error_free_builtname:
252         free(builtname);
253 error_ret:
254         return ret;
255 }
256
257 /**
258  * bsort_channel_array_by_index() - reorder so that the array is in index order
259  *
260  **/
261
262 inline void bsort_channel_array_by_index(struct iio_channel_info **ci_array,
263                                          int cnt)
264 {
265
266         struct iio_channel_info temp;
267         int x, y;
268
269         for (x = 0; x < cnt; x++)
270                 for (y = 0; y < (cnt - 1); y++)
271                         if ((*ci_array)[y].index > (*ci_array)[y+1].index) {
272                                 temp = (*ci_array)[y + 1];
273                                 (*ci_array)[y + 1] = (*ci_array)[y];
274                                 (*ci_array)[y] = temp;
275                         }
276 }
277
278 /**
279  * build_channel_array() - function to figure out what channels are present
280  * @device_dir: the IIO device directory in sysfs
281  * @
282  **/
283 inline int build_channel_array(const char *device_dir,
284                               struct iio_channel_info **ci_array,
285                               int *counter)
286 {
287         DIR *dp;
288         FILE *sysfsfp;
289         int count, i;
290         struct iio_channel_info *current;
291         int ret;
292         const struct dirent *ent;
293         char *scan_el_dir;
294         char *filename;
295
296         *counter = 0;
297         ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir);
298         if (ret < 0) {
299                 ret = -ENOMEM;
300                 goto error_ret;
301         }
302         dp = opendir(scan_el_dir);
303         if (dp == NULL) {
304                 ret = -errno;
305                 goto error_free_name;
306         }
307         while (ent = readdir(dp), ent != NULL)
308                 if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"),
309                            "_en") == 0) {
310                         ret = asprintf(&filename,
311                                        "%s/%s", scan_el_dir, ent->d_name);
312                         if (ret < 0) {
313                                 ret = -ENOMEM;
314                                 goto error_close_dir;
315                         }
316                         sysfsfp = fopen(filename, "r");
317                         if (sysfsfp == NULL) {
318                                 ret = -errno;
319                                 free(filename);
320                                 goto error_close_dir;
321                         }
322                         fscanf(sysfsfp, "%u", &ret);
323                         if (ret == 1)
324                                 (*counter)++;
325                         fclose(sysfsfp);
326                         free(filename);
327                 }
328         *ci_array = malloc(sizeof(**ci_array) * (*counter));
329         if (*ci_array == NULL) {
330                 ret = -ENOMEM;
331                 goto error_close_dir;
332         }
333         seekdir(dp, 0);
334         count = 0;
335         while (ent = readdir(dp), ent != NULL) {
336                 if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"),
337                            "_en") == 0) {
338                         current = &(*ci_array)[count++];
339                         ret = asprintf(&filename,
340                                        "%s/%s", scan_el_dir, ent->d_name);
341                         if (ret < 0) {
342                                 ret = -ENOMEM;
343                                 /* decrement count to avoid freeing name */
344                                 count--;
345                                 goto error_cleanup_array;
346                         }
347                         sysfsfp = fopen(filename, "r");
348                         if (sysfsfp == NULL) {
349                                 free(filename);
350                                 ret = -errno;
351                                 goto error_cleanup_array;
352                         }
353                         fscanf(sysfsfp, "%u", &current->enabled);
354                         fclose(sysfsfp);
355
356                         if (!current->enabled) {
357                                 free(filename);
358                                 count--;
359                                 continue;
360                         }
361
362                         current->scale = 1.0;
363                         current->offset = 0;
364                         current->name = strndup(ent->d_name,
365                                                 strlen(ent->d_name) -
366                                                 strlen("_en"));
367                         if (current->name == NULL) {
368                                 free(filename);
369                                 ret = -ENOMEM;
370                                 goto error_cleanup_array;
371                         }
372                         /* Get the generic and specific name elements */
373                         ret = iioutils_break_up_name(current->name,
374                                                      &current->generic_name);
375                         if (ret) {
376                                 free(filename);
377                                 goto error_cleanup_array;
378                         }
379                         ret = asprintf(&filename,
380                                        "%s/%s_index",
381                                        scan_el_dir,
382                                        current->name);
383                         if (ret < 0) {
384                                 free(filename);
385                                 ret = -ENOMEM;
386                                 goto error_cleanup_array;
387                         }
388                         sysfsfp = fopen(filename, "r");
389                         fscanf(sysfsfp, "%u", &current->index);
390                         fclose(sysfsfp);
391                         free(filename);
392                         /* Find the scale */
393                         ret = iioutils_get_param_float(&current->scale,
394                                                        "scale",
395                                                        device_dir,
396                                                        current->name,
397                                                        current->generic_name);
398                         if (ret < 0)
399                                 goto error_cleanup_array;
400                         ret = iioutils_get_param_float(&current->offset,
401                                                        "offset",
402                                                        device_dir,
403                                                        current->name,
404                                                        current->generic_name);
405                         if (ret < 0)
406                                 goto error_cleanup_array;
407                         ret = iioutils_get_type(&current->is_signed,
408                                                 &current->bytes,
409                                                 &current->bits_used,
410                                                 &current->shift,
411                                                 &current->mask,
412                                                 &current->be,
413                                                 device_dir,
414                                                 current->name,
415                                                 current->generic_name);
416                 }
417         }
418
419         closedir(dp);
420         /* reorder so that the array is in index order */
421         bsort_channel_array_by_index(ci_array, *counter);
422
423         return 0;
424
425 error_cleanup_array:
426         for (i = count - 1;  i >= 0; i--)
427                 free((*ci_array)[i].name);
428         free(*ci_array);
429 error_close_dir:
430         closedir(dp);
431 error_free_name:
432         free(scan_el_dir);
433 error_ret:
434         return ret;
435 }
436
437 /**
438  * find_type_by_name() - function to match top level types by name
439  * @name: top level type instance name
440  * @type: the type of top level instance being sort
441  *
442  * Typical types this is used for are device and trigger.
443  **/
444 inline int find_type_by_name(const char *name, const char *type)
445 {
446         const struct dirent *ent;
447         int number, numstrlen;
448
449         FILE *nameFile;
450         DIR *dp;
451         char thisname[IIO_MAX_NAME_LENGTH];
452         char *filename;
453
454         dp = opendir(iio_dir);
455         if (dp == NULL) {
456                 printf("No industrialio devices available\n");
457                 return -ENODEV;
458         }
459
460         while (ent = readdir(dp), ent != NULL) {
461                 if (strcmp(ent->d_name, ".") != 0 &&
462                         strcmp(ent->d_name, "..") != 0 &&
463                         strlen(ent->d_name) > strlen(type) &&
464                         strncmp(ent->d_name, type, strlen(type)) == 0) {
465                         numstrlen = sscanf(ent->d_name + strlen(type),
466                                            "%d",
467                                            &number);
468                         /* verify the next character is not a colon */
469                         if (strncmp(ent->d_name + strlen(type) + numstrlen,
470                                         ":",
471                                         1) != 0) {
472                                 filename = malloc(strlen(iio_dir)
473                                                 + strlen(type)
474                                                 + numstrlen
475                                                 + 6);
476                                 if (filename == NULL) {
477                                         closedir(dp);
478                                         return -ENOMEM;
479                                 }
480                                 sprintf(filename, "%s%s%d/name",
481                                         iio_dir,
482                                         type,
483                                         number);
484                                 nameFile = fopen(filename, "r");
485                                 if (!nameFile) {
486                                         free(filename);
487                                         continue;
488                                 }
489                                 free(filename);
490                                 fscanf(nameFile, "%s", thisname);
491                                 fclose(nameFile);
492                                 if (strcmp(name, thisname) == 0) {
493                                         closedir(dp);
494                                         return number;
495                                 }
496                         }
497                 }
498         }
499         closedir(dp);
500         return -ENODEV;
501 }
502
503 inline int _write_sysfs_int(char *filename, char *basedir, int val, int verify)
504 {
505         int ret = 0;
506         FILE *sysfsfp;
507         int test;
508         char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
509         if (temp == NULL)
510                 return -ENOMEM;
511         sprintf(temp, "%s/%s", basedir, filename);
512         sysfsfp = fopen(temp, "w");
513         if (sysfsfp == NULL) {
514                 printf("failed to open %s\n", temp);
515                 ret = -errno;
516                 goto error_free;
517         }
518         fprintf(sysfsfp, "%d", val);
519         fclose(sysfsfp);
520         if (verify) {
521                 sysfsfp = fopen(temp, "r");
522                 if (sysfsfp == NULL) {
523                         printf("failed to open %s\n", temp);
524                         ret = -errno;
525                         goto error_free;
526                 }
527                 fscanf(sysfsfp, "%d", &test);
528                 fclose(sysfsfp);
529                 if (test != val) {
530                         printf("Possible failure in int write %d to %s%s\n",
531                                 val,
532                                 basedir,
533                                 filename);
534                         ret = -1;
535                 }
536         }
537 error_free:
538         free(temp);
539         return ret;
540 }
541
542 int write_sysfs_int(char *filename, char *basedir, int val)
543 {
544         return _write_sysfs_int(filename, basedir, val, 0);
545 }
546
547 int write_sysfs_int_and_verify(char *filename, char *basedir, int val)
548 {
549         return _write_sysfs_int(filename, basedir, val, 1);
550 }
551
552 int _write_sysfs_string(char *filename, char *basedir, char *val, int verify)
553 {
554         int ret = 0;
555         FILE  *sysfsfp;
556         char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
557         if (temp == NULL) {
558                 printf("Memory allocation failed\n");
559                 return -ENOMEM;
560         }
561         sprintf(temp, "%s/%s", basedir, filename);
562         sysfsfp = fopen(temp, "w");
563         if (sysfsfp == NULL) {
564                 printf("Could not open %s\n", temp);
565                 ret = -errno;
566                 goto error_free;
567         }
568         fprintf(sysfsfp, "%s", val);
569         fclose(sysfsfp);
570         if (verify) {
571                 sysfsfp = fopen(temp, "r");
572                 if (sysfsfp == NULL) {
573                         printf("could not open file to verify\n");
574                         ret = -errno;
575                         goto error_free;
576                 }
577                 fscanf(sysfsfp, "%s", temp);
578                 fclose(sysfsfp);
579                 if (strcmp(temp, val) != 0) {
580                         printf("Possible failure in string write of %s "
581                                 "Should be %s "
582                                 "written to %s\%s\n",
583                                 temp,
584                                 val,
585                                 basedir,
586                                 filename);
587                         ret = -1;
588                 }
589         }
590 error_free:
591         free(temp);
592
593         return ret;
594 }
595
596 /**
597  * write_sysfs_string_and_verify() - string write, readback and verify
598  * @filename: name of file to write to
599  * @basedir: the sysfs directory in which the file is to be found
600  * @val: the string to write
601  **/
602 int write_sysfs_string_and_verify(char *filename, char *basedir, char *val)
603 {
604         return _write_sysfs_string(filename, basedir, val, 1);
605 }
606
607 int write_sysfs_string(char *filename, char *basedir, char *val)
608 {
609         return _write_sysfs_string(filename, basedir, val, 0);
610 }
611
612 int read_sysfs_posint(char *filename, char *basedir)
613 {
614         int ret;
615         FILE  *sysfsfp;
616         char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
617         if (temp == NULL) {
618                 printf("Memory allocation failed");
619                 return -ENOMEM;
620         }
621         sprintf(temp, "%s/%s", basedir, filename);
622         sysfsfp = fopen(temp, "r");
623         if (sysfsfp == NULL) {
624                 ret = -errno;
625                 goto error_free;
626         }
627         fscanf(sysfsfp, "%d\n", &ret);
628         fclose(sysfsfp);
629 error_free:
630         free(temp);
631         return ret;
632 }
633
634 int read_sysfs_float(char *filename, char *basedir, float *val)
635 {
636         float ret = 0;
637         FILE  *sysfsfp;
638         char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
639         if (temp == NULL) {
640                 printf("Memory allocation failed");
641                 return -ENOMEM;
642         }
643         sprintf(temp, "%s/%s", basedir, filename);
644         sysfsfp = fopen(temp, "r");
645         if (sysfsfp == NULL) {
646                 ret = -errno;
647                 goto error_free;
648         }
649         fscanf(sysfsfp, "%f\n", val);
650         fclose(sysfsfp);
651 error_free:
652         free(temp);
653         return ret;
654 }