Created
May 31, 2018 19:46
-
-
Save stek29/b4f6c2750713a36bd61995b54e3d2eaf to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright 2017 Adam H. Leventhal. All Rights Reserved. | |
*/ | |
#include <unistd.h> | |
#include <fcntl.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <strings.h> | |
#include <unistd.h> | |
#include <errno.h> | |
#include <sys/attr.h> | |
#include <sys/snapshot.h> | |
#define HAVE_OP_ROOT !defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) | |
#if HAVE_OP_ROOT | |
int fs_snapshot_root(int, const char *, uint32_t); | |
#endif | |
const char *g_pname; | |
void | |
usage(void) | |
{ | |
(void) fprintf(stderr, "Usage:\n"); | |
(void) fprintf(stderr, "\t%s -l <vol> -- list snapshots\n", g_pname); | |
(void) fprintf(stderr, "\t%s -c <snap> <vol> -- create snapshot\n", g_pname); | |
(void) fprintf(stderr, "\t%s -n <snap> <newname> <vol> -- rename snapshot\n", g_pname); | |
(void) fprintf(stderr, "\t%s -d <snap> <vol> -- delete snapshot\n", g_pname); | |
(void) fprintf(stderr, "\t%s -r <snap> <vol -- revert to snapshot\n", g_pname); | |
(void) fprintf(stderr, "\t%s -s <snap> <vol> <mntpnt> -- mount snapshot\n", g_pname); | |
#if HAVE_OP_ROOT | |
(void) fprintf(stderr, "\t%s -R <snap> <vol> -- set rootfs to snapshot on next boot -- non-osx only\n", g_pname); | |
#endif | |
exit(2); | |
} | |
int | |
do_create(const char *vol, const char *snap) | |
{ | |
int dirfd = open(vol, O_RDONLY, 0); | |
if (dirfd < 0) { | |
perror("open"); | |
exit(1); | |
} | |
int ret = fs_snapshot_create(dirfd, snap, 0); | |
if (ret != 0) | |
perror("fs_snapshot_create"); | |
return (ret); | |
} | |
int | |
do_delete(const char *vol, const char *snap) | |
{ | |
int dirfd = open(vol, O_RDONLY, 0); | |
if (dirfd < 0) { | |
perror("open"); | |
exit(1); | |
} | |
int ret = fs_snapshot_delete(dirfd, snap, 0); | |
if (ret != 0) | |
perror("fs_snapshot_delete"); | |
return (ret); | |
} | |
int | |
do_revert(const char *vol, const char *snap) | |
{ | |
int dirfd = open(vol, O_RDONLY, 0); | |
if (dirfd < 0) { | |
perror("open"); | |
exit(1); | |
} | |
int ret = fs_snapshot_revert(dirfd, snap, 0); | |
if (ret != 0) | |
perror("fs_snapshot_revert"); | |
return (ret); | |
} | |
int | |
do_rename(const char *vol, const char *snap, const char *nw) | |
{ | |
int dirfd = open(vol, O_RDONLY, 0); | |
if (dirfd < 0) { | |
perror("open"); | |
exit(1); | |
} | |
int ret = fs_snapshot_rename(dirfd, snap, nw, 0); | |
if (ret != 0) | |
perror("fs_snapshot_rename"); | |
return (ret); | |
} | |
#if HAVE_OP_ROOT | |
int | |
do_root(const char *vol, const char *snap) | |
{ | |
int dirfd = open(vol, O_RDONLY, 0); | |
if (dirfd < 0) { | |
perror("open"); | |
exit(1); | |
} | |
int ret = fs_snapshot_root(dirfd, snap, 0); | |
if (ret != 0) | |
perror("fs_snapshot_root"); | |
return (ret); | |
} | |
#endif | |
int | |
do_mount(const char *vol, const char *snap, const char *mntpnt) | |
{ | |
int dirfd = open(vol, O_RDONLY, 0); | |
if (dirfd < 0) { | |
perror("open"); | |
exit(1); | |
} | |
int ret = fs_snapshot_mount(dirfd, mntpnt, snap, 0); | |
if (ret != 0) { | |
perror("fs_snapshot_mount"); | |
} else { | |
printf("mount_apfs: snapshot implicitly mounted readonly\n"); | |
} | |
return (ret); | |
} | |
int | |
do_list(const char *vol) | |
{ | |
int dirfd = open(vol, O_RDONLY, 0); | |
if (dirfd < 0) { | |
perror("open"); | |
exit(1); | |
} | |
struct attrlist alist = { 0 }; | |
char abuf[2048]; | |
alist.commonattr = ATTR_BULK_REQUIRED; | |
int count = fs_snapshot_list(dirfd, &alist, &abuf[0], sizeof (abuf), 0); | |
if (count < 0) { | |
perror("fs_snapshot_list"); | |
exit(1); | |
} | |
char *p = &abuf[0]; | |
for (int i = 0; i < count; i++) { | |
char *field = p; | |
uint32_t len = *(uint32_t *)field; | |
field += sizeof (uint32_t); | |
attribute_set_t attrs = *(attribute_set_t *)field; | |
field += sizeof (attribute_set_t); | |
if (attrs.commonattr & ATTR_CMN_NAME) { | |
attrreference_t ar = *(attrreference_t *)field; | |
char *name = field + ar.attr_dataoffset; | |
field += sizeof (attrreference_t); | |
(void) printf("%s\n", name); | |
} | |
p += len; | |
} | |
return (0); | |
} | |
int | |
main(int argc, char **argv) | |
{ | |
g_pname = strrchr(argv[0], '/') + 1; | |
if (argc < 3 || argv[1][0] != '-' || | |
argv[1][1] == '\0' || argv[1][2] != '\0') { | |
usage(); | |
} | |
switch (argv[1][1]) { | |
case 'l': | |
if (argc != 3) | |
usage(); | |
return (do_list(argv[2])); | |
case 'c': | |
if (argc != 4) | |
usage(); | |
return (do_create(argv[3], argv[2])); | |
case 'd': | |
if (argc != 4) | |
usage(); | |
return (do_delete(argv[3], argv[2])); | |
case 'n': | |
if (argc != 5) | |
usage(); | |
return (do_rename(argv[4], argv[2], argv[3])); | |
case 's': | |
if (argc != 5) | |
usage(); | |
return (do_mount(argv[3], argv[2], argv[4])); | |
case 'r': | |
if (argc != 4) | |
usage(); | |
return (do_revert(argv[3], argv[2])); | |
#if HAVE_OP_ROOT | |
case 'R': | |
if (argc != 4) | |
usage(); | |
return (do_root(argv[3], argv[2])); | |
#endif | |
default: | |
usage(); | |
} | |
return (0); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment