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