xref: /dragonfly/sbin/hammer2/cmd_setcomp.c (revision 938e74dc)
1 /*
2  * Copyright (c) 2013 The DragonFly Project.  All rights reserved.
3  *
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in
13  *    the documentation and/or other materials provided with the
14  *    distribution.
15  * 3. Neither the name of The DragonFly Project nor the names of its
16  *    contributors may be used to endorse or promote products derived
17  *    from this software without specific, prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
23  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
25  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
29  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 
33 #include "hammer2.h"
34 
35 static int cmd_setcomp_core(uint8_t comp_algo, const char *path_str,
36 			    struct stat *st);
37 
38 int
39 cmd_setcomp(const char *comp_str, char **paths)
40 {
41 	static const char *comps[] = HAMMER2_COMP_STRINGS;
42 	struct stat st;
43 	int comp_algo;
44 	int comp_level;
45 	int ecode;
46 	int res;
47 	char *str;
48 	const char *s1;
49 	const char *s2;
50 
51 	str = strdup(comp_str);
52 	s1 = strtok(str, ":");
53 	s2 = s1 ? strtok(NULL, ":") : NULL;
54 	ecode = 0;
55 
56 	if (isdigit(s1[0])) {
57 		comp_algo = strtol(s1, NULL, 0);
58 	} else {
59 		comp_algo = HAMMER2_COMP_STRINGS_COUNT;
60 		while (--comp_algo >= 0) {
61 			if (strcasecmp(s1, comps[comp_algo]) == 0)
62 				break;
63 		}
64 		if (comp_algo < 0 && strcasecmp(s1, "default") == 0) {
65 			comp_algo = HAMMER2_COMP_LZ4;
66 			s1 = "lz4";
67 		}
68 		if (comp_algo < 0 && strcasecmp(s1, "disabled") == 0) {
69 			comp_algo = HAMMER2_COMP_AUTOZERO;
70 			s1 = "autozero";
71 		}
72 		if (comp_algo < 0) {
73 			fprintf(stderr, "Unknown compression type: %s\n", s1);
74 			ecode = 3;
75 		}
76 	}
77 	if (s2 == NULL) {
78 		comp_level = 0;
79 	} else if (isdigit(s2[0])) {
80 		comp_level = strtol(s2, NULL, 0);
81 	} else if (strcasecmp(s2, "default") == 0) {
82 		comp_level = 0;
83 	} else {
84 		comp_level = 0;
85 		fprintf(stderr, "Unknown compression level: %s\n", s2);
86 		ecode = 3;
87 	}
88 
89 	if (comp_level) {
90 		switch(comp_algo) {
91 		case HAMMER2_COMP_ZLIB:
92 			if (comp_level < 6 || comp_level > 9) {
93 				fprintf(stderr,
94 					"Unsupported comp_level %d for %s\n",
95 					comp_level, s1);
96 				ecode = 3;
97 			}
98 			break;
99 		default:
100 			fprintf(stderr,
101 				"Unsupported comp_level %d for %s\n",
102 				comp_level, s1);
103 			ecode = 3;
104 		}
105 	}
106 
107 	if (ecode == 0) {
108 		while (*paths) {
109 			if (lstat(*paths, &st) == 0) {
110 				res = cmd_setcomp_core(
111 					HAMMER2_ENC_COMP(comp_algo) |
112 					 HAMMER2_ENC_LEVEL(comp_level),
113 				        *paths,
114 					&st);
115 				if (res)
116 					ecode = res;
117 			} else {
118 				printf("%s: %s\n", *paths, strerror(errno));
119 				ecode = 3;
120 			}
121 			++paths;
122 		}
123 	}
124 	free (str);
125 
126 	return ecode;
127 }
128 
129 static int
130 cmd_setcomp_core(uint8_t comp_algo, const char *path_str, struct stat *st)
131 {
132 	hammer2_ioc_inode_t inode;
133 	int fd;
134 	int res;
135 
136 	fd = hammer2_ioctl_handle(path_str);
137 	if (fd < 0) {
138 		res = 3;
139 		goto failed;
140 	}
141 	res = ioctl(fd, HAMMER2IOC_INODE_GET, &inode);
142 	if (res < 0) {
143 		fprintf(stderr,
144 			"%s: HAMMER2IOC_INODE_GET: error %s\n",
145 			path_str, strerror(errno));
146 		res = 3;
147 		goto failed;
148 	}
149 	printf("%s\tcomp_algo=0x%02x\n", path_str, comp_algo);
150 	inode.ip_data.comp_algo = comp_algo;
151 	res = ioctl(fd, HAMMER2IOC_INODE_SET, &inode);
152 	if (res < 0) {
153 		fprintf(stderr,
154 			"%s: HAMMER2IOC_INODE_SET: error %s\n",
155 			path_str, strerror(errno));
156 		res = 3;
157 		goto failed;
158 	}
159 	res = 0;
160 
161 	if (RecurseOpt && S_ISDIR(st->st_mode)) {
162 		DIR *dir;
163 		char *path;
164 		struct dirent *den;
165 
166 		if ((dir = fdopendir(fd)) != NULL) {
167 			while ((den = readdir(dir)) != NULL) {
168 				if (strcmp(den->d_name, ".") == 0 ||
169 				    strcmp(den->d_name, "..") == 0) {
170 					continue;
171 				}
172 				asprintf(&path, "%s/%s", path_str, den->d_name);
173 				if (lstat(path, st) == 0)
174 					cmd_setcomp_core(comp_algo, path, st);
175 				free(path);
176 			}
177 			closedir(dir);
178 		}
179 	}
180 failed:
181 	close(fd);
182 	return res;
183 }
184 
185 #if 0
186 
187 int
188 cmd_setcomp_recursive(char* option_string, char* comp_string, char* file_string)
189 {
190 	int ecode = 0;
191 	int set_files;
192 	int comp_method;
193 
194 	if (strcmp(option_string, "-r") == 0) {
195 		set_files = 0;
196 	} else if (strcmp(option_string, "-rf") == 0) {
197 		set_files = 1;
198 	} else {
199 		printf("setcomp: Unrecognized option.\n");
200 		exit(1);
201 	}
202 	if (strcmp(comp_string, "0") == 0) {
203 		printf("Will turn off compression on directory/file %s\n", file_string);
204 		comp_method = HAMMER2_COMP_NONE;
205 	} else if (strcmp(comp_string, "1") == 0) {
206 		printf("Will set zero-checking compression on directory/file %s.\n", file_string);
207 		comp_method = HAMMER2_COMP_AUTOZERO;
208 	} else if (strcmp(comp_string, "2") == 0) {
209 		printf("Will set LZ4 compression on directory/file %s.\n", file_string);
210 		comp_method = HAMMER2_COMP_LZ4;
211 	} else if (strcmp(comp_string, "3") == 0) {
212 		printf("Will set ZLIB (slowest) compression on directory/file %s.\n", file_string);
213 		comp_method = HAMMER2_COMP_ZLIB;
214 	}
215 	else {
216 		printf("Unknown compression method.\n");
217 		return 1;
218 	}
219 	int fd = hammer2_ioctl_handle(file_string);
220 	hammer2_ioc_inode_t inode;
221 	int res = ioctl(fd, HAMMER2IOC_INODE_GET, &inode);
222 	if (res < 0) {
223 		fprintf(stderr, "ERROR before setting the mode: %s\n", strerror(errno));
224 		return 3;
225 	}
226 	if (inode.ip_data.type != HAMMER2_OBJTYPE_DIRECTORY) {
227 		printf("setcomp: the specified object is not a directory, nothing changed.\n");
228 		return 1;
229 	}
230 	printf("Attention: recursive compression mode setting demanded, this may take a while...\n");
231 	ecode = setcomp_recursive_call(file_string, comp_method, set_files);
232 	inode.ip_data.comp_algo = comp_method;
233 	res = ioctl(fd, HAMMER2IOC_INODE_SET, &inode);
234 	if (res < 0) {
235 		if (errno != EINVAL) {
236 			fprintf(stderr, "ERROR after trying to set the mode: %s\n", strerror(errno));
237 			return 3;
238 		}
239 	}
240 	close(fd);
241 	return ecode;
242 }
243 
244 int
245 setcomp_recursive_call(char *directory, int comp_method, int set_files)
246 {
247 	int ecode = 0;
248 	DIR *dir;
249 	if ((dir = opendir (directory)) == NULL) {
250         fprintf(stderr, "ERROR while trying to set the mode recursively: %s\n",
251 			strerror(errno));
252 		return 3;
253     }
254     struct dirent *dent;
255     int lenght;
256     lenght = strlen(directory);
257     char name[HAMMER2_INODE_MAXNAME];
258     strcpy(name, directory);
259     name[lenght] = '/';
260     ++lenght;
261     errno = 0;
262     dent = readdir(dir);
263     while (dent != NULL && ecode == 0) {
264 		if ((strcmp(dent->d_name, ".") != 0) &&
265 		 (strcmp(dent->d_name, "..") != 0)) {
266 			strncpy(name + lenght, dent->d_name, HAMMER2_INODE_MAXNAME -
267 				lenght);
268 			int fd = hammer2_ioctl_handle(name);
269 			hammer2_ioc_inode_t inode;
270 			int res = ioctl(fd, HAMMER2IOC_INODE_GET, &inode);
271 			if (res < 0) {
272 				fprintf(stderr, "ERROR during recursion: %s\n",
273 					strerror(errno));
274 				return 3;
275 			}
276 			if (inode.ip_data.type == HAMMER2_OBJTYPE_DIRECTORY) {
277 				ecode = setcomp_recursive_call(name, comp_method, set_files);
278 				inode.ip_data.comp_algo = comp_method;
279 				res = ioctl(fd, HAMMER2IOC_INODE_SET, &inode);
280 			}
281 			else {
282 				if (set_files == 1 && inode.ip_data.type ==
283 						HAMMER2_OBJTYPE_REGFILE) {
284 					inode.ip_data.comp_algo = comp_method;
285 					res = ioctl(fd, HAMMER2IOC_INODE_SET, &inode);
286 				}
287 			}
288 			if (res < 0) {
289 				if (errno != EINVAL) {
290 					fprintf(stderr, "ERROR during recursion after trying"
291 						"to set the mode: %s\n",
292 						strerror(errno));
293 					return 3;
294 				}
295 			}
296 			close(fd);
297 		}
298 		errno = 0; //we must set errno to 0 before readdir()
299 		dent = readdir(dir);
300 	}
301 	closedir(dir);
302 	if (errno != 0) {
303 		fprintf(stderr, "ERROR during iteration: %s\n", strerror(errno));
304 		return 3;
305     }
306     return ecode;
307 }
308 
309 #endif
310