1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
|
/*
* Copyright (C) 2022 Ernesto A. Fernández <ernesto@corellium.com>
*/
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "version.h"
static char *progname;
/**
* usage - Print usage information and exit
*/
static void usage(void)
{
fprintf(stderr, "usage: %s [-v] mountpoint name\n", progname);
exit(EXIT_FAILURE);
}
/**
* version - Print version information and exit
*/
static void version(void)
{
if (*GIT_COMMIT) {
printf("apfs-snap %s\n", GIT_COMMIT);
exit(EXIT_SUCCESS);
} else {
printf("apfs-snap - unknown git commit id\n");
exit(EXIT_FAILURE);
}
}
/**
* system_error - Print a system error message and exit
*/
static __attribute__((noreturn)) void system_error(void)
{
perror(progname);
exit(EXIT_FAILURE);
}
/**
* fatal - Print a message and exit with an error code
* @message: text to print
*/
static __attribute__((noreturn)) void fatal(const char *message)
{
fprintf(stderr, "%s: %s\n", progname, message);
exit(EXIT_FAILURE);
}
#define APFS_SNAP_MAX_NAMELEN 255
struct apfs_ioctl_snap_name {
char name[APFS_SNAP_MAX_NAMELEN + 1];
};
#define APFS_IOC_TAKE_SNAPSHOT _IOW('@', 0x85, struct apfs_ioctl_snap_name)
/**
* create_snapshot - Submit the snapshot creation request to the driver
* @fd: open file descriptor for the mountpoint
* @name: label for the snapshot
*/
static void create_snapshot(int fd, const char *name)
{
static struct apfs_ioctl_snap_name arg = {0};
if (strlen(name) > APFS_SNAP_MAX_NAMELEN)
fatal("snapshot label is too long");
strcpy(arg.name, name);
if (ioctl(fd, APFS_IOC_TAKE_SNAPSHOT, &arg) < 0)
system_error();
}
int main(int argc, char *argv[])
{
const char *mountpoint = NULL;
const char *snapname = NULL;
int fd;
if (argc == 0)
exit(EXIT_FAILURE);
progname = argv[0];
while (1) {
int opt = getopt(argc, argv, "v");
if (opt == -1)
break;
switch (opt) {
case 'v':
version();
default:
usage();
}
}
if (optind != argc - 2)
usage();
mountpoint = argv[optind];
snapname = argv[optind + 1];
fd = open(mountpoint, O_RDONLY);
if (fd == -1)
system_error();
create_snapshot(fd, snapname);
return 0;
}
|