diff options
author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2015-06-10 20:48:34 -0700 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2015-06-10 20:48:34 -0700 |
commit | 78a66b00d97c89a43b1ee753814913c55ec2e3ee (patch) | |
tree | e5cb4bcf3db64b0fb0f68c4578e4722397605b71 /tools/iio/iio_utils.c | |
parent | e703f23747e25db6ccc1f752f787925f86c27f31 (diff) | |
parent | bbf5f037fad47e4affef6696aaf88a40b261e639 (diff) |
Merge tag 'iio-for-v4.2c' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into staging-next
Jonathan writes:
Third round of new IIO drivers, cleanups and functionality for the 4.2 cycle.
Given Linus announced a 4.8rc coming up, hopefully time for one more
lot of IIO patches this cycle. Some of these are actually
improvements / fixes for patches earlier in the cycle.
New device support
* st_accel driver - support devices with 8 bit channels.
Cleanup
* A general cleanup of the iio tools under /tools/ from Hartmut.
I'm more than a little embarassed by how bad some of these were! Are well,
much more refined and less bug prone now.
These cover lots of stuff like unhandled error returns, memory leaks as
well as general refactoring to tidy the code up.
* iio_simple_dummy - fix memory leaks in the init functions, drop some
pointless error returns from functions that never generate errors and
make the module parameter explicitly unsigned.
* More buffer handling reworks from Lars-Peter, this time targetting hardware
buffers (a little used corner that looks likely to get more use in the near
future). Specifically:
- Always compute the masklength as inkernel buffer users may need it.
- Add a means of labeling which buffer modes a given buffer implementation
supports.
- In the case of hardware buffers, require strict scan matching rather than
matching to a superset. Currently the demux is bypassed by these drivers
(this may well not change for efficiency reasons) so allowing a superset
of channels to be selected would otherwise lead to more data than requested
confusing userspace.
Driver funcationality improvments
* mmc35240 - adds a compensation to the raw values as borrowed form Memsic's
own input driver.
* mma8452
- event support
- event debouncing
- high pass filter configuration
- triggers
* vf610 - allow conversion mode to be adjusted
Fixlets
* mmc35240
- Off by one error that by coincidence had no real effect.
- i2c_device_name should be lowercase.
- Lack of null terminator at end of attributes array.
- Avoid computing the fractional part of the magnetic field by moving
the scaling into userspace where floating point is available to simplify
the maths.
- Use a smaller sleep before assuming the measurement is done. This is
safe and improves the possible polling rate.
- Fix sensitivity on z-axis - datasheet disagrees with Memsic's releasedd
code and the value used in the code seems to be correct.
* stk3310 - make a local variable signed to ensure error handling works.
* twl4030
- fix calculation of the temperature sense current - bug unlikely
to have ever been noticed as the difference is small.
- Fix errors in descriptions.
Diffstat (limited to 'tools/iio/iio_utils.c')
-rw-r--r-- | tools/iio/iio_utils.c | 469 |
1 files changed, 381 insertions, 88 deletions
diff --git a/tools/iio/iio_utils.c b/tools/iio/iio_utils.c index 6f6452167b670..ec9ab7f9ae4c5 100644 --- a/tools/iio/iio_utils.c +++ b/tools/iio/iio_utils.c @@ -29,6 +29,8 @@ static char * const iio_direction[] = { * iioutils_break_up_name() - extract generic name from full channel name * @full_name: the full channel name * @generic_name: the output generic channel name + * + * Returns 0 on success, or a negative error code if string extraction failed. **/ int iioutils_break_up_name(const char *full_name, char **generic_name) @@ -36,7 +38,7 @@ int iioutils_break_up_name(const char *full_name, char *current; char *w, *r; char *working, *prefix = ""; - int i; + int i, ret; for (i = 0; i < sizeof(iio_direction) / sizeof(iio_direction[0]); i++) if (!strncmp(full_name, iio_direction[i], @@ -46,7 +48,14 @@ int iioutils_break_up_name(const char *full_name, } current = strdup(full_name + strlen(prefix) + 1); + if (!current) + return -ENOMEM; + working = strtok(current, "_\0"); + if (!working) { + free(current); + return -EINVAL; + } w = working; r = working; @@ -59,21 +68,25 @@ int iioutils_break_up_name(const char *full_name, r++; } *w = '\0'; - asprintf(generic_name, "%s_%s", prefix, working); + ret = asprintf(generic_name, "%s_%s", prefix, working); free(current); - return 0; + return (ret == -1) ? -ENOMEM : 0; } /** * iioutils_get_type() - find and process _type attribute data * @is_signed: output whether channel is signed * @bytes: output how many bytes the channel storage occupies + * @bits_used: output number of valid bits of data + * @shift: output amount of bits to shift right data before applying bit mask * @mask: output a bit mask for the raw data - * @be: big endian - * @device_dir: the iio device directory + * @be: output if data in big endian + * @device_dir: the IIO device directory * @name: the channel name * @generic_name: the channel type name + * + * Returns a value >= 0 on success, otherwise a negative error code. **/ int iioutils_get_type(unsigned *is_signed, unsigned *bytes, @@ -94,10 +107,9 @@ int iioutils_get_type(unsigned *is_signed, const struct dirent *ent; ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir); - if (ret < 0) { - ret = -ENOMEM; - goto error_ret; - } + if (ret < 0) + return -ENOMEM; + ret = asprintf(&builtname, FORMAT_TYPE_FILE, name); if (ret < 0) { ret = -ENOMEM; @@ -114,6 +126,7 @@ int iioutils_get_type(unsigned *is_signed, ret = -errno; goto error_free_builtname_generic; } + ret = -ENOENT; while (ent = readdir(dp), ent != NULL) /* * Do we allow devices to override a generic name with @@ -129,8 +142,8 @@ int iioutils_get_type(unsigned *is_signed, } sysfsfp = fopen(filename, "r"); if (sysfsfp == NULL) { - printf("failed to open %s\n", filename); ret = -errno; + printf("failed to open %s\n", filename); goto error_free_filename; } @@ -141,8 +154,12 @@ int iioutils_get_type(unsigned *is_signed, bits_used, &padint, shift); if (ret < 0) { - printf("failed to pass scan type description\n"); ret = -errno; + printf("failed to pass scan type description\n"); + goto error_close_sysfsfp; + } else if (ret != 5) { + ret = -EIO; + printf("scan type description didn't match\n"); goto error_close_sysfsfp; } *be = (endianchar == 'b'); @@ -151,34 +168,50 @@ int iioutils_get_type(unsigned *is_signed, *mask = ~0; else *mask = (1 << *bits_used) - 1; - if (signchar == 's') - *is_signed = 1; - else - *is_signed = 0; - fclose(sysfsfp); + *is_signed = (signchar == 's'); + if (fclose(sysfsfp)) { + ret = -errno; + printf("Failed to close %s\n", filename); + goto error_free_filename; + } + + sysfsfp = 0; free(filename); filename = 0; - sysfsfp = 0; } error_close_sysfsfp: if (sysfsfp) - fclose(sysfsfp); + if (fclose(sysfsfp)) + perror("iioutils_get_type(): Failed to close file"); + error_free_filename: if (filename) free(filename); error_closedir: - closedir(dp); + if (closedir(dp) == -1) + perror("iioutils_get_type(): Failed to close directory"); + error_free_builtname_generic: free(builtname_generic); error_free_builtname: free(builtname); error_free_scan_el_dir: free(scan_el_dir); -error_ret: + return ret; } +/** + * iioutils_get_param_float() - read a float value from a channel parameter + * @output: output the float value + * @param_name: the parameter name to read + * @device_dir: the IIO device directory in sysfs + * @name: the channel name + * @generic_name: the channel type name + * + * Returns a value >= 0 on success, otherwise a negative error code. + **/ int iioutils_get_param_float(float *output, const char *param_name, const char *device_dir, @@ -193,10 +226,9 @@ int iioutils_get_param_float(float *output, const struct dirent *ent; ret = asprintf(&builtname, "%s_%s", name, param_name); - if (ret < 0) { - ret = -ENOMEM; - goto error_ret; - } + if (ret < 0) + return -ENOMEM; + ret = asprintf(&builtname_generic, "%s_%s", generic_name, param_name); if (ret < 0) { @@ -208,6 +240,7 @@ int iioutils_get_param_float(float *output, ret = -errno; goto error_free_builtname_generic; } + ret = -ENOENT; while (ent = readdir(dp), ent != NULL) if ((strcmp(builtname, ent->d_name) == 0) || (strcmp(builtname_generic, ent->d_name) == 0)) { @@ -222,25 +255,31 @@ int iioutils_get_param_float(float *output, ret = -errno; goto error_free_filename; } - fscanf(sysfsfp, "%f", output); + errno = 0; + if (fscanf(sysfsfp, "%f", output) != 1) + ret = errno ? -errno : -ENODATA; + break; } error_free_filename: if (filename) free(filename); error_closedir: - closedir(dp); + if (closedir(dp) == -1) + perror("iioutils_get_param_float(): Failed to close directory"); + error_free_builtname_generic: free(builtname_generic); error_free_builtname: free(builtname); -error_ret: + return ret; } /** - * bsort_channel_array_by_index() - reorder so that the array is in index order - * + * bsort_channel_array_by_index() - sort the array in index order + * @ci_array: the iio_channel_info array to be sorted + * @cnt: the amount of array elements **/ void bsort_channel_array_by_index(struct iio_channel_info **ci_array, @@ -262,7 +301,10 @@ void bsort_channel_array_by_index(struct iio_channel_info **ci_array, /** * build_channel_array() - function to figure out what channels are present * @device_dir: the IIO device directory in sysfs - * @ + * @ci_array: output the resulting array of iio_channel_info + * @counter: output the amount of array elements + * + * Returns 0 on success, otherwise a negative error code. **/ int build_channel_array(const char *device_dir, struct iio_channel_info **ci_array, @@ -270,7 +312,7 @@ int build_channel_array(const char *device_dir, { DIR *dp; FILE *sysfsfp; - int count, i; + int count = 0, i; struct iio_channel_info *current; int ret; const struct dirent *ent; @@ -279,10 +321,9 @@ int build_channel_array(const char *device_dir, *counter = 0; ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir); - if (ret < 0) { - ret = -ENOMEM; - goto error_ret; - } + if (ret < 0) + return -ENOMEM; + dp = opendir(scan_el_dir); if (dp == NULL) { ret = -errno; @@ -303,10 +344,24 @@ int build_channel_array(const char *device_dir, free(filename); goto error_close_dir; } - fscanf(sysfsfp, "%i", &ret); + errno = 0; + if (fscanf(sysfsfp, "%i", &ret) != 1) { + ret = errno ? -errno : -ENODATA; + if (fclose(sysfsfp)) + perror("build_channel_array(): Failed to close file"); + + free(filename); + goto error_close_dir; + } + if (ret == 1) (*counter)++; - fclose(sysfsfp); + if (fclose(sysfsfp)) { + ret = -errno; + free(filename); + goto error_close_dir; + } + free(filename); } *ci_array = malloc(sizeof(**ci_array) * (*counter)); @@ -315,7 +370,6 @@ int build_channel_array(const char *device_dir, goto error_close_dir; } seekdir(dp, 0); - count = 0; while (ent = readdir(dp), ent != NULL) { if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"), "_en") == 0) { @@ -332,12 +386,25 @@ int build_channel_array(const char *device_dir, } sysfsfp = fopen(filename, "r"); if (sysfsfp == NULL) { + ret = -errno; free(filename); + count--; + goto error_cleanup_array; + } + errno = 0; + if (fscanf(sysfsfp, "%i", ¤t_enabled) != 1) { + ret = errno ? -errno : -ENODATA; + free(filename); + count--; + goto error_cleanup_array; + } + + if (fclose(sysfsfp)) { ret = -errno; + free(filename); + count--; goto error_cleanup_array; } - fscanf(sysfsfp, "%i", ¤t_enabled); - fclose(sysfsfp); if (!current_enabled) { free(filename); @@ -353,6 +420,7 @@ int build_channel_array(const char *device_dir, if (current->name == NULL) { free(filename); ret = -ENOMEM; + count--; goto error_cleanup_array; } /* Get the generic and specific name elements */ @@ -360,6 +428,8 @@ int build_channel_array(const char *device_dir, ¤t->generic_name); if (ret) { free(filename); + free(current->name); + count--; goto error_cleanup_array; } ret = asprintf(&filename, @@ -372,8 +442,29 @@ int build_channel_array(const char *device_dir, goto error_cleanup_array; } sysfsfp = fopen(filename, "r"); - fscanf(sysfsfp, "%u", ¤t->index); - fclose(sysfsfp); + if (sysfsfp == NULL) { + ret = -errno; + printf("failed to open %s\n", filename); + free(filename); + goto error_cleanup_array; + } + + errno = 0; + if (fscanf(sysfsfp, "%u", ¤t->index) != 1) { + ret = errno ? -errno : -ENODATA; + if (fclose(sysfsfp)) + perror("build_channel_array(): Failed to close file"); + + free(filename); + goto error_cleanup_array; + } + + if (fclose(sysfsfp)) { + ret = -errno; + free(filename); + goto error_cleanup_array; + } + free(filename); /* Find the scale */ ret = iioutils_get_param_float(¤t->scale, @@ -399,38 +490,64 @@ int build_channel_array(const char *device_dir, device_dir, current->name, current->generic_name); + if (ret < 0) + goto error_cleanup_array; } } - closedir(dp); + if (closedir(dp) == -1) { + ret = -errno; + goto error_cleanup_array; + } + + free(scan_el_dir); /* reorder so that the array is in index order */ bsort_channel_array_by_index(ci_array, *counter); return 0; error_cleanup_array: - for (i = count - 1; i >= 0; i--) + for (i = count - 1; i >= 0; i--) { free((*ci_array)[i].name); + free((*ci_array)[i].generic_name); + } free(*ci_array); error_close_dir: - closedir(dp); + if (dp) + if (closedir(dp) == -1) + perror("build_channel_array(): Failed to close dir"); + error_free_name: free(scan_el_dir); -error_ret: + return ret; } +int calc_digits(int num) +{ + int count = 0; + + while (num != 0) { + num /= 10; + count++; + } + + return count; +} + /** * find_type_by_name() - function to match top level types by name * @name: top level type instance name - * @type: the type of top level instance being sort + * @type: the type of top level instance being searched * + * Returns the device number of a matched IIO device on success, otherwise a + * negative error code. * Typical types this is used for are device and trigger. **/ int find_type_by_name(const char *name, const char *type) { const struct dirent *ent; - int number, numstrlen; + int number, numstrlen, ret; FILE *nameFile; DIR *dp; @@ -448,9 +565,19 @@ int find_type_by_name(const char *name, const char *type) strcmp(ent->d_name, "..") != 0 && strlen(ent->d_name) > strlen(type) && strncmp(ent->d_name, type, strlen(type)) == 0) { - numstrlen = sscanf(ent->d_name + strlen(type), - "%d", - &number); + errno = 0; + ret = sscanf(ent->d_name + strlen(type), "%d", &number); + if (ret < 0) { + ret = -errno; + printf("failed to read element number\n"); + goto error_close_dir; + } else if (ret != 1) { + ret = -EIO; + printf("failed to match element number\n"); + goto error_close_dir; + } + + numstrlen = calc_digits(number); /* verify the next character is not a colon */ if (strncmp(ent->d_name + strlen(type) + numstrlen, ":", @@ -460,33 +587,55 @@ int find_type_by_name(const char *name, const char *type) + numstrlen + 6); if (filename == NULL) { - closedir(dp); - return -ENOMEM; + ret = -ENOMEM; + goto error_close_dir; } - sprintf(filename, "%s%s%d/name", - iio_dir, - type, - number); + + ret = sprintf(filename, "%s%s%d/name", iio_dir, + type, number); + if (ret < 0) { + free(filename); + goto error_close_dir; + } + nameFile = fopen(filename, "r"); if (!nameFile) { free(filename); continue; } free(filename); - fscanf(nameFile, "%s", thisname); - fclose(nameFile); + errno = 0; + if (fscanf(nameFile, "%s", thisname) != 1) { + ret = errno ? -errno : -ENODATA; + goto error_close_dir; + } + + if (fclose(nameFile)) { + ret = -errno; + goto error_close_dir; + } + if (strcmp(name, thisname) == 0) { - closedir(dp); + if (closedir(dp) == -1) + return -errno; return number; } } } } - closedir(dp); + if (closedir(dp) == -1) + return -errno; + return -ENODEV; + +error_close_dir: + if (closedir(dp) == -1) + perror("find_type_by_name(): Failed to close directory"); + return ret; } -int _write_sysfs_int(char *filename, char *basedir, int val, int verify) +static int _write_sysfs_int(const char *filename, const char *basedir, int val, + int verify) { int ret = 0; FILE *sysfsfp; @@ -495,24 +644,49 @@ int _write_sysfs_int(char *filename, char *basedir, int val, int verify) if (temp == NULL) return -ENOMEM; - sprintf(temp, "%s/%s", basedir, filename); + ret = sprintf(temp, "%s/%s", basedir, filename); + if (ret < 0) + goto error_free; + sysfsfp = fopen(temp, "w"); if (sysfsfp == NULL) { + ret = -errno; printf("failed to open %s\n", temp); + goto error_free; + } + ret = fprintf(sysfsfp, "%d", val); + if (ret < 0) { + if (fclose(sysfsfp)) + perror("_write_sysfs_int(): Failed to close dir"); + + goto error_free; + } + + if (fclose(sysfsfp)) { ret = -errno; goto error_free; } - fprintf(sysfsfp, "%d", val); - fclose(sysfsfp); + if (verify) { sysfsfp = fopen(temp, "r"); if (sysfsfp == NULL) { + ret = -errno; printf("failed to open %s\n", temp); + goto error_free; + } + if (fscanf(sysfsfp, "%d", &test) != 1) { + ret = errno ? -errno : -ENODATA; + if (fclose(sysfsfp)) + perror("_write_sysfs_int(): Failed to close dir"); + + goto error_free; + } + + if (fclose(sysfsfp)) { ret = -errno; goto error_free; } - fscanf(sysfsfp, "%d", &test); - fclose(sysfsfp); + if (test != val) { printf("Possible failure in int write %d to %s%s\n", val, @@ -526,17 +700,36 @@ error_free: return ret; } -int write_sysfs_int(char *filename, char *basedir, int val) +/** + * write_sysfs_int() - write an integer value to a sysfs file + * @filename: name of the file to write to + * @basedir: the sysfs directory in which the file is to be found + * @val: integer value to write to file + * + * Returns a value >= 0 on success, otherwise a negative error code. + **/ +int write_sysfs_int(const char *filename, const char *basedir, int val) { return _write_sysfs_int(filename, basedir, val, 0); } -int write_sysfs_int_and_verify(char *filename, char *basedir, int val) +/** + * write_sysfs_int_and_verify() - write an integer value to a sysfs file + * and verify + * @filename: name of the file to write to + * @basedir: the sysfs directory in which the file is to be found + * @val: integer value to write to file + * + * Returns a value >= 0 on success, otherwise a negative error code. + **/ +int write_sysfs_int_and_verify(const char *filename, const char *basedir, + int val) { return _write_sysfs_int(filename, basedir, val, 1); } -int _write_sysfs_string(char *filename, char *basedir, char *val, int verify) +static int _write_sysfs_string(const char *filename, const char *basedir, + const char *val, int verify) { int ret = 0; FILE *sysfsfp; @@ -546,24 +739,49 @@ int _write_sysfs_string(char *filename, char *basedir, char *val, int verify) printf("Memory allocation failed\n"); return -ENOMEM; } - sprintf(temp, "%s/%s", basedir, filename); + ret = sprintf(temp, "%s/%s", basedir, filename); + if (ret < 0) + goto error_free; + sysfsfp = fopen(temp, "w"); if (sysfsfp == NULL) { + ret = -errno; printf("Could not open %s\n", temp); + goto error_free; + } + ret = fprintf(sysfsfp, "%s", val); + if (ret < 0) { + if (fclose(sysfsfp)) + perror("_write_sysfs_string(): Failed to close dir"); + + goto error_free; + } + + if (fclose(sysfsfp)) { ret = -errno; goto error_free; } - fprintf(sysfsfp, "%s", val); - fclose(sysfsfp); + if (verify) { sysfsfp = fopen(temp, "r"); if (sysfsfp == NULL) { + ret = -errno; printf("could not open file to verify\n"); + goto error_free; + } + if (fscanf(sysfsfp, "%s", temp) != 1) { + ret = errno ? -errno : -ENODATA; + if (fclose(sysfsfp)) + perror("_write_sysfs_string(): Failed to close dir"); + + goto error_free; + } + + if (fclose(sysfsfp)) { ret = -errno; goto error_free; } - fscanf(sysfsfp, "%s", temp); - fclose(sysfsfp); + if (strcmp(temp, val) != 0) { printf("Possible failure in string write of %s " "Should be %s " @@ -586,18 +804,38 @@ error_free: * @filename: name of file to write to * @basedir: the sysfs directory in which the file is to be found * @val: the string to write + * + * Returns a value >= 0 on success, otherwise a negative error code. **/ -int write_sysfs_string_and_verify(char *filename, char *basedir, char *val) +int write_sysfs_string_and_verify(const char *filename, const char *basedir, + const char *val) { return _write_sysfs_string(filename, basedir, val, 1); } -int write_sysfs_string(char *filename, char *basedir, char *val) +/** + * write_sysfs_string() - write string to a sysfs file + * @filename: name of file to write to + * @basedir: the sysfs directory in which the file is to be found + * @val: the string to write + * + * Returns a value >= 0 on success, otherwise a negative error code. + **/ +int write_sysfs_string(const char *filename, const char *basedir, + const char *val) { return _write_sysfs_string(filename, basedir, val, 0); } -int read_sysfs_posint(char *filename, char *basedir) +/** + * read_sysfs_posint() - read an integer value from file + * @filename: name of file to read from + * @basedir: the sysfs directory in which the file is to be found + * + * Returns the read integer value >= 0 on success, otherwise a negative error + * code. + **/ +int read_sysfs_posint(const char *filename, const char *basedir) { int ret; FILE *sysfsfp; @@ -607,20 +845,41 @@ int read_sysfs_posint(char *filename, char *basedir) printf("Memory allocation failed"); return -ENOMEM; } - sprintf(temp, "%s/%s", basedir, filename); + ret = sprintf(temp, "%s/%s", basedir, filename); + if (ret < 0) + goto error_free; + sysfsfp = fopen(temp, "r"); if (sysfsfp == NULL) { ret = -errno; goto error_free; } - fscanf(sysfsfp, "%d\n", &ret); - fclose(sysfsfp); + errno = 0; + if (fscanf(sysfsfp, "%d\n", &ret) != 1) { + ret = errno ? -errno : -ENODATA; + if (fclose(sysfsfp)) + perror("read_sysfs_posint(): Failed to close dir"); + + goto error_free; + } + + if (fclose(sysfsfp)) + ret = -errno; + error_free: free(temp); return ret; } -int read_sysfs_float(char *filename, char *basedir, float *val) +/** + * read_sysfs_float() - read a float value from file + * @filename: name of file to read from + * @basedir: the sysfs directory in which the file is to be found + * @val: output the read float value + * + * Returns a value >= 0 on success, otherwise a negative error code. + **/ +int read_sysfs_float(const char *filename, const char *basedir, float *val) { int ret = 0; FILE *sysfsfp; @@ -630,19 +889,40 @@ int read_sysfs_float(char *filename, char *basedir, float *val) printf("Memory allocation failed"); return -ENOMEM; } - sprintf(temp, "%s/%s", basedir, filename); + ret = sprintf(temp, "%s/%s", basedir, filename); + if (ret < 0) + goto error_free; + sysfsfp = fopen(temp, "r"); if (sysfsfp == NULL) { ret = -errno; goto error_free; } - fscanf(sysfsfp, "%f\n", val); - fclose(sysfsfp); + errno = 0; + if (fscanf(sysfsfp, "%f\n", val) != 1) { + ret = errno ? -errno : -ENODATA; + if (fclose(sysfsfp)) + perror("read_sysfs_float(): Failed to close dir"); + + goto error_free; + } + + if (fclose(sysfsfp)) + ret = -errno; + error_free: free(temp); return ret; } +/** + * read_sysfs_string() - read a string from file + * @filename: name of file to read from + * @basedir: the sysfs directory in which the file is to be found + * @str: output the read string + * + * Returns a value >= 0 on success, otherwise a negative error code. + **/ int read_sysfs_string(const char *filename, const char *basedir, char *str) { int ret = 0; @@ -653,14 +933,27 @@ int read_sysfs_string(const char *filename, const char *basedir, char *str) printf("Memory allocation failed"); return -ENOMEM; } - sprintf(temp, "%s/%s", basedir, filename); + ret = sprintf(temp, "%s/%s", basedir, filename); + if (ret < 0) + goto error_free; + sysfsfp = fopen(temp, "r"); if (sysfsfp == NULL) { ret = -errno; goto error_free; } - fscanf(sysfsfp, "%s\n", str); - fclose(sysfsfp); + errno = 0; + if (fscanf(sysfsfp, "%s\n", str) != 1) { + ret = errno ? -errno : -ENODATA; + if (fclose(sysfsfp)) + perror("read_sysfs_string(): Failed to close dir"); + + goto error_free; + } + + if (fclose(sysfsfp)) + ret = -errno; + error_free: free(temp); return ret; |