blob: 528e0e4b6e5cae7ec3b484447a85437088a8823b [file] [log] [blame]
/* Copyright 2021 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "crosid.h"
static const char *sysroot = "";
void crosid_set_sysroot(const char *path)
{
sysroot = path;
}
/*
* Get the file size via seeking and rewinding. Note that this needs
* to be done via a seek instead of a stat, since some files in /proc
* and /sys have a size of zero when stat'ed.
*/
static ssize_t get_file_size(FILE *f)
{
ssize_t size;
if (fseek(f, 0, SEEK_END) < 0)
return -1;
size = ftell(f);
rewind(f);
return size;
}
int crosid_read_file(const char *dir, const char *file, char **data_ptr,
size_t *size_ptr)
{
FILE *f;
char *buf = NULL;
ssize_t seek_size;
ssize_t size;
char full_path[PATH_MAX] = { 0 };
/*
* Using an int avoids compiler warning
* (comparison of integers of different signs)
*/
int full_path_sz = sizeof(full_path) - 1;
if (snprintf(full_path, full_path_sz, "%s%s/%s", sysroot, dir, file) >=
full_path_sz) {
crosid_log(LOG_ERR, "File path too long!\n");
crosid_log(LOG_ERR, " sysroot=%s\n", sysroot);
crosid_log(LOG_ERR, " dir=%s\n", dir);
crosid_log(LOG_ERR, " file=%s\n", file);
return -1;
}
*data_ptr = NULL;
f = fopen(full_path, "rb");
if (!f) {
/* This one is SPEW, as we expect some files to not exist */
crosid_log(LOG_SPEW, "Failed to open \"%s\" for reading: %s\n",
full_path, strerror(errno));
return -1;
}
seek_size = get_file_size(f);
if (seek_size < 0) {
crosid_log(LOG_ERR,
"Failed to get file size while reading \"%s\": %s\n",
full_path, strerror(errno));
goto err;
}
buf = malloc(seek_size + 1);
if (!buf) {
crosid_log(LOG_ERR,
"Failed to allocate %zu bytes while reading %s\n",
seek_size + 1, full_path);
goto err;
}
/*
* 0 <= fread() <= size
* Normally we'd expect the return value to be the size, but
* in SMBIOS sysfs, the kernel lets us seek further than we
* can read, thus, we have to handle getting a value less than
* the size we got thru seek.
*/
size = fread(buf, 1, seek_size, f);
if (size != seek_size && !feof(f)) {
crosid_log(LOG_ERR, "%s was not at EOF after reading\n",
full_path);
goto err;
}
buf[size] = '\0';
fclose(f);
*data_ptr = buf;
if (size_ptr)
*size_ptr = size;
return 0;
err:
fclose(f);
free(buf);
return -1;
}