summaryrefslogtreecommitdiffstats
path: root/diskdev_cmds/setclass.tproj/setclass.c
diff options
context:
space:
mode:
Diffstat (limited to 'diskdev_cmds/setclass.tproj/setclass.c')
-rw-r--r--diskdev_cmds/setclass.tproj/setclass.c153
1 files changed, 153 insertions, 0 deletions
diff --git a/diskdev_cmds/setclass.tproj/setclass.c b/diskdev_cmds/setclass.tproj/setclass.c
new file mode 100644
index 0000000..306547b
--- /dev/null
+++ b/diskdev_cmds/setclass.tproj/setclass.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2010-2020 Apple Inc. All rights reserved.
+ */
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/attr.h>
+
+/* from sys/cprotect.h */
+
+#define PROTECTION_CLASS_A 1
+#define PROTECTION_CLASS_B 2
+#define PROTECTION_CLASS_C 3
+#define PROTECTION_CLASS_D 4
+#define PROTECTION_CLASS_E 5
+#define PROTECTION_CLASS_F 6
+
+void
+usage(void)
+{
+ printf("usage: setclass <path> [A-F]\n");
+ printf("\tsets <path> to a protection class from A to F.\n");
+ printf("\tIf no class is specified, reports the current class for <path>.\n");
+ exit(0);
+}
+
+int
+chartoclass(char c)
+{
+ switch (c) {
+ /* directory 'unset' operation */
+ case '0':
+ return 0;
+ case 'A':
+ case 'a':
+ return PROTECTION_CLASS_A;
+ case 'B':
+ case 'b':
+ return PROTECTION_CLASS_B;
+ case 'C':
+ case 'c':
+ return PROTECTION_CLASS_C;
+ case 'D':
+ case 'd':
+ return PROTECTION_CLASS_D;
+ case 'E':
+ case 'e':
+ return PROTECTION_CLASS_E;
+ case 'F':
+ case 'f':
+ return PROTECTION_CLASS_F;
+ default:
+ usage();
+ exit(0);
+ }
+ return 0;
+}
+
+char
+classtochar(int class)
+{
+ if (class < 0) {
+ /* negative classes are invalid */
+ return -1;
+ }
+
+ /* otherwise, it must be >= 0... */
+ if (class == 0) {
+ /* Directories are allowed to be "unset" */
+ return 0;
+ }
+ return 'A' + (class - 1);
+}
+
+int
+main(int argc, char **argv)
+{
+ int error = 0, class = 0, do_set = 0;
+ static struct attrlist req = {
+ .bitmapcount = ATTR_BIT_MAP_COUNT,
+ .commonattr = ATTR_CMN_DATA_PROTECT_FLAGS
+ };
+
+ if ((argc < 2) || (argc > 3))
+ usage();
+
+ if (argv[2]) {
+ do_set = 1;
+ class = chartoclass(*argv[2]);
+ }
+
+ /*
+ * setclass and getclass for `argv[1]` using setattrlist(2) and
+ * getattrlist(2) respectively.
+ */
+ if (do_set) {
+ struct {
+ uint32_t prot_class;
+ } __attribute__((packed, aligned(4))) attrs = {
+ .prot_class = class
+ };
+
+ error = setattrlist(argv[1], (void *)&req, &attrs, sizeof(attrs),
+ FSOPT_NOFOLLOW);
+ if (error) {
+ char new_class = classtochar(class);
+ if (new_class == 0) {
+ warn("could not set protection class of %s to (directory none)",
+ argv[1]);
+ }
+ else {
+ warn("could not set protection class of %s to %c", argv[1],
+ new_class);
+ }
+ }
+ }
+ else {
+ req.commonattr |= ATTR_CMN_RETURNED_ATTRS;
+
+ struct {
+ uint32_t len;
+ attribute_set_t returned;
+ uint32_t prot_class;
+ } __attribute__((packed, aligned(4))) attrs;
+
+ error = getattrlist(argv[1], (void *)&req, &attrs, sizeof(attrs),
+ FSOPT_NOFOLLOW);
+ if (error == -1 || attrs.len != sizeof(attrs) ||
+ attrs.returned.commonattr != req.commonattr) {
+ if (error == -1) {
+ error = errno;
+ }
+ else {
+ error = EINVAL;
+ }
+ err(error, "could not get protection class");
+ }
+ else {
+ class = attrs.prot_class;
+ char new_class = classtochar(class);
+ if (new_class == 0) {
+ printf("%s is in protection class (directory none) \n", argv[1]);
+ }
+ else {
+ printf("%s is in protection class %c\n", argv[1], new_class);
+ }
+ }
+ }
+
+ return error;
+}