LCOV - code coverage report
Current view: top level - drivers - tapdisk-utils.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 6 157 3.8 %
Date: 2025-07-10 10:47:11 Functions: 1 14 7.1 %
Branches: 2 88 2.3 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (c) 2016, Citrix Systems, Inc.
       3                 :            :  *
       4                 :            :  * All rights reserved.
       5                 :            :  *
       6                 :            :  * Redistribution and use in source and binary forms, with or without
       7                 :            :  * modification, are permitted provided that the following conditions are met:
       8                 :            :  * 
       9                 :            :  *  1. Redistributions of source code must retain the above copyright
      10                 :            :  *     notice, this list of conditions and the following disclaimer.
      11                 :            :  *  2. Redistributions in binary form must reproduce the above copyright
      12                 :            :  *     notice, this list of conditions and the following disclaimer in the
      13                 :            :  *     documentation and/or other materials provided with the distribution.
      14                 :            :  *  3. Neither the name of the copyright holder nor the names of its 
      15                 :            :  *     contributors may be used to endorse or promote products derived from 
      16                 :            :  *     this software without specific prior written permission.
      17                 :            :  *
      18                 :            :  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
      19                 :            :  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
      20                 :            :  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
      21                 :            :  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
      22                 :            :  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
      23                 :            :  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
      24                 :            :  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
      25                 :            :  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
      26                 :            :  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
      27                 :            :  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
      28                 :            :  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      29                 :            :  */
      30                 :            : 
      31                 :            : #ifdef HAVE_CONFIG_H
      32                 :            : #include "config.h"
      33                 :            : #endif
      34                 :            : 
      35                 :            : #include <stdlib.h>
      36                 :            : #include <errno.h>
      37                 :            : #include <stdio.h>
      38                 :            : #include <string.h>
      39                 :            : #include <unistd.h>
      40                 :            : #include <linux/fs.h>
      41                 :            : #include <sys/stat.h>
      42                 :            : #include <sys/mman.h>
      43                 :            : #include <sys/ioctl.h>
      44                 :            : #include <sys/resource.h>
      45                 :            : #include <sys/utsname.h>
      46                 :            : #include <arpa/inet.h>
      47                 :            : 
      48                 :            : #ifdef __linux__
      49                 :            : #include <linux/version.h>
      50                 :            : #endif
      51                 :            : 
      52                 :            : #define SYSLOG_NAMES
      53                 :            : #include <syslog.h>
      54                 :            : #include <stdarg.h>
      55                 :            : 
      56                 :            : #include "tapdisk.h"
      57                 :            : #include "tapdisk-log.h"
      58                 :            : #include "tapdisk-utils.h"
      59                 :            : #include "tapdisk-syslog.h"
      60                 :            : 
      61                 :            : #define MIN(a,b) (((a) < (b)) ? (a) : (b))
      62                 :            : 
      63                 :            : #define ASSERT(_p)                                                                              \
      64                 :            :         if (!(_p)) {                                                                                    \
      65                 :            :                 EPRINTF("%s:%d: FAILED ASSERTION: '%s'\n",                    \
      66                 :            :                         __FILE__, __LINE__, #_p);                                               \
      67                 :            :                 td_panic();                                                                                     \
      68                 :            :         }
      69                 :            : 
      70                 :            : static int
      71                 :          0 : tapdisk_syslog_facility_by_name(const char *name)
      72                 :            : {
      73                 :            :         int facility;
      74                 :            :         CODE *c;
      75                 :            : 
      76                 :          0 :         facility = -1;
      77                 :            : 
      78         [ #  # ]:          0 :         for (c = facilitynames; c->c_name != NULL; ++c)
      79         [ #  # ]:          0 :                 if (!strcmp(c->c_name, name)) {
      80                 :          0 :                         facility = c->c_val;
      81                 :          0 :                         break;
      82                 :            :                 }
      83                 :            : 
      84                 :          0 :         return facility;
      85                 :            : }
      86                 :            : 
      87                 :            : int
      88                 :          0 : tapdisk_syslog_facility(const char *arg)
      89                 :            : {
      90                 :            :         int facility;
      91                 :            :         char *endptr;
      92                 :            : 
      93         [ #  # ]:          0 :         if (arg) {
      94                 :          0 :                 facility = strtol(arg, &endptr, 0);
      95         [ #  # ]:          0 :                 if (*endptr == 0)
      96                 :          0 :                         return facility;
      97                 :            : 
      98                 :          0 :                 facility = tapdisk_syslog_facility_by_name(arg);
      99         [ #  # ]:          0 :                 if (facility >= 0)
     100                 :          0 :                         return facility;
     101                 :            :         }
     102                 :            : 
     103                 :            :         return LOG_DAEMON;
     104                 :            : }
     105                 :            : 
     106                 :            : char*
     107                 :          0 : tapdisk_syslog_ident(const char *name)
     108                 :            : {
     109                 :            :         char ident[TD_SYSLOG_IDENT_MAX+1];
     110                 :            :         size_t size, len;
     111                 :            :         pid_t pid;
     112                 :            : 
     113                 :          0 :         pid  = getpid();
     114                 :          0 :         size = sizeof(ident);
     115                 :          0 :         len  = 0;
     116                 :            : 
     117                 :          0 :         len  = snprintf(NULL, 0, "[%d]", pid);
     118                 :          0 :         len  = snprintf(ident, size - len, "%s", name);
     119                 :          0 :         snprintf(ident + len, size - len, "[%d]", pid);
     120                 :            : 
     121                 :          0 :         return strdup(ident);
     122                 :            : }
     123                 :            : 
     124                 :            : size_t
     125                 :          0 : tapdisk_syslog_strftime(char *buf, size_t size, const struct timeval *tv)
     126                 :            : {
     127                 :          0 :         const char *mon[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
     128                 :            :                               "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
     129                 :            :         struct tm tm;
     130                 :            : 
     131                 :            :         /*
     132                 :            :          * TIMESTAMP :=  <Mmm> " " <dd> " " <hh> ":" <mm> ":" <ss>.
     133                 :            :          * Local time, no locales.
     134                 :            :          */
     135                 :            : 
     136                 :          0 :         localtime_r(&tv->tv_sec, &tm);
     137                 :            : 
     138                 :          0 :         return snprintf(buf, size, "%s %2d %02d:%02d:%02d",
     139                 :          0 :                         mon[tm.tm_mon], tm.tm_mday,
     140                 :            :                         tm.tm_hour, tm.tm_min, tm.tm_sec);
     141                 :            : }
     142                 :            : 
     143                 :            : size_t
     144                 :          0 : tapdisk_syslog_strftv(char *buf, size_t size, const struct timeval *tv)
     145                 :            : {
     146                 :            :         struct tm tm;
     147                 :            : 
     148                 :          0 :         localtime_r(&tv->tv_sec, &tm);
     149                 :            : 
     150                 :          0 :         return snprintf(buf, size, "[%02d:%02d:%02d.%03ld]",
     151                 :            :                         tm.tm_hour, tm.tm_min, tm.tm_sec,
     152                 :          0 :                         (long)tv->tv_usec / 1000);
     153                 :            : }
     154                 :            : 
     155                 :            : int
     156                 :          0 : tapdisk_set_resource_limits(void)
     157                 :            : {
     158                 :            :         int err;
     159                 :            :         struct rlimit rlim;
     160                 :            : 
     161                 :          0 :         rlim.rlim_cur = RLIM_INFINITY;
     162                 :          0 :         rlim.rlim_max = RLIM_INFINITY;
     163                 :            : 
     164                 :          0 :         err = setrlimit(RLIMIT_MEMLOCK, &rlim);
     165         [ #  # ]:          0 :         if (err == -1) {
     166                 :          0 :                 EPRINTF("RLIMIT_MEMLOCK failed: %d\n", errno);
     167                 :          0 :                 return -errno;
     168                 :            :         }
     169                 :            : 
     170                 :          0 :         err = mlockall(MCL_CURRENT | MCL_FUTURE);
     171         [ #  # ]:          0 :         if (err == -1) {
     172                 :          0 :                 EPRINTF("mlockall failed: %d\n", errno);
     173                 :          0 :                 return -errno;
     174                 :            :         }
     175                 :            : 
     176                 :            : #define CORE_DUMP
     177                 :            : #if defined(CORE_DUMP)
     178                 :          0 :         err = setrlimit(RLIMIT_CORE, &rlim);
     179         [ #  # ]:          0 :         if (err == -1)
     180                 :          0 :                 EPRINTF("RLIMIT_CORE failed: %d\n", errno);
     181                 :            : #endif
     182                 :            : 
     183                 :            :         return 0;
     184                 :            : }
     185                 :            : 
     186                 :            : int
     187                 :          2 : tapdisk_namedup(char **dup, const char *name)
     188                 :            : {
     189                 :          2 :         *dup = NULL;
     190                 :            : 
     191         [ +  - ]:          2 :         if (strnlen(name, MAX_NAME_LEN) >= MAX_NAME_LEN)
     192                 :            :                 return -ENAMETOOLONG;
     193                 :            :         
     194                 :          2 :         *dup = strdup(name);
     195         [ +  - ]:          2 :         if (!*dup)
     196                 :            :                 return -ENOMEM;
     197                 :            : 
     198                 :          2 :         return 0;
     199                 :            : }
     200                 :            : 
     201                 :            : /*Get Image size, secsize*/
     202                 :            : int
     203                 :          0 : tapdisk_get_image_size(int fd, uint64_t *_sectors, uint32_t *_sector_size)
     204                 :            : {
     205                 :            :         struct stat stat;
     206                 :            :         uint64_t sectors, bytes;
     207                 :            :         uint32_t sector_size;
     208                 :            : 
     209                 :          0 :         sectors       = 0;
     210                 :          0 :         sector_size   = 0;
     211                 :          0 :         *_sectors     = 0;
     212                 :          0 :         *_sector_size = 0;
     213                 :            : 
     214         [ #  # ]:          0 :         if (fstat(fd, &stat)) {
     215                 :            :                 DPRINTF("ERROR: fstat failed, Couldn't stat image");
     216                 :          0 :                 return -EINVAL;
     217                 :            :         }
     218                 :            : 
     219         [ #  # ]:          0 :         if (S_ISBLK(stat.st_mode)) {
     220                 :            :                 /*Accessing block device directly*/
     221         [ #  # ]:          0 :                 if (ioctl(fd,BLKGETSIZE64,&bytes)==0) {
     222                 :          0 :                         sectors = bytes >> SECTOR_SHIFT;
     223         [ #  # ]:          0 :                 } else if (ioctl(fd,BLKGETSIZE,&sectors)!=0) {
     224                 :            :                         DPRINTF("ERR: BLKGETSIZE and BLKGETSIZE64 failed, couldn't stat image");
     225                 :            :                         return -EINVAL;
     226                 :            :                 }
     227                 :            : 
     228                 :            :                 /*Get the sector size*/
     229                 :            : #if defined(BLKSSZGET)
     230                 :            :                 {
     231                 :          0 :                         sector_size = DEFAULT_SECTOR_SIZE;
     232                 :          0 :                         ioctl(fd, BLKSSZGET, &sector_size);
     233                 :            : 
     234         [ #  # ]:          0 :                         if (sector_size != DEFAULT_SECTOR_SIZE)
     235                 :          0 :                                 DPRINTF("Note: sector size is %u (not %d)\n",
     236                 :            :                                         sector_size, DEFAULT_SECTOR_SIZE);
     237                 :            :                 }
     238                 :            : #else
     239                 :            :                 sector_size = DEFAULT_SECTOR_SIZE;
     240                 :            : #endif
     241                 :            : 
     242                 :            :         } else {
     243                 :            :                 /*Local file? try fstat instead*/
     244                 :          0 :                 sectors     = (stat.st_size >> SECTOR_SHIFT);
     245                 :          0 :                 sector_size = DEFAULT_SECTOR_SIZE;
     246                 :            :         }
     247                 :            : 
     248                 :          0 :         if (sectors == 0) {             
     249                 :            :                 sectors     = 16836057ULL;
     250                 :            :                 sector_size = DEFAULT_SECTOR_SIZE;
     251                 :            :         }
     252                 :            : 
     253                 :            :         return 0;
     254                 :            : }
     255                 :            : 
     256                 :            : #ifdef __linux__
     257                 :            : 
     258                 :          0 : int tapdisk_linux_version(void)
     259                 :            : {
     260                 :            :         struct utsname uts;
     261                 :            :         unsigned int version, patchlevel, sublevel;
     262                 :            :         int n, err;
     263                 :            : 
     264                 :          0 :         err = uname(&uts);
     265         [ #  # ]:          0 :         if (err)
     266                 :          0 :                 return -errno;
     267                 :            : 
     268                 :          0 :         n = sscanf(uts.release, "%u.%u.%u", &version, &patchlevel, &sublevel);
     269         [ #  # ]:          0 :         if (n != 3) {
     270                 :          0 :                 sublevel = 0;
     271                 :          0 :                 n = sscanf(uts.release, "%u.%u", &version, &patchlevel);
     272         [ #  # ]:          0 :                 if (n != 2)
     273                 :            :                         return -ENOSYS;
     274                 :            :         }
     275                 :            : 
     276                 :          0 :         return KERNEL_VERSION(version, patchlevel, sublevel);
     277                 :            : }
     278                 :            : 
     279                 :            : #else
     280                 :            : 
     281                 :            : int tapdisk_linux_version(void)
     282                 :            : {
     283                 :            :         return -ENOSYS;
     284                 :            : }
     285                 :            : 
     286                 :            : #endif
     287                 :            : 
     288                 :            : #ifdef WORDS_BIGENDIAN
     289                 :            : uint64_t ntohll(uint64_t a) {
     290                 :            :         return a;
     291                 :            : }
     292                 :            : #else
     293                 :          0 : uint64_t ntohll(uint64_t a) {
     294                 :          0 :         uint32_t lo = a & 0xffffffff;
     295                 :          0 :         uint32_t hi = a >> 32U;
     296                 :          0 :         lo = ntohl(lo);
     297                 :          0 :         hi = ntohl(hi);
     298                 :          0 :         return ((uint64_t) lo) << 32U | hi;
     299                 :            : }
     300                 :            : #endif
     301                 :            : #define htonll ntohll
     302                 :            : 
     303                 :            : 
     304                 :            : /**
     305                 :            :  * Simplified version of snprintf that return 0 if everything has gone OK and
     306                 :            :  * +errno if not (including the buffer not being large enough to hold the
     307                 :            :  * string).
     308                 :            :  */
     309                 :            : int
     310                 :          0 : tapdisk_snprintf(char *buf, int * const off, int * const size,
     311                 :            :                 unsigned int depth,     const char *format, ...) {
     312                 :            : 
     313                 :            :         int err, i;
     314                 :            :         va_list ap;
     315                 :            : 
     316         [ #  # ]:          0 :         ASSERT(buf);
     317         [ #  # ]:          0 :         ASSERT(off);
     318         [ #  # ]:          0 :         ASSERT(size);
     319                 :            : 
     320         [ #  # ]:          0 :         for (i = 0; i < depth; i++) {
     321                 :          0 :                 err = snprintf(buf + *off, *size, "  ");
     322         [ #  # ]:          0 :                 if (err < 0)
     323                 :          0 :                         return errno;
     324                 :          0 :                 *off += err;
     325                 :          0 :                 *size -= err;
     326                 :            :         }
     327                 :            : 
     328                 :          0 :         va_start(ap, format);
     329                 :          0 :         err = vsnprintf(buf + *off, *size, format, ap);
     330                 :          0 :         va_end(ap);
     331         [ #  # ]:          0 :         if (err >= *size)
     332                 :            :                 return ENOBUFS;
     333         [ #  # ]:          0 :         else if (err < 0)
     334                 :          0 :                 return errno;
     335                 :          0 :         *off += err;
     336                 :          0 :         *size -= err;
     337                 :          0 :         return 0;
     338                 :            : }
     339                 :            : 
     340                 :            : void
     341                 :          0 : shm_init(struct shm *shm) {
     342                 :            : 
     343         [ #  # ]:          0 :     ASSERT(shm);
     344                 :            : 
     345                 :          0 :     shm->path = NULL;
     346                 :          0 :     shm->fd = -1;
     347                 :          0 :     shm->mem = NULL;
     348                 :          0 :     shm->size = 0;
     349                 :          0 : }
     350                 :            : 
     351                 :            : 
     352                 :            : int
     353                 :          0 : shm_destroy(struct shm *shm) {
     354                 :            : 
     355                 :          0 :     int err = 0;
     356                 :            : 
     357         [ #  # ]:          0 :     ASSERT(shm);
     358                 :            : 
     359         [ #  # ]:          0 :     if (shm->mem) {
     360                 :          0 :         err = munmap(shm->mem, shm->size);
     361         [ #  # ]:          0 :         if (err == -1) {
     362                 :          0 :             err = errno;
     363                 :          0 :             EPRINTF("failed to munmap %s: %s\n", shm->path,
     364                 :            :                     strerror(err));
     365                 :            :             goto out;
     366                 :            :         }
     367                 :          0 :         shm->mem = NULL;
     368                 :            :     }
     369                 :            : 
     370         [ #  # ]:          0 :     if (shm->fd != -1) {
     371                 :            :         do {
     372                 :          0 :             err = close(shm->fd);
     373         [ #  # ]:          0 :             if (err)
     374                 :          0 :                 err = errno;
     375         [ #  # ]:          0 :         } while (err == EINTR);
     376         [ #  # ]:          0 :         if (err) {
     377                 :          0 :             EPRINTF("failed to close %s: %s\n", shm->path, strerror(err));
     378                 :            :             goto out;
     379                 :            :         }
     380                 :          0 :         shm->fd = -1;
     381                 :            :     }
     382                 :            : 
     383         [ #  # ]:          0 :     if (shm->path) {
     384                 :          0 :         err = unlink(shm->path);
     385         [ #  # ]:          0 :         if (unlikely(err == -1)) {
     386                 :          0 :             err = errno;
     387         [ #  # ]:          0 :             if (unlikely(err != ENOENT))
     388                 :            :                 goto out;
     389                 :            :             else
     390                 :          0 :                 err = 0;
     391                 :            :         }
     392                 :            :     }
     393                 :            : 
     394                 :            : out:
     395                 :          0 :     return err;
     396                 :            : }
     397                 :            : 
     398                 :            : 
     399                 :            : int
     400                 :          0 : shm_create(struct shm *shm) {
     401                 :            : 
     402                 :            :     int err;
     403                 :            : 
     404         [ #  # ]:          0 :     ASSERT(shm);
     405         [ #  # ]:          0 :     ASSERT(shm->path);
     406         [ #  # ]:          0 :     ASSERT(shm->size);
     407                 :            : 
     408                 :          0 :     shm->fd = open(shm->path, O_CREAT | O_TRUNC | O_RDWR | O_EXCL,
     409                 :            :             S_IRUSR | S_IWUSR);
     410         [ #  # ]:          0 :     if (shm->fd == -1) {
     411                 :          0 :         err = errno;
     412                 :          0 :         EPRINTF("failed to open %s: %s\n", shm->path, strerror(err));
     413                 :            :         goto out;
     414                 :            :     }
     415                 :            : 
     416                 :          0 :     err = ftruncate(shm->fd, shm->size);
     417         [ #  # ]:          0 :     if (err == -1) {
     418                 :          0 :         err = errno;
     419                 :          0 :         EPRINTF("failed to truncate %s: %s\n", shm->path, strerror(err));
     420                 :            :         goto out;
     421                 :            :     }
     422                 :            : 
     423                 :          0 :     shm->mem = mmap(NULL, shm->size, PROT_READ | PROT_WRITE, MAP_SHARED,
     424                 :            :             shm->fd, 0);
     425         [ #  # ]:          0 :     if (shm->mem == MAP_FAILED) {
     426                 :          0 :         err = errno;
     427                 :          0 :         EPRINTF("failed to mmap %s: %s\n", shm->path, strerror(err));
     428                 :            :         goto out;
     429                 :            :     }
     430                 :            : 
     431                 :            : out:
     432         [ #  # ]:          0 :     if (err) {
     433                 :          0 :         int err2 = shm_destroy(shm);
     434         [ #  # ]:          0 :         if (err2)
     435                 :          0 :             EPRINTF("failed to clean up failed shared memory file creation: "
     436                 :            :                     "%s (error ignored)\n", strerror(-err2));
     437                 :            :     }
     438                 :          0 :     return err;
     439                 :            : }

Generated by: LCOV version 1.13