1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
14  */
15 
16 #include <sys/types.h>
17 #include <sys/stat.h>
18 
19 #include <attr.h>
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <unistd.h>
25 #include <libnvpair.h>
26 
27 extern const char *__progname;
28 
29 int vflag = 0;
30 
31 static int
dosattr_set_ro(int fildes,const char * fname)32 dosattr_set_ro(int fildes, const char *fname)
33 {
34 	nvlist_t	*nvl = NULL;
35 	int		err;
36 
37 	err = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0);
38 	if (err != 0)
39 		return (err);
40 
41 	(void) nvlist_add_boolean_value(nvl, A_READONLY, 1);
42 
43 	if (fname == NULL) {
44 		err = fsetattr(fildes, XATTR_VIEW_READWRITE, nvl);
45 	} else {
46 		err = setattrat(fildes, XATTR_VIEW_READWRITE, fname, nvl);
47 	}
48 	if (err < 0) {
49 		err = errno;
50 		if (vflag > 1) {
51 			(void) fprintf(stderr,
52 			    "dosattr_set: setattrat (%s), err %d\n",
53 			    fname, err);
54 		}
55 	}
56 
57 	nvlist_free(nvl);
58 
59 	return (err);
60 }
61 
62 void
usage(void)63 usage(void)
64 {
65 	(void) fprintf(stderr, "usage: %s [-v] file\n",
66 	    __progname);
67 	exit(1);
68 }
69 
70 int
main(int argc,char ** argv)71 main(int argc, char **argv)
72 {
73 	char *fname;
74 	int c, fd, n;
75 
76 	while ((c = getopt(argc, argv, "v")) != -1) {
77 		switch (c) {
78 		case 'v':
79 			vflag++;
80 			break;
81 		case '?':
82 		default:
83 			usage();
84 			break;
85 		}
86 	}
87 
88 	if (optind + 1 != argc)
89 		usage();
90 	fname = argv[optind];
91 
92 	fd = open(fname, O_CREAT | O_RDWR, 0644);
93 	if (fd < 0) {
94 		perror(fname);
95 		exit(1);
96 	}
97 
98 	if (vflag)
99 		(void) fprintf(stderr, "Write 1 (mode 644)\n");
100 	n = write(fd, "mode 644 OK\n", 12);
101 	if (n != 12) {
102 		(void) fprintf(stderr, "write mode 644, err=%d\n", errno);
103 		exit(1);
104 	}
105 
106 	if (vflag)
107 		(void) fprintf(stderr, "Chmod 444\n");
108 	n = fchmod(fd, 0444);
109 	if (n < 0) {
110 		(void) fprintf(stderr, "chmod 444, err=%d\n", errno);
111 		exit(1);
112 	}
113 
114 	if (vflag)
115 		(void) fprintf(stderr, "Write 2 (mode 444)\n");
116 	n = write(fd, "mode 444 OK\n", 12);
117 	if (n != 12) {
118 		(void) fprintf(stderr, "write mode 444, err=%d\n", errno);
119 		exit(1);
120 	}
121 
122 	if (vflag)
123 		(void) fprintf(stderr, "Set DOS R/O\n");
124 	n = dosattr_set_ro(fd, NULL /* fname? */);
125 	if (n != 0) {
126 		(void) fprintf(stderr, "Set R/O, err=%d\n", n);
127 		exit(1);
128 	}
129 
130 	/*
131 	 * This fails, but write on an already open handle should succeed
132 	 * the same as when we've set the mode to 444 after open.
133 	 */
134 	if (vflag)
135 		(void) fprintf(stderr, "Write 3 (DOS R/O)\n");
136 	n = write(fd, "Write DOS RO?\n", 14);
137 	if (n != 14) {
138 		(void) fprintf(stderr, "write (DOS R/O), err=%d\n", errno);
139 		exit(1);
140 	}
141 
142 	return (0);
143 }
144