Skip to content

Commit

Permalink
Fix running from PATH and add better usage/manpage (#5)
Browse files Browse the repository at this point in the history
* Misc changes

- Don't segfault when ran from PATH
- Remove useless `-u` arg from usage
- Elaborate on usage

* Add manpage

* usage: Use spaces not tabs

* Add snaputil -o

This will query the IORegistry to determine what the system apfs
snapshot's name should be.

* Update manpage

Co-authored-by: Cameron Katri <[email protected]>
  • Loading branch information
Diatrus and CRKatri authored Mar 13, 2022
1 parent 1cb945d commit 2bcf604
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 10 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
all: snapUtil

snapUtil: snapUtil.c
clang -Wall -Os -g -o snapUtil snapUtil.c
clang -Wall -Os -g -o snapUtil snapUtil.c -framework CoreFoundation -framework IOKit

clean:
rm -f snapUtil
66 changes: 57 additions & 9 deletions snapUtil.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,22 @@
#include <sys/attr.h>
#include <sys/snapshot.h>

#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/IOKitLib.h>

const char *g_pname;

void
usage(void)
{
(void) fprintf(stderr, "Usage:\n");
(void) fprintf(stderr, "\t%s -l <vol>\n", g_pname);
(void) fprintf(stderr, "\t%s -c <snap> <vol>\n", g_pname);
(void) fprintf(stderr, "\t%s -n <snap> <newname> <vol>\n", g_pname);
(void) fprintf(stderr, "\t%s -d <snap> <vol>\n", g_pname);
(void) fprintf(stderr, "\t%s -r <snap> <vol>\n", g_pname);
(void) fprintf(stderr, "\t%s -s <snap> <vol> <mntpnt>\n", g_pname);
(void) fprintf(stderr, "\t%s -u <snap> <vol>\n", g_pname);
(void) fprintf(stderr, "\t%s -l <vol> (List all 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);
(void) fprintf(stderr, "\t%s -o (Print original snapshot name)\n", g_pname);
exit(2);
}

Expand Down Expand Up @@ -153,13 +156,54 @@ do_list(const char *vol)
return (0);
}

int
do_origName(void) {
const UInt8 *bytes;
CFIndex length;
CFDataRef manifestHash, rootSnapshotName;

io_registry_entry_t chosen = IORegistryEntryFromPath(0, "IODeviceTree:/chosen");

rootSnapshotName = IORegistryEntryCreateCFProperty(chosen, CFSTR("root-snapshot-name"), kCFAllocatorDefault, 0);

if (rootSnapshotName != NULL && CFGetTypeID(rootSnapshotName) == CFDataGetTypeID()) {
CFStringRef snapshotString = CFStringCreateFromExternalRepresentation(kCFAllocatorDefault, rootSnapshotName, kCFStringEncodingUTF8);
CFRelease(rootSnapshotName);
char buffer[100];
const char *ptr = CFStringGetCStringPtr(snapshotString, kCFStringEncodingUTF8);
if (ptr == NULL) {
if (CFStringGetCString(snapshotString, buffer, 100, kCFStringEncodingUTF8))
ptr = buffer;
}
printf("%s\n", ptr);
} else {
manifestHash = (CFDataRef)IORegistryEntryCreateCFProperty(chosen, CFSTR("boot-manifest-hash"), kCFAllocatorDefault, 0);
IOObjectRelease(chosen);

if (manifestHash == NULL || CFGetTypeID(manifestHash) != CFDataGetTypeID()) {
fprintf(stderr, "Unable to read boot-manifest-hash or root-snapshot-name\n");
return 1;
}

length = CFDataGetLength(manifestHash);
bytes = CFDataGetBytePtr(manifestHash);
CFRelease(manifestHash);

printf("com.apple.os.update-");
for (int i = 0; i < length; i++)
printf("%02X", bytes[i]);
printf("\n");
}

return 0;
}

int
main(int argc, char **argv)
{
g_pname = strrchr(argv[0], '/') + 1;
g_pname = argv[0];

if (argc < 3 || argv[1][0] != '-' ||
if (argc < 2 || argv[1][0] != '-' ||
argv[1][1] == '\0' || argv[1][2] != '\0') {
usage();
}
Expand Down Expand Up @@ -189,6 +233,10 @@ main(int argc, char **argv)
if (argc != 4)
usage();
return (do_revert(argv[3], argv[2]));
case 'o':
if (argc != 2)
usage();
return (do_origName());
default:
usage();
}
Expand Down
69 changes: 69 additions & 0 deletions snaputil.1
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
.\"-
.\" Copyright (c) 2021 Cameron Katri
.\" SPDX-License-Identifier: Apache-2.0
.\"
.Dd September 28, 2021
.Dt SNAPUTIL 1
.Os
.Sh NAME
.Nm snaputil
.Nd manipulate APFS snapshots
.Sh SYNOPSIS
.Nm
.Oo
.Fl c Ar name Ar volume |
.Fl d Ar name Ar volume |
.Fl l Ar volume |
.Fl n Ar name Ar newname Ar volume |
.Fl o |
.Fl r Ar name Ar volume |
.Fl s Ar name Ar volume Ar mnt
.Oc
.Sh DESCRIPTION
.Nm
perform the selected action on the specified APFS volume, then exits.
.Bl -tag -width -indent
.It Fl c Ar name Ar volume
Create a snapshot called
.Ar name
on
.Ar volume .
.It Fl d Ar name Ar volume
Delete the snapshot named
.Ar name
on
.Ar volume .
.It Fl l Ar volume
List the snapshots on
.Ar volume .
.It Fl n Ar name Ar newname Ar volume
Rename the snapshot in
.Ar volume
for
.Ar name
to
.Ar newname .
.It Fl o
Query the IORegistry to determine what the system apfs snapshot's name should be.
.It Fl r Ar name Ar volume
Revert
.Ar volume
to the snapshot
.Ar name .
.It Fl s Ar name Ar volume Ar mnt
Mount the snapshot
.Ar name
from
.Ar volume
at
.Ar mnt .
.El
.Sh HISTORY
The
.Nm
utility was written on Feburary 9, 2017, by
.An Adam H. Leventhal
then updated on Janurary 22, 2018 by
.An Blair Zajac
to use
.In sys/snapshot.h .

0 comments on commit 2bcf604

Please sign in to comment.