Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/icon-themes/   (LibreOffice Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 2 kB image not shown  

Quelle  hv_vss_daemon.c   Sprache: unbekannt

 
// SPDX-License-Identifier: GPL-2.0-only
/*
 * An implementation of the host initiated guest snapshot for Hyper-V.
 *
 * Copyright (C) 2013, Microsoft, Inc.
 * Author : K. Y. Srinivasan <kys@microsoft.com>
 */



#include <sys/types.h>
#include <sys/poll.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/sysmacros.h>
#include <fcntl.h>
#include <stdio.h>
#include <mntent.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <linux/fs.h>
#include <linux/major.h>
#include <linux/hyperv.h>
#include <syslog.h>
#include <getopt.h>
#include <stdbool.h>
#include <dirent.h>

static bool fs_frozen;

/* Don't use syslog() in the function since that can cause write to disk */
static int vss_do_freeze(char *dir, unsigned int cmd)
{
 int ret, fd = open(dir, O_RDONLY);

 if (fd < 0)
  return 1;

 ret = ioctl(fd, cmd, 0);

 /*
 * If a partition is mounted more than once, only the first
 * FREEZE/THAW can succeed and the later ones will get
 * EBUSY/EINVAL respectively: there could be 2 cases:
 * 1) a user may mount the same partition to different directories
 *  by mistake or on purpose;
 * 2) The subvolume of btrfs appears to have the same partition
 * mounted more than once.
 */

 if (ret) {
  if ((cmd == FIFREEZE && errno == EBUSY) ||
      (cmd == FITHAW && errno == EINVAL)) {
   close(fd);
   return 0;
  }
 }

 close(fd);
 return !!ret;
}

static bool is_dev_loop(const char *blkname)
{
 char *buffer;
 DIR *dir;
 struct dirent *entry;
 bool ret = false;

 buffer = malloc(PATH_MAX);
 if (!buffer) {
  syslog(LOG_ERR, "Can't allocate memory!");
  exit(1);
 }

 snprintf(buffer, PATH_MAX, "%s/loop", blkname);
 if (!access(buffer, R_OK | X_OK)) {
  ret = true;
  goto free_buffer;
 } else if (errno != ENOENT) {
  syslog(LOG_ERR, "Can't access: %s; error:%d %s!",
         buffer, errno, strerror(errno));
 }

 snprintf(buffer, PATH_MAX, "%s/slaves", blkname);
 dir = opendir(buffer);
 if (!dir) {
  if (errno != ENOENT)
   syslog(LOG_ERR, "Can't opendir: %s; error:%d %s!",
          buffer, errno, strerror(errno));
  goto free_buffer;
 }

 while ((entry = readdir(dir)) != NULL) {
  if (strcmp(entry->d_name, ".") == 0 ||
      strcmp(entry->d_name, "..") == 0)
   continue;

  snprintf(buffer, PATH_MAX, "%s/slaves/%s", blkname,
    entry->d_name);
  if (is_dev_loop(buffer)) {
   ret = true;
   break;
  }
 }
 closedir(dir);
free_buffer:
 free(buffer);
 return ret;
}

static int vss_operate(int operation)
{
 char match[] = "/dev/";
 FILE *mounts;
 struct mntent *ent;
 struct stat sb;
 char errdir[1024] = {0};
 char blkdir[23]; /* /sys/dev/block/XXX:XXX */
 unsigned int cmd;
 int error = 0, root_seen = 0, save_errno = 0;

 switch (operation) {
 case VSS_OP_FREEZE:
  cmd = FIFREEZE;
  break;
 case VSS_OP_THAW:
  cmd = FITHAW;
  break;
 default:
  return -1;
 }

 mounts = setmntent("/proc/mounts""r");
 if (mounts == NULL)
  return -1;

 while ((ent = getmntent(mounts))) {
  if (strncmp(ent->mnt_fsname, match, strlen(match)))
   continue;
  if (stat(ent->mnt_fsname, &sb)) {
   syslog(LOG_ERR, "Can't stat: %s; error:%d %s!",
          ent->mnt_fsname, errno, strerror(errno));
  } else {
   sprintf(blkdir, "/sys/dev/block/%d:%d",
    major(sb.st_rdev), minor(sb.st_rdev));
   if (is_dev_loop(blkdir))
    continue;
  }
  if (hasmntopt(ent, MNTOPT_RO) != NULL)
   continue;
  if (strcmp(ent->mnt_type, "vfat") == 0)
   continue;
  if (strcmp(ent->mnt_dir, "/") == 0) {
   root_seen = 1;
   continue;
  }
  error |= vss_do_freeze(ent->mnt_dir, cmd);
  if (operation == VSS_OP_FREEZE) {
   if (error)
    goto err;
   fs_frozen = true;
  }
 }

 endmntent(mounts);

 if (root_seen) {
  error |= vss_do_freeze("/", cmd);
  if (operation == VSS_OP_FREEZE) {
   if (error)
    goto err;
   fs_frozen = true;
  }
 }

 if (operation == VSS_OP_THAW && !error)
  fs_frozen = false;

 goto out;
err:
 save_errno = errno;
 if (ent) {
  strncpy(errdir, ent->mnt_dir, sizeof(errdir)-1);
  endmntent(mounts);
 }
 vss_operate(VSS_OP_THAW);
 fs_frozen = false;
 /* Call syslog after we thaw all filesystems */
 if (ent)
  syslog(LOG_ERR, "FREEZE of %s failed; error:%d %s",
         errdir, save_errno, strerror(save_errno));
 else
  syslog(LOG_ERR, "FREEZE of / failed; error:%d %s", save_errno,
         strerror(save_errno));
out:
 return error;
}

void print_usage(char *argv[])
{
 fprintf(stderr, "Usage: %s [options]\n"
  "Options are:\n"
  "  -n, --no-daemon        stay in foreground, don't daemonize\n"
  "  -h, --help             print this help\n", argv[0]);
}

int main(int argc, char *argv[])
{
 int vss_fd = -1, len;
 int error;
 struct pollfd pfd;
 int op;
 struct hv_vss_msg vss_msg[1];
 int daemonize = 1, long_index = 0, opt;
 int in_handshake;
 __u32 kernel_modver;

 static struct option long_options[] = {
  {"help", no_argument,    0,  'h' },
  {"no-daemon", no_argument,    0,  'n' },
  {0,  0,     0,  0   }
 };

 while ((opt = getopt_long(argc, argv, "hn", long_options,
      &long_index)) != -1) {
  switch (opt) {
  case 'n':
   daemonize = 0;
   break;
  case 'h':
   print_usage(argv);
   exit(0);
  default:
   print_usage(argv);
   exit(EXIT_FAILURE);
  }
 }

 if (daemonize && daemon(10))
  return 1;

 openlog("Hyper-V VSS"0, LOG_USER);
 syslog(LOG_INFO, "VSS starting; pid is:%d", getpid());

reopen_vss_fd:
 if (vss_fd != -1)
  close(vss_fd);
 if (fs_frozen) {
  if (vss_operate(VSS_OP_THAW) || fs_frozen) {
   syslog(LOG_ERR, "failed to thaw file system: err=%d",
          errno);
   exit(EXIT_FAILURE);
  }
 }

 in_handshake = 1;
 vss_fd = open("/dev/vmbus/hv_vss", O_RDWR);
 if (vss_fd < 0) {
  syslog(LOG_ERR, "open /dev/vmbus/hv_vss failed; error: %d %s",
         errno, strerror(errno));
  exit(EXIT_FAILURE);
 }
 /*
 * Register ourselves with the kernel.
 */

 vss_msg->vss_hdr.operation = VSS_OP_REGISTER1;

 len = write(vss_fd, vss_msg, sizeof(struct hv_vss_msg));
 if (len < 0) {
  syslog(LOG_ERR, "registration to kernel failed; error: %d %s",
         errno, strerror(errno));
  close(vss_fd);
  exit(EXIT_FAILURE);
 }

 pfd.fd = vss_fd;

 while (1) {
  pfd.events = POLLIN;
  pfd.revents = 0;

  if (poll(&pfd, 1, -1) < 0) {
   syslog(LOG_ERR, "poll failed; error:%d %s", errno, strerror(errno));
   if (errno == EINVAL) {
    close(vss_fd);
    exit(EXIT_FAILURE);
   }
   else
    continue;
  }

  len = read(vss_fd, vss_msg, sizeof(struct hv_vss_msg));

  if (in_handshake) {
   if (len != sizeof(kernel_modver)) {
    syslog(LOG_ERR, "invalid version negotiation");
    exit(EXIT_FAILURE);
   }
   kernel_modver = *(__u32 *)vss_msg;
   in_handshake = 0;
   syslog(LOG_INFO, "VSS: kernel module version: %d",
          kernel_modver);
   continue;
  }

  if (len != sizeof(struct hv_vss_msg)) {
   syslog(LOG_ERR, "read failed; error:%d %s",
          errno, strerror(errno));
   goto reopen_vss_fd;
  }

  op = vss_msg->vss_hdr.operation;
  error =  HV_S_OK;

  switch (op) {
  case VSS_OP_FREEZE:
  case VSS_OP_THAW:
   error = vss_operate(op);
   syslog(LOG_INFO, "VSS: op=%s: %s\n",
    op == VSS_OP_FREEZE ? "FREEZE" : "THAW",
    error ? "failed" : "succeeded");

   if (error) {
    error = HV_E_FAIL;
    syslog(LOG_ERR, "op=%d failed!", op);
    syslog(LOG_ERR, "report it with these files:");
    syslog(LOG_ERR, "/etc/fstab and /proc/mounts");
   }
   break;
  case VSS_OP_HOT_BACKUP:
   syslog(LOG_INFO, "VSS: op=CHECK HOT BACKUP\n");
   break;
  default:
   syslog(LOG_ERR, "Illegal op:%d\n", op);
  }

  /*
 * The write() may return an error due to the faked VSS_OP_THAW
 * message upon hibernation. Ignore the error by resetting the
 * dev file, i.e. closing and re-opening it.
 */

  vss_msg->error = error;
  len = write(vss_fd, vss_msg, sizeof(struct hv_vss_msg));
  if (len != sizeof(struct hv_vss_msg)) {
   syslog(LOG_ERR, "write failed; error: %d %s", errno,
          strerror(errno));
   goto reopen_vss_fd;
  }
 }

 close(vss_fd);
 exit(0);
}

Messung V0.5 in Prozent
C=96 H=93 G=94

[zur Elbe Produktseite wechseln0.34QuellennavigatorsAnalyse erneut starten2026-06-08]