From 7de03e4e519705301265c0415b3c0af85263a7ac Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 09:52:36 +0200 Subject: Adding upstream version 1:4.13.0. Signed-off-by: Daniel Baumann --- tools/sfex_lib.c | 474 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 474 insertions(+) create mode 100644 tools/sfex_lib.c (limited to 'tools/sfex_lib.c') diff --git a/tools/sfex_lib.c b/tools/sfex_lib.c new file mode 100644 index 0000000..2d01602 --- /dev/null +++ b/tools/sfex_lib.c @@ -0,0 +1,474 @@ +/*------------------------------------------------------------------------- + * + * Shared Disk File EXclusiveness Control Program(SF-EX) + * + * sfex_lib.c --- Libraries for other SF-EX modules. + * + * 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 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. + * + * 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. + * + * Copyright (c) 2007 NIPPON TELEGRAPH AND TELEPHONE CORPORATION + * + * $Id$ + * + *-------------------------------------------------------------------------*/ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sfex.h" +#include "sfex_lib.h" + +static void *locked_mem; +static int dev_fd; +unsigned long sector_size = 0; + +int +prepare_lock (const char *device) +{ + int sec_tmp = 0; + + do { + dev_fd = open (device, O_RDWR | O_DIRECT | O_SYNC); + if (dev_fd == -1) { + if (errno == EINTR || errno == EAGAIN) + continue; + cl_log(LOG_ERR, "can't open device %s: %s\n", + device, strerror (errno)); + exit (3); + } + break; + } + while (1); + + ioctl(dev_fd, BLKSSZGET, &sec_tmp); + sector_size = (unsigned long)sec_tmp; + if (sector_size == 0) { + cl_log(LOG_ERR, "Get sector size failed: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + + if (posix_memalign + ((void **) (&locked_mem), SFEX_ODIRECT_ALIGNMENT, + sector_size) != 0) { + cl_log(LOG_ERR, "Failed to allocate aligned memory\n"); + exit (3); + } + memset (locked_mem, 0, sector_size); + + return 0; +} + +/* + * get_progname --- a program name + * + * We get program name from directory path. It does not include delimiter + * characters. Return value is pointer that point string of program name. + * We assume delimiter is '/'. + */ +const char * +get_progname (const char *argv0) +{ + char *p; + + p = strrchr (argv0, '/'); + if (p) + return p + 1; + else + return argv0; +} + +/* + * get_nodename --- get a node name(hostname) + * + * We get a node name by using uname(2) and return pointer of it. + * The error checks are done in this function. The caller does not have + * to check return value. + */ +char * +get_nodename (void) +{ + struct utsname u; + char *n; + + if (uname (&u)) { + cl_log(LOG_ERR, "%s\n", strerror (errno)); + exit (3); + } + if (strlen (u.nodename) > SFEX_MAX_NODENAME) { + cl_log(LOG_ERR, + "nodename %s is too long. must be less than %lu byte.\n", + u.nodename, (unsigned long)SFEX_MAX_NODENAME); + exit (3); + } + n = strdup (&u.nodename[0]); + if (!n) { + cl_log(LOG_ERR, "%s\n", strerror (errno)); + exit (3); + } + return n; +} + +/* + * init_controldata --- initialize control data + * + * We initialize each member of sfex_controldata structure. + */ +void +init_controldata (sfex_controldata * cdata, size_t blocksize, int numlocks) +{ + memcpy (cdata->magic, SFEX_MAGIC, sizeof (cdata->magic)); + cdata->version = SFEX_VERSION; + cdata->revision = SFEX_REVISION; + cdata->blocksize = blocksize; + cdata->numlocks = numlocks; +} + +/* + * init_lockdata --- initialize lock data + * + * We initialize each member of sfex_lockdata structure. + */ +void +init_lockdata (sfex_lockdata * ldata) +{ + ldata->status = SFEX_STATUS_UNLOCK; + ldata->count = 0; + ldata->nodename[0] = 0; +} + +/* + * write_controldata --- write control data into file + * + * We write sfex_controldata struct into file. We open a file with + * synchronization mode and write out control data. + * + * cdata --- pointer of control data + * + * device --- name of target file + */ +void +write_controldata (const sfex_controldata * cdata) +{ + sfex_controldata_ondisk *block; + int fd; + + block = (sfex_controldata_ondisk *) (locked_mem); + + /* We write control data into the buffer with given format. */ + /* We write the offset value of each field of the control data directly. + * Because a point using this value is limited to two places, we do not + * use macro. If you change the following offset values, you must change + * values in the read_controldata() function. + */ + memset (block, 0, cdata->blocksize); + memcpy (block->magic, cdata->magic, sizeof (block->magic)); + snprintf ((char *) (block->version), sizeof (block->version), "%d", + cdata->version); + snprintf ((char *) (block->revision), sizeof (block->revision), "%d", + cdata->revision); + snprintf ((char *) (block->blocksize), sizeof (block->blocksize), "%u", + (unsigned)cdata->blocksize); + snprintf ((char *) (block->numlocks), sizeof (block->numlocks), "%d", + cdata->numlocks); + + fd = dev_fd; + if (lseek (fd, 0, SEEK_SET) == -1) { + cl_log(LOG_ERR, "can't seek file pointer: %s\n", + strerror (errno)); + exit (3); + } + + /* write buffer into a file */ + do { + ssize_t s = write (fd, block, cdata->blocksize); + if (s == -1) { + if (errno == EINTR || errno == EAGAIN) + continue; + cl_log(LOG_ERR, "can't write meta-data: %s\n", + strerror (errno)); + exit (3); + } + else + break; + } + while (1); +} + +/* + * write_lockdata --- write lock data into file + * + * We write sfex_lockdata into file and seek file pointer to the given + * position of lock data. + * + * cdata --- pointer for control data + * + * ldata --- pointer for lock data + * + * device --- file name for write + * + * index --- index number for lock data. 1 origine. + */ +int +write_lockdata (const sfex_controldata * cdata, const sfex_lockdata * ldata, + int index) +{ + sfex_lockdata_ondisk *block; + int fd; + + block = (sfex_lockdata_ondisk *) locked_mem; + /* We write lock data into buffer with given format */ + /* We write the offset value of each field of the control data directly. + * Because a point using this value is limited to two places, we do not + * use macro. If you chage the following offset values, you must change + * values in the read_lockdata() function. + */ + memset (block, 0, cdata->blocksize); + block->status = ldata->status; + snprintf ((char *) (block->count), sizeof (block->count), "%d", + ldata->count); + snprintf ((char *) (block->nodename), sizeof (block->nodename), "%s", + ldata->nodename); + + fd = dev_fd; + + /* seek a file pointer to given position */ + if (lseek (fd, cdata->blocksize * index, SEEK_SET) == -1) { + cl_log(LOG_ERR, "can't seek file pointer: %s\n", + strerror (errno)); + return -1; + } + + /* write buffer into file */ + do { + ssize_t s = write (fd, block, cdata->blocksize); + if (s == -1) { + if (errno == EINTR || errno == EAGAIN) + continue; + cl_log(LOG_ERR, "can't write meta-data: %s\n", + strerror (errno)); + return -1; + } + else if (s != cdata->blocksize) { + /* if writing atomically failed, this process is error */ + cl_log(LOG_ERR, "can't write meta-data atomically.\n"); + return -1; + } + break; + } + while (1); + return 0; +} + +/* + * read_controldata --- read control data from file + * + * read sfex_controldata structure from file. + * + * cdata --- pointer for control data + * + * device --- file name for reading + */ +int +read_controldata (sfex_controldata * cdata) +{ + sfex_controldata_ondisk *block; + + block = (sfex_controldata_ondisk *) (locked_mem); + + if (lseek (dev_fd, 0, SEEK_SET) == -1) { + cl_log(LOG_ERR, "can't seek file pointer: %s\n", + strerror (errno)); + return -1; + } + + /* read data from file */ + do { + ssize_t s = read (dev_fd, block, sector_size); + if (s == -1) { + if (errno == EINTR || errno == EAGAIN) + continue; + cl_log(LOG_ERR, + "can't read controldata meta-data: %s\n", + strerror (errno)); + return -1; + } + else + break; + } while (1); + + /* read control data from buffer */ + /* 1. check the magic number. 2. check null terminator of each field + 3. check the version number. 4. Unmuch of revision number is allowed */ + /* We write the offset value of each field of the control data directly. + * Because a point using this value is limited to two places, we do not + * use macro. If you chage the following offset values, you must change + * values in the write_controldata() function. + */ + memcpy (cdata->magic, block->magic, 4); + if (memcmp (cdata->magic, SFEX_MAGIC, sizeof (cdata->magic))) { + cl_log(LOG_ERR, "magic number mismatched. %c%c%c%c <-> %s\n", block->magic[0], block->magic[1], block->magic[2], block->magic[3], SFEX_MAGIC); + return -1; + } + if (block->version[sizeof (block->version)-1] + || block->revision[sizeof (block->revision)-1] + || block->blocksize[sizeof (block->blocksize)-1] + || block->numlocks[sizeof (block->numlocks)-1]) { + cl_log(LOG_ERR, "control data format error.\n"); + return -1; + } + cdata->version = atoi ((char *) (block->version)); + if (cdata->version != SFEX_VERSION) { + cl_log(LOG_ERR, + "version number mismatched. program is %d, data is %d.\n", + SFEX_VERSION, cdata->version); + return -1; + } + cdata->revision = atoi ((char *) (block->revision)); + cdata->blocksize = atoi ((char *) (block->blocksize)); + cdata->numlocks = atoi ((char *) (block->numlocks)); + + return 0; +} + +/* + * read_lockdata --- read lock data from file + * + * read sfex_lockdata from file and seek file pointer to head position of the + * file. + * + * cdata --- pointer for control data + * + * ldata --- pointer for lock data. Read lock data are stored into this + * pointed area. + * + * device --- file name of source file + * + * index --- index number. 1 origin. + */ +int +read_lockdata (const sfex_controldata * cdata, sfex_lockdata * ldata, + int index) +{ + sfex_lockdata_ondisk *block; + int fd; + + block = (sfex_lockdata_ondisk *) (locked_mem); + + fd = dev_fd; + + /* seek a file pointer to given position */ + if (lseek (fd, cdata->blocksize * index, SEEK_SET) == -1) { + cl_log(LOG_ERR, "can't seek file pointer: %s\n", + strerror (errno)); + return -1; + } + + /* read from file */ + do { + ssize_t s = read (fd, block, cdata->blocksize); + if (s == -1) { + if (errno == EINTR || errno == EAGAIN) + continue; + cl_log(LOG_ERR, "can't read lockdata meta-data: %s\n", + strerror (errno)); + return -1; + } + else if (s != cdata->blocksize) { + cl_log(LOG_ERR, "can't read meta-data atomically.\n"); + return -1; + } + break; + } + while (1); + + /* read control data form buffer */ + /* 1. check null terminator of each field 2. check the status */ + /* We write the offset value of each field of the control data directly. + * Because a point using this value is limited to two places, we do not + * use macro. If you chage the following offset values, you must change + * values in the write_lockdata() function. + */ + if (block->count[sizeof(block->count)-1] || block->nodename[sizeof(block->nodename)-1]) { + cl_log(LOG_ERR, "lock data format error.\n"); + return -1; + } + ldata->status = block->status; + if (ldata->status != SFEX_STATUS_UNLOCK + && ldata->status != SFEX_STATUS_LOCK) { + cl_log(LOG_ERR, "lock data format error.\n"); + return -1; + } + ldata->count = atoi ((char *) (block->count)); + strncpy ((char *) (ldata->nodename), (const char *) (block->nodename), sizeof(ldata->nodename)); + +#ifdef SFEX_DEBUG + cl_log(LOG_INFO, "status: %c\n", ldata->status); + cl_log(LOG_INFO, "count: %d\n", ldata->count); + cl_log(LOG_INFO, "nodename: %s\n", ldata->nodename); +#endif + return 0; +} + +/* + * lock_index_check --- check the value of index + * + * The lock_index_check function checks whether the value of index exceeds + * the number of lock data on the shared disk. + * + * cdata --- pointer for control data + * + * index --- index number + */ +int +lock_index_check(sfex_controldata * cdata, int index) +{ + if (read_controldata(cdata) == -1) { + cl_log(LOG_ERR, "%s\n", "read_controldata failed in lock_index_check"); + return -1; + } +#ifdef SFEX_DEBUG + cl_log(LOG_INFO, "version: %d\n", cdata->version); + cl_log(LOG_INFO, "revision: %d\n", cdata->revision); + cl_log(LOG_INFO, "blocksize: %d\n", cdata->blocksize); + cl_log(LOG_INFO, "numlocks: %d\n", cdata->numlocks); +#endif + + if (index > cdata->numlocks) { + cl_log(LOG_ERR, "index %d is too large. %d locks are stored.\n", + index, cdata->numlocks); + return -1; + } + + if (cdata->blocksize != sector_size) { + cl_log(LOG_ERR, "sector_size is not the same as the blocksize.\n"); + return -1; + } + return 0; +} -- cgit v1.2.3