diff --git a/Makefile.am b/Makefile.am index 73fd4429..5b10a90a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -56,6 +56,7 @@ src_iwd_SOURCES = src/main.c linux/nl80211.h linux/kdbus.h \ src/scan.h src/scan.c \ src/util.h src/util.c \ src/agent.h src/agent.c \ + src/storage.h src/storage.c \ iwd.h src_iwd_LDADD = ell/libell-internal.la diff --git a/configure.ac b/configure.ac index 1a8aca37..6e6d36d8 100644 --- a/configure.ac +++ b/configure.ac @@ -51,6 +51,23 @@ AC_ARG_ENABLE(pie, AC_HELP_STRING([--enable-pie], fi ]) +if (test "${prefix}" = "NONE"); then + dnl no prefix and no localstatedir, so default to /var + if (test "$localstatedir" = '${prefix}/var'); then + AC_SUBST([localstatedir], ['/var']) + fi + + prefix="${ac_default_prefix}" +fi + +if (test "$localstatedir" = '${prefix}/var'); then + storagedir="${prefix}/var/lib/iwd" +else + storagedir="${localstatedir}/lib/iwd" +fi + +AC_DEFINE_UNQUOTED(STORAGEDIR, "${storagedir}", + [Directory for the storage files]) AC_CHECK_HEADERS(linux/types.h linux/if_alg.h) AC_PATH_PROG(A2X, [a2x], [], $PATH:/sbin:/usr/sbin) diff --git a/src/storage.c b/src/storage.c new file mode 100644 index 00000000..3f9ba9d3 --- /dev/null +++ b/src/storage.c @@ -0,0 +1,198 @@ +/* + * + * Wireless daemon for Linux + * + * Copyright (C) 2013-2015 Intel Corporation. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "storage.h" + +#ifdef TEMP_FAILURE_RETRY +#define TFR TEMP_FAILURE_RETRY +#else +#define TFR +#endif + +#define STORAGE_DIR_MODE (S_IRUSR | S_IWUSR | S_IXUSR) +#define STORAGE_FILE_MODE (S_IRUSR | S_IWUSR) + +int create_dirs(const char *filename) +{ + struct stat st; + char *dir; + const char *prev, *next; + int err; + + if (filename[0] != '/') + return -1; + + err = stat(filename, &st); + if (!err && S_ISREG(st.st_mode)) + return 0; + + dir = l_malloc(strlen(filename) + 1); + strcpy(dir, "/"); + + for (prev = filename; (next = strchr(prev + 1, '/')); prev = next) { + /* Skip consecutive '/' characters */ + if (next - prev == 1) + continue; + + strncat(dir, prev + 1, next - prev); + + if (mkdir(dir, STORAGE_DIR_MODE) == -1 && errno != EEXIST) { + l_free(dir); + return -1; + } + } + + l_free(dir); + return 0; +} + +ssize_t read_file(void *buffer, size_t len, const char *path_fmt, ...) +{ + va_list ap; + char *path; + ssize_t r; + int fd; + + va_start(ap, path_fmt); + path = l_strdup_vprintf(path_fmt, ap); + va_end(ap); + + fd = TFR(open(path, O_RDONLY)); + + l_free(path); + + if (fd == -1) + return -1; + + r = TFR(read(fd, buffer, len)); + + TFR(close(fd)); + + return r; +} + +/* + * Write a buffer to a file in a transactionally safe form + * + * Given a buffer, write it to a file named after + * @path_fmt+args. However, to make sure the file contents are + * consistent (ie: a crash right after opening or during write() + * doesn't leave a file half baked), the contents are written to a + * file with a temporary name and when closed, it is renamed to the + * specified name (@path_fmt+args). + */ +ssize_t write_file(const void *buffer, size_t len, + const char *path_fmt, ...) +{ + va_list ap; + char *tmp_path, *path; + ssize_t r; + int fd; + + va_start(ap, path_fmt); + path = l_strdup_vprintf(path_fmt, ap); + va_end(ap); + + tmp_path = l_strdup_printf("%s.XXXXXX.tmp", path); + + r = -1; + if (create_dirs(path) != 0) + goto error_create_dirs; + + fd = TFR(mkostemps(tmp_path, 4, O_CLOEXEC)); + if (fd == -1) + goto error_mkostemps; + + r = TFR(write(fd, buffer, len)); + + TFR(close(fd)); + + if (r != (ssize_t) len) { + r = -1; + goto error_write; + } + + /* + * Now that the file contents are written, rename to the real + * file name; this way we are uniquely sure that the whole + * thing is there. + */ + unlink(path); + + /* conserve @r's value from 'write' */ + if (link(tmp_path, path) == -1) + r = -1; + +error_write: + unlink(tmp_path); +error_mkostemps: +error_create_dirs: + l_free(tmp_path); + l_free(path); + return r; +} + +struct l_settings *storage_network_open(const char *type, const char *ssid) +{ + struct l_settings *settings; + char *path; + + if (ssid == NULL || type == NULL) + return NULL; + + /* TODO: Handle SSID's with filesystem-reserved characters */ + path = l_strdup_printf(STORAGEDIR "/%s.%s", ssid, type); + settings = l_settings_new(); + + l_settings_load_from_file(settings, path); + l_free(path); + + return settings; +} + +void storage_network_sync(const char *type, const char *ssid, + struct l_settings *settings) +{ + char *data; + size_t length = 0; + + /* TODO: Handle SSID's with filesystem-reserved characters */ + data = l_settings_to_data(settings, &length); + write_file(data, length, STORAGEDIR "/%s.%s", ssid, type); + l_free(data); +} diff --git a/src/storage.h b/src/storage.h new file mode 100644 index 00000000..550f3fe2 --- /dev/null +++ b/src/storage.h @@ -0,0 +1,35 @@ +/* + * + * Wireless daemon for Linux + * + * Copyright (C) 2013-2015 Intel Corporation. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +struct l_settings; + +int create_dirs(const char *filename); + +ssize_t read_file(void *buffer, size_t len, const char *path_fmt, ...) + __attribute__((format(printf, 3, 4))); + +ssize_t write_file(const void *buffer, size_t len, const char *path_fmt, ...) + __attribute__((format(printf, 3, 4))); + +struct l_settings *storage_network_open(const char *type, const char *ssid); +void storage_network_sync(const char *type, const char *ssid, + struct l_settings *settings);