X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;ds=sidebyside;f=lib%2Fcfg.c;h=d61cd778f291cc18b421e47aae9c047418b30e9c;hb=2d2d6d4a71776813f8d2fd1af1051f22b836befc;hp=901315ed99cd83d0f8b333a7e8e03247734f66c8;hpb=0c7af78c3754f006b347d044131b9c1043b3407a;p=openvswitch diff --git a/lib/cfg.c b/lib/cfg.c index 901315ed..d61cd778 100644 --- a/lib/cfg.c +++ b/lib/cfg.c @@ -25,10 +25,9 @@ #include #include #include -#include -#include #include "coverage.h" #include "dynamic-string.h" +#include "lockfile.h" #include "ofpbuf.h" #include "packets.h" #include "svec.h" @@ -52,8 +51,7 @@ static char *cfg_name; static char *tmp_name; /* Lock information. */ -static char *lock_name; -static int lock_fd = -1; +static struct lockfile *lockfile; /* Flag to indicate whether local modifications have been made. */ static bool dirty; @@ -92,6 +90,12 @@ static bool is_type(const char *s, enum cfg_flags); #define CC_FILE_NAME CC_ALNUM "._-" #define CC_KEY CC_ALNUM "._-@$:+" +void +cfg_init(void) +{ + svec_terminate(&cfg); +} + /* Sets 'file_name' as the configuration file read by cfg_read(). Returns 0 on * success, otherwise a positive errno value if 'file_name' cannot be opened. * @@ -100,15 +104,14 @@ static bool is_type(const char *s, enum cfg_flags); int cfg_set_file(const char *file_name) { - const char *slash; + char *lock_name; int fd; if (cfg_name) { - assert(lock_fd < 0); + assert(!lockfile); free(cfg_name); - free(lock_name); free(tmp_name); - cfg_name = lock_name = tmp_name = NULL; + cfg_name = tmp_name = NULL; } /* Make sure that we can open this file for reading. */ @@ -125,18 +128,11 @@ cfg_set_file(const char *file_name) * rename(tmp_name, cfg_name) will work. */ tmp_name = xasprintf("%s.~tmp~", file_name); - /* Put the lock file in the same directory as cfg_name, but prefixed by - * a dot so as not to garner administrator interest. */ - slash = strrchr(file_name, '/'); - if (slash) { - lock_name = xasprintf("%.*s/.%s.~lock~", - slash - file_name, file_name, slash + 1); - } else { - lock_name = xasprintf(".%s.~lock~", file_name); - } - + lock_name = lockfile_name(file_name); VLOG_INFO("using \"%s\" as configuration file, \"%s\" as lock file", file_name, lock_name); + free(lock_name); + return 0; } @@ -183,6 +179,7 @@ cfg_read(void) file = fopen(cfg_name, "r"); if (!file) { VLOG_ERR("failed to open \"%s\": %s", cfg_name, strerror(errno)); + svec_terminate(&cfg); return errno; } @@ -273,54 +270,12 @@ cfg_get_cookie(uint8_t *cookie) void cfg_unlock(void) { - if (lock_fd != -1) { - COVERAGE_INC(cfg_unlock); - close(lock_fd); - lock_fd = -1; - } -} - -static int -open_lockfile(const char *name) -{ - for (;;) { - /* Try to open an existing lock file. */ - int fd = open(name, O_RDWR); - if (fd >= 0) { - return fd; - } else if (errno != ENOENT) { - VLOG_WARN("%s: failed to open lock file: %s", - name, strerror(errno)); - return -errno; - } - - /* Try to create a new lock file. */ - VLOG_INFO("%s: lock file does not exist, creating", name); - fd = open(name, O_RDWR | O_CREAT | O_EXCL, 0600); - if (fd >= 0) { - return fd; - } else if (errno != EEXIST) { - VLOG_WARN("%s: failed to create lock file: %s", - name, strerror(errno)); - return -errno; - } - - /* Someone else created the lock file. Try again. */ + if (lockfile) { + lockfile_unlock(lockfile); + lockfile = NULL; } } -static int -try_lock(int fd, bool block) -{ - struct flock l; - memset(&l, 0, sizeof l); - l.l_type = F_WRLCK; - l.l_whence = SEEK_SET; - l.l_start = 0; - l.l_len = 0; - return fcntl(fd, block ? F_SETLKW : F_SETLK, &l) == -1 ? errno : 0; -} - /* Locks the configuration file against modification by other processes and * re-reads it from disk. * @@ -332,65 +287,18 @@ try_lock(int fd, bool block) int cfg_lock(uint8_t *cookie, int timeout) { - long long int start; - long long int elapsed = 0; - int fd; - uint8_t curr_cookie[CFG_COOKIE_LEN]; - - assert(lock_fd < 0); - COVERAGE_INC(cfg_lock); - - time_refresh(); - start = time_msec(); - for (;;) { - int error; - - /* Open lock file. */ - fd = open_lockfile(lock_name); - if (fd < 0) { - return -fd; - } - - /* Try to lock it. This will block (if 'timeout' > 0). */ - error = try_lock(fd, timeout > 0); - time_refresh(); - elapsed = time_msec() - start; - if (!error) { - /* Success! */ - break; - } - - /* Lock failed. Close the lock file and reopen it on the next - * iteration, just in case someone deletes it underneath us (even - * though that should not happen). */ - close(fd); - if (error != EINTR) { - /* Hard error, give up. */ - COVERAGE_INC(cfg_lock_error); - VLOG_WARN("%s: failed to lock file " - "(after %lld ms, with %d-ms timeout): %s", - lock_name, elapsed, timeout, strerror(error)); - return error; - } + int error; - /* Probably, the periodic timer set up by time_init() woke up us. Just - * check whether it's time to give up. */ - if (timeout != INT_MAX && elapsed >= timeout) { - COVERAGE_INC(cfg_lock_timeout); - VLOG_WARN("%s: giving up on lock file after %lld ms", - lock_name, elapsed); - return ETIMEDOUT; - } - COVERAGE_INC(cfg_lock_retry); - } - if (elapsed) { - VLOG_WARN("%s: waited %lld ms for lock file", lock_name, elapsed); + assert(!lockfile); + error = lockfile_lock(cfg_name, timeout, &lockfile); + if (error) { + return error; } - lock_fd = fd; cfg_read(); if (cookie) { + uint8_t curr_cookie[CFG_COOKIE_LEN]; cfg_get_cookie(curr_cookie); if (memcmp(curr_cookie, cookie, sizeof *curr_cookie)) { @@ -676,6 +584,25 @@ cfg_del_match(const char *pattern_, ...) free(pattern); } +/* Fills 'svec' with all of the key-value pairs that match shell glob pattern + * 'pattern'. The caller must first initialize 'svec'. */ +void +cfg_get_matches(struct svec *svec, const char *pattern_, ...) +{ + char *pattern; + char **p; + + FORMAT_KEY(pattern_, pattern); + + for (p = cfg.names; *p; p++) { + if (!fnmatch(pattern, *p, 0)) { + svec_add(svec, *p); + } + } + + free(pattern); +} + /* Fills 'svec' with all of the key-value pairs that have sections that * begin with 'section'. The caller must first initialize 'svec'. */ void @@ -1101,8 +1028,8 @@ find_key(const char *key) static bool parse_mac(const char *s, uint8_t mac[6]) { - return sscanf(s, "%"SCNx8":%"SCNx8":%"SCNx8":%"SCNx8":%"SCNx8":%"SCNx8, - &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]) == 6; + return (sscanf(s, ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(mac)) + == ETH_ADDR_SCAN_COUNT); } static bool