X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=lib%2Fcfg.c;h=d61cd778f291cc18b421e47aae9c047418b30e9c;hb=3f262d7de1dea6b4f70db1c4ff2e79de89c74b0d;hp=b4d1d591a74e8e6188881577dc60fb1c949e0fa5;hpb=064af42167bf4fc9aaea2702d80ce08074b889c0;p=openvswitch diff --git a/lib/cfg.c b/lib/cfg.c index b4d1d591..d61cd778 100644 --- a/lib/cfg.c +++ b/lib/cfg.c @@ -1,27 +1,16 @@ /* Copyright (c) 2008, 2009 Nicira Networks - * - * 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 3 of the License, or - * (at your option) any later version. * - * This program 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 General Public License for more details. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * http://www.apache.org/licenses/LICENSE-2.0 * - * In addition, as a special exception, Nicira Networks gives permission - * to link the code of its release of vswitchd with the OpenSSL project's - * "OpenSSL" library (or with modified versions of it that use the same - * license as the "OpenSSL" library), and distribute the linked - * executables. You must obey the GNU General Public License in all - * respects for all of the code used other than "OpenSSL". If you modify - * this file, you may extend this exception to your version of the file, - * but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #include @@ -36,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" @@ -63,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; @@ -103,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. * @@ -111,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. */ @@ -136,40 +128,26 @@ 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; } static int update_cookie(void) { + struct sha1_ctx context; int i; - SHA1Context context; - if (SHA1Reset(&context) != shaSuccess) { - return -1; - } + sha1_init(&context); for (i = 0; i < cfg.n; i++) { - if (SHA1Input(&context, (uint8_t *)cfg.names[i], - strlen(cfg.names[i])) != shaSuccess) { - return -1; - } - SHA1Input(&context, (uint8_t *)"\n", 1); - } - if (SHA1Result(&context, cfg_cookie) != shaSuccess) { - return -1; + sha1_update(&context, cfg.names[i], strlen(cfg.names[i])); + sha1_update(&context, "\n", 1); } + sha1_final(&context, cfg_cookie); return 0; } @@ -201,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; } @@ -291,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; + if (lockfile) { + lockfile_unlock(lockfile); + lockfile = NULL; } } -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. */ - } -} - -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. * @@ -350,62 +287,18 @@ try_lock(int fd, bool block) int cfg_lock(uint8_t *cookie, int timeout) { - long long int start = time_msec(); - long long int elapsed = 0; - int fd; - uint8_t curr_cookie[CFG_COOKIE_LEN]; - - assert(lock_fd < 0); - COVERAGE_INC(cfg_lock); - 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)) { @@ -691,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 @@ -1116,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