/* * Simple functions to access files. Paths can be globally prefixed to read * data from an alternative source (e.g. a /proc dump for regression tests). * * Copyright (C) 2008 Cai Qian * Copyright (C) 2008-2012 Karel Zak * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include #include #include #include "all-io.h" #include "path.h" #include "nls.h" #include "c.h" static size_t prefixlen; static char pathbuf[PATH_MAX]; int path_set_prefix(const char *prefix) { size_t len = strlen(prefix); if (len >= sizeof(pathbuf) - 1) { errno = ENAMETOOLONG; return -1; } prefixlen = len; strcpy(pathbuf, prefix); return 0; } static const char * path_vcreate(const char *path, va_list ap) { int rc = vsnprintf( pathbuf + prefixlen, sizeof(pathbuf) - prefixlen, path, ap); if (rc < 0) return NULL; if ((size_t)rc >= sizeof(pathbuf)) { errno = ENAMETOOLONG; return NULL; } return pathbuf; } const char * path_get(const char *path, ...) { const char *p; va_list ap; va_start(ap, path); p = path_vcreate(path, ap); va_end(ap); return p; } static FILE * path_vfopen(const char *mode, int exit_on_error, const char *path, va_list ap) { FILE *f; const char *p = path_vcreate(path, ap); if (!p) goto err; f = fopen(p, mode); if (!f) goto err; return f; err: if (exit_on_error) err(EXIT_FAILURE, _("cannot open %s"), p ? p : "path"); return NULL; } static int path_vopen(int flags, const char *path, va_list ap) { int fd; const char *p = path_vcreate(path, ap); if (!p) goto err; fd = open(p, flags); if (fd == -1) goto err; return fd; err: err(EXIT_FAILURE, _("cannot open %s"), p ? p : "path"); } FILE * path_fopen(const char *mode, int exit_on_error, const char *path, ...) { FILE *fd; va_list ap; va_start(ap, path); fd = path_vfopen(mode, exit_on_error, path, ap); va_end(ap); return fd; } void path_read_str(char *result, size_t len, const char *path, ...) { FILE *fd; va_list ap; va_start(ap, path); fd = path_vfopen("r" UL_CLOEXECSTR, 1, path, ap); va_end(ap); if (!fgets(result, len, fd)) err(EXIT_FAILURE, _("cannot read %s"), pathbuf); fclose(fd); len = strlen(result); if (result[len - 1] == '\n') result[len - 1] = '\0'; } int path_read_s32(const char *path, ...) { FILE *fd; va_list ap; int result; va_start(ap, path); fd = path_vfopen("r" UL_CLOEXECSTR, 1, path, ap); va_end(ap); if (fscanf(fd, "%d", &result) != 1) { if (ferror(fd)) err(EXIT_FAILURE, _("cannot read %s"), pathbuf); else errx(EXIT_FAILURE, _("parse error: %s"), pathbuf); } fclose(fd); return result; } uint64_t path_read_u64(const char *path, ...) { FILE *fd; va_list ap; uint64_t result; va_start(ap, path); fd = path_vfopen("r", 1, path, ap); va_end(ap); if (fscanf(fd, "%"SCNu64, &result) != 1) { if (ferror(fd)) err(EXIT_FAILURE, _("cannot read %s"), pathbuf); else errx(EXIT_FAILURE, _("parse error: %s"), pathbuf); } fclose(fd); return result; } int path_write_str(const char *str, const char *path, ...) { int fd, result; va_list ap; va_start(ap, path); fd = path_vopen(O_WRONLY|O_CLOEXEC, path, ap); va_end(ap); result = write_all(fd, str, strlen(str)); close(fd); return result; } int path_exist(const char *path, ...) { va_list ap; const char *p; va_start(ap, path); p = path_vcreate(path, ap); va_end(ap); return p && access(p, F_OK) == 0; } #ifdef HAVE_CPU_SET_T static cpu_set_t * path_cpuparse(int maxcpus, int islist, const char *path, va_list ap) { FILE *fd; cpu_set_t *set; size_t setsize, len = maxcpus * 7; char buf[len]; fd = path_vfopen("r" UL_CLOEXECSTR, 1, path, ap); if (!fgets(buf, len, fd)) err(EXIT_FAILURE, _("cannot read %s"), pathbuf); fclose(fd); len = strlen(buf); if (buf[len - 1] == '\n') buf[len - 1] = '\0'; set = cpuset_alloc(maxcpus, &setsize, NULL); if (!set) err(EXIT_FAILURE, _("failed to callocate cpu set")); if (islist) { if (cpulist_parse(buf, set, setsize, 0)) errx(EXIT_FAILURE, _("failed to parse CPU list %s"), buf); } else { if (cpumask_parse(buf, set, setsize)) errx(EXIT_FAILURE, _("failed to parse CPU mask %s"), buf); } return set; } cpu_set_t * path_read_cpuset(int maxcpus, const char *path, ...) { va_list ap; cpu_set_t *set; va_start(ap, path); set = path_cpuparse(maxcpus, 0, path, ap); va_end(ap); return set; } cpu_set_t * path_read_cpulist(int maxcpus, const char *path, ...) { va_list ap; cpu_set_t *set; va_start(ap, path); set = path_cpuparse(maxcpus, 1, path, ap); va_end(ap); return set; } #endif /* HAVE_CPU_SET_T */