1 /*
2  * Copyright (C) 2021 Jakub Kruszona-Zawadzki, Core Technology Sp. z o.o.
3  *
4  * This file is part of MooseFS.
5  *
6  * MooseFS is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, version 2 (only).
9  *
10  * MooseFS is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with MooseFS; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02111-1301, USA
18  * or visit http://www.gnu.org/licenses/gpl-2.0.html
19  */
20 
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 
25 #include <stdio.h>
26 #include <string.h>
27 #include <math.h>
28 #include <limits.h>
29 #include <stdlib.h>
30 #include <sys/types.h>
31 #include <sys/param.h>
32 #include <sys/stat.h>
33 #include <sys/statvfs.h>
34 #include <sys/time.h>
35 #include <unistd.h>
36 #include <fcntl.h>
37 #include <inttypes.h>
38 #include <poll.h>
39 #include <errno.h>
40 
41 #include "labelparser.h"
42 #include "datapack.h"
43 #include "massert.h"
44 #include "strerr.h"
45 #include "mfsstrerr.h"
46 #include "sockets.h"
47 #include "hashfn.h"
48 #include "liset64.h"
49 #include "clocks.h"
50 #include "md5.h"
51 #include "MFSCommunication.h"
52 #include "idstr.h"
53 
54 #include "mfstools_master.h"
55 
56 #define tcpread(s,b,l) tcptoread(s,b,l,20000)
57 #define tcpwrite(s,b,l) tcptowrite(s,b,l,20000)
58 
59 #define FILEINFO_QUICK 0x01
60 #define FILEINFO_CRC 0x02
61 #define FILEINFO_SIGNATURE 0x04
62 
63 #define DIRINFO_INODES 0x01
64 #define DIRINFO_DIRS 0x02
65 #define DIRINFO_FILES 0x04
66 #define DIRINFO_CHUNKS 0x08
67 #define DIRINFO_LENGTH 0x10
68 #define DIRINFO_SIZE 0x20
69 #define DIRINFO_REALSIZE 0x40
70 #define DIRINFO_PRECISE 0x80
71 
72 #define INODE_VALUE_MASK 0x1FFFFFFF
73 #define INODE_TYPE_MASK 0x60000000
74 #define INODE_TYPE_TRASH 0x20000000
75 #define INODE_TYPE_SUSTAINED 0x40000000
76 #define INODE_TYPE_SPECIAL 0x00000000
77 
78 static const char* eattrtab[EATTR_BITS]={EATTR_STRINGS};
79 static const char* eattrdesc[EATTR_BITS]={EATTR_DESCRIPTIONS};
80 
81 static uint8_t humode=0;
82 static uint8_t numbermode=0;
83 
84 #define PHN_USESI       0x01
85 #define PHN_USEIEC      0x00
print_humanized_number(const char * format,uint64_t number,uint8_t flags)86 void print_humanized_number(const char *format,uint64_t number,uint8_t flags) {
87 	char numbuf[6];	// [ "xxx" , "xx" , "x" , "x.x" ] + ["" , "X" , "Xi"]
88 	uint64_t divisor;
89 	uint16_t b;
90 	uint8_t i;
91 	uint8_t scale;
92 
93 	if (flags & PHN_USESI) {
94 		divisor = 1000;
95 	} else {
96 		divisor = 1024;
97 	}
98 	if (number>(UINT64_MAX/100)) {
99 		number /= divisor;
100 		number *= 100;
101 		scale = 1;
102 	} else {
103 		number *= 100;
104 		scale = 0;
105 	}
106 	while (number>=99950) {
107 		number /= divisor;
108 		scale+=1;
109 	}
110 	i=0;
111 	if (number<995 && scale>0) {
112 		b = ((uint32_t)number + 5) / 10;
113 		numbuf[i++]=(b/10)+'0';
114 		numbuf[i++]='.';
115 		numbuf[i++]=(b%10)+'0';
116 	} else {
117 		b = ((uint32_t)number + 50) / 100;
118 		if (b>=100) {
119 			numbuf[i++]=(b/100)+'0';
120 			b%=100;
121 		}
122 		if (b>=10 || i>0) {
123 			numbuf[i++]=(b/10)+'0';
124 			b%=10;
125 		}
126 		numbuf[i++]=b+'0';
127 	}
128 	if (scale>0) {
129 		if (flags&PHN_USESI) {
130 			numbuf[i++]="-kMGTPE"[scale];
131 		} else {
132 			numbuf[i++]="-KMGTPE"[scale];
133 			numbuf[i++]='i';
134 		}
135 	}
136 	numbuf[i++]='\0';
137 	printf(format,numbuf);
138 }
139 
print_number_only(uint64_t number,uint8_t bytesflag)140 void print_number_only(uint64_t number,uint8_t bytesflag) {
141 	if (humode>0) {
142 		if (bytesflag) {
143 			if (humode==1 || humode==3) {
144 				print_humanized_number("%5sB",number,PHN_USEIEC);
145 			} else {
146 				print_humanized_number("%4sB",number,PHN_USESI);
147 			}
148 		} else {
149 			if (humode==1 || humode==3) {
150 				print_humanized_number("%5s",number,PHN_USEIEC);
151 			} else {
152 				print_humanized_number("%4s",number,PHN_USESI);
153 			}
154 		}
155 		if (humode>2) {
156 			printf(" (%"PRIu64")",number);
157 		}
158 	} else {
159 		if (numbermode==0) {
160 			printf("%"PRIu64,number);
161 		} else if (numbermode==1) {
162 			printf("%"PRIu64,number/1024);
163 		} else if (numbermode==2) {
164 			printf("%"PRIu64,number/(1024*1024));
165 		} else if (numbermode==3) {
166 			printf("%"PRIu64,number/(1024*1024*1024));
167 		}
168 	}
169 }
170 
print_number(const char * prefix,const char * suffix,uint64_t number,uint8_t mode32,uint8_t bytesflag,uint8_t dflag)171 void print_number(const char *prefix,const char *suffix,uint64_t number,uint8_t mode32,uint8_t bytesflag,uint8_t dflag) {
172 	if (prefix) {
173 		printf("%s",prefix);
174 	}
175 	if (dflag) {
176 		if (humode>0) {
177 			if (bytesflag) {
178 				if (humode==1 || humode==3) {
179 					print_humanized_number("%5sB",number,PHN_USEIEC);
180 				} else {
181 					print_humanized_number("%4sB",number,PHN_USESI);
182 				}
183 			} else {
184 				if (humode==1 || humode==3) {
185 					print_humanized_number(" %5s",number,PHN_USEIEC);
186 				} else {
187 					print_humanized_number(" %4s",number,PHN_USESI);
188 				}
189 			}
190 			if (humode>2) {
191 				if (mode32) {
192 					printf(" (%10"PRIu32")",(uint32_t)number);
193 				} else {
194 					printf(" (%20"PRIu64")",number);
195 				}
196 			}
197 		} else {
198 			if (numbermode==0) {
199 				if (mode32) {
200 					printf("%10"PRIu32,(uint32_t)number);
201 				} else {
202 					printf("%20"PRIu64,number);
203 				}
204 			} else if (numbermode==1) {
205 				if (mode32) {
206 					printf("%7"PRIu32,((uint32_t)number)/1024);
207 				} else {
208 					printf("%17"PRIu64,number/1024);
209 				}
210 			} else if (numbermode==2) {
211 				if (mode32) {
212 					printf("%4"PRIu32,((uint32_t)number)/(1024*1024));
213 				} else {
214 					printf("%14"PRIu64,number/(1024*1024));
215 				}
216 			} else if (numbermode==3) {
217 				if (mode32) {
218 					printf("%1"PRIu32,((uint32_t)number)/(1024*1024*1024));
219 				} else {
220 					printf("%11"PRIu64,number/(1024*1024*1024));
221 				}
222 			}
223 		}
224 	} else {
225 		switch(humode) {
226 		case 0:
227 			if (numbermode==0) {
228 				if (mode32) {
229 					printf("         -");
230 				} else {
231 					printf("                   -");
232 				}
233 			} else if (numbermode==1) {
234 				if (mode32) {
235 					printf("      -");
236 				} else {
237 					printf("                -");
238 				}
239 			} else if (numbermode==2) {
240 				if (mode32) {
241 					printf("   -");
242 				} else {
243 					printf("             -");
244 				}
245 			} else if (numbermode==3) {
246 				if (mode32) {
247 					printf("-");
248 				} else {
249 					printf("          -");
250 				}
251 			}
252 			break;
253 		case 1:
254 			printf("     -");
255 			break;
256 		case 2:
257 			printf("    -");
258 			break;
259 		case 3:
260 			if (mode32) {
261 				printf("                  -");
262 			} else {
263 				printf("                            -");
264 			}
265 			break;
266 		case 4:
267 			if (mode32) {
268 				printf("                 -");
269 			} else {
270 				printf("                           -");
271 			}
272 			break;
273 		}
274 	}
275 	if (suffix) {
276 		printf("%s",suffix);
277 	}
278 }
279 
my_get_number(const char * str,uint64_t * ret,uint64_t max,uint8_t bytesflag)280 int my_get_number(const char *str,uint64_t *ret,uint64_t max,uint8_t bytesflag) {
281 	uint64_t val,frac,fracdiv;
282 	double drval,mult;
283 	int f;
284 	val=0;
285 	frac=0;
286 	fracdiv=1;
287 	f=0;
288 	while (*str>='0' && *str<='9') {
289 		f=1;
290 		val*=10;
291 		val+=(*str-'0');
292 		str++;
293 	}
294 	if (*str=='.') {	// accept ".5" (without 0)
295 		str++;
296 		while (*str>='0' && *str<='9') {
297 			fracdiv*=10;
298 			frac*=10;
299 			frac+=(*str-'0');
300 			str++;
301 		}
302 		if (fracdiv==1) {	// if there was '.' expect number afterwards
303 			return -1;
304 		}
305 	} else if (f==0) {	// but not empty string
306 		return -1;
307 	}
308 	if (str[0]=='\0' || (bytesflag && str[0]=='B' && str[1]=='\0')) {
309 		mult=1.0;
310 	} else if (str[0]!='\0' && (str[1]=='\0' || (bytesflag && str[1]=='B' && str[2]=='\0'))) {
311 		switch(str[0]) {
312 		case 'k':
313 			mult=1e3;
314 			break;
315 		case 'M':
316 			mult=1e6;
317 			break;
318 		case 'G':
319 			mult=1e9;
320 			break;
321 		case 'T':
322 			mult=1e12;
323 			break;
324 		case 'P':
325 			mult=1e15;
326 			break;
327 		case 'E':
328 			mult=1e18;
329 			break;
330 		default:
331 			return -1;
332 		}
333 	} else if (str[0]!='\0' && str[1]=='i' && (str[2]=='\0' || (bytesflag && str[2]=='B' && str[3]=='\0'))) {
334 		switch(str[0]) {
335 		case 'K':
336 			mult=1024.0;
337 			break;
338 		case 'M':
339 			mult=1048576.0;
340 			break;
341 		case 'G':
342 			mult=1073741824.0;
343 			break;
344 		case 'T':
345 			mult=1099511627776.0;
346 			break;
347 		case 'P':
348 			mult=1125899906842624.0;
349 			break;
350 		case 'E':
351 			mult=1152921504606846976.0;
352 			break;
353 		default:
354 			return -1;
355 		}
356 	} else {
357 		return -1;
358 	}
359 	drval = round(((double)frac/(double)fracdiv+(double)val)*mult);
360 	*ret = drval;
361 	if (drval>max || ((*ret)==0 && drval>1.0)) { // when max==UINT64_MAX and drval==2^64 then drval>max is false because common type for uint64_t and double is double and we lost precision here - therefore the second condition
362 		return -2;
363 	}
364 	return 1;
365 }
366 
bsd_basename(const char * path,char * bname)367 int bsd_basename(const char *path,char *bname) {
368 	const char *endp, *startp;
369 
370 	/* Empty or NULL string gets treated as "." */
371 	if (path == NULL || *path == '\0') {
372 		(void)strcpy(bname, ".");
373 		return 0;
374 	}
375 
376 	/* Strip trailing slashes */
377 	endp = path + strlen(path) - 1;
378 	while (endp > path && *endp == '/') {
379 		endp--;
380 	}
381 
382 	/* All slashes becomes "/" */
383 	if (endp == path && *endp == '/') {
384 		(void)strcpy(bname, "/");
385 		return 0;
386 	}
387 
388 	/* Find the start of the base */
389 	startp = endp;
390 	while (startp > path && *(startp - 1) != '/') {
391 		startp--;
392 	}
393 	if (endp - startp + 2 > PATH_MAX) {
394 		return -1;
395 	}
396 	(void)strncpy(bname, startp, endp - startp + 1);
397 	bname[endp - startp + 1] = '\0';
398 	return 0;
399 }
400 
bsd_dirname(const char * path,char * bname)401 int bsd_dirname(const char *path,char *bname) {
402 	const char *endp;
403 
404 	/* Empty or NULL string gets treated as "." */
405 	if (path == NULL || *path == '\0') {
406 		(void)strcpy(bname, ".");
407 		return 0;
408 	}
409 
410 	/* Strip trailing slashes */
411 	endp = path + strlen(path) - 1;
412 	while (endp > path && *endp == '/') {
413 		endp--;
414 	}
415 
416 	/* Find the start of the dir */
417 	while (endp > path && *endp != '/') {
418 		endp--;
419 	}
420 
421 	/* Either the dir is "/" or there are no slashes */
422 	if (endp == path) {
423 		(void)strcpy(bname, *endp == '/' ? "/" : ".");
424 		return 0;
425 	} else {
426 		do {
427 			endp--;
428 		} while (endp > path && *endp == '/');
429 	}
430 
431 	if (endp - path + 2 > PATH_MAX) {
432 		return -1;
433 	}
434 	(void)strncpy(bname, path, endp - path + 1);
435 	bname[endp - path + 1] = '\0';
436 	return 0;
437 }
438 
dirname_inplace(char * path)439 void dirname_inplace(char *path) {
440 	char *endp;
441 
442 	if (path==NULL) {
443 		return;
444 	}
445 	if (path[0]=='\0') {
446 		path[0]='.';
447 		path[1]='\0';
448 		return;
449 	}
450 
451 	/* Strip trailing slashes */
452 	endp = path + strlen(path) - 1;
453 	while (endp > path && *endp == '/') {
454 		endp--;
455 	}
456 
457 	/* Find the start of the dir */
458 	while (endp > path && *endp != '/') {
459 		endp--;
460 	}
461 
462 	if (endp == path) {
463 		if (path[0]=='/') {
464 			path[1]='\0';
465 		} else {
466 			path[0]='.';
467 			path[1]='\0';
468 		}
469 		return;
470 	} else {
471 		*endp = '\0';
472 	}
473 }
474 
475 int inode_liset;
476 int chunk_liset;
477 
478 /* ---- INODE QUEUE ---- */
479 
480 typedef struct _inoqueue {
481 	uint32_t inode;
482 	struct _inoqueue *next;
483 } inoqueue;
484 
485 static inoqueue *qhead,**qtail;
486 
sc_dequeue(uint32_t * inode)487 uint8_t sc_dequeue(uint32_t *inode) {
488 	inoqueue *iq;
489 	if (qhead==NULL) {
490 		return 0;
491 	} else {
492 		iq = qhead;
493 		qhead = iq->next;
494 		if (qhead==NULL) {
495 			qtail = &qhead;
496 		}
497 		*inode = iq->inode;
498 		free(iq);
499 		return 1;
500 	}
501 }
502 
sc_enqueue(uint32_t inode)503 uint8_t sc_enqueue(uint32_t inode) {
504 	inoqueue *iq;
505 	if (liset_addval(inode_liset,inode)==0) { // new element
506 		iq = malloc(sizeof(inoqueue));
507 		iq->inode = inode;
508 		iq->next = NULL;
509 		*qtail = iq;
510 		qtail = &(iq->next);
511 		return 1;
512 	} else {
513 		return 0;
514 	}
515 }
516 
parse_slice_expr(char * p,int64_t * slice_from,int64_t * slice_to)517 static inline int parse_slice_expr(char *p,int64_t *slice_from,int64_t *slice_to) {
518 	if (*p==':') {
519 		*slice_from = 0;
520 		p++;
521 	} else {
522 		*slice_from = strtoll(p,&p,10);
523 		if (*p!=':') {
524 			return -1;
525 		}
526 		p++;
527 	}
528 	if (*p=='\0') {
529 		*slice_to = 0x80000000;
530 	} else {
531 		*slice_to = strtoll(p,&p,10);
532 	}
533 	if (*p!='\0') {
534 		return -1;
535 	}
536 	return 0;
537 }
538 
539 // formats:
540 //  #     - number of seconds
541 //  #s    - number of seconds
542 //  #.#m  - number of minutes
543 //  #.#h  - number of hours
544 //  #.#d  - number of days
545 //  #.#w  - number of weeks
parse_period(char * str,char ** endpos)546 static inline uint32_t parse_period(char *str,char **endpos) {
547 	double base;
548 	double divisor;
549 	base = 0.0;
550 	while ((*str)>='0' && (*str)<='9') {
551 		base *= 10.0;
552 		base += (*str)-'0';
553 		str++;
554 	}
555 	if ((*str)=='.') {
556 		divisor = 0.1;
557 		str++;
558 		while ((*str)>='0' && (*str)<='9') {
559 			base += ((*str)-'0')*divisor;
560 			divisor /= 10.0;
561 			str++;
562 		}
563 	}
564 	while ((*str)==' ') {
565 		str++;
566 	}
567 	if ((*str)=='s') {
568 		str++;
569 	} else if ((*str)=='m') {
570 		str++;
571 		base *= 60.0;
572 	} else if ((*str)=='h') {
573 		str++;
574 		base *= 3600.0;
575 	} else if ((*str)=='d') {
576 		str++;
577 		base *= 86400.0;
578 	} else if ((*str)=='w') {
579 		str++;
580 		base *= 604800.0;
581 	}
582 	*endpos = str;
583 	if (base >= UINT32_MAX) {
584 		return UINT32_MAX;
585 	}
586 	if (base <= 0) {
587 		return 0;
588 	}
589 	return base;
590 }
591 
file_paths(const char * fname)592 int file_paths(const char* fname) {
593 	const char *p;
594 	struct stat st;
595 	char cwdbuff[MAXPATHLEN];
596 	uint32_t arginode;
597 	uint32_t inode;
598 	uint32_t leng,pleng;
599 
600 	p = fname;
601 	while (*p>='0' && *p<='9') {
602 		p++;
603 	}
604 
605 	if (*p=='\0' && stat(fname,&st)<0 && errno==ENOENT) {
606 		arginode = strtoul(fname,NULL,10);
607 		p = getcwd(cwdbuff,MAXPATHLEN);
608 		if (master_prepare_conn(p,&inode,NULL,NULL,0,0)<0) {
609 			return -1;
610 		}
611 		inode = arginode;
612 	} else {
613 		if (master_prepare_conn(fname,&inode,NULL,NULL,0,0)<0) {
614 			return -1;
615 		}
616 	}
617 	master_new_packet();
618 	master_put32bit(inode);
619 	if (master_send_and_receive(CLTOMA_FUSE_PATHS,MATOCL_FUSE_PATHS)<0) {
620 		return -1;
621 	}
622 	leng = master_get_leng();
623 	if (leng==1) {
624 		printf("%s: %s\n",fname,mfsstrerr(master_get8bit()));
625 		return -1;
626 	}
627 	printf("%s:\n",fname);
628 	while (leng>=4) {
629 		pleng = master_get32bit();
630 		leng-=4;
631 		if (leng>=pleng) {
632 			while (pleng) {
633 				putchar(master_get8bit());
634 				pleng--;
635 				leng--;
636 			}
637 			putchar('\n');
638 		} else {
639 			leng=0;
640 		}
641 	}
642 	if (master_end_packet()==0) {
643 		printf("%s: master query: packet size error\n",fname);
644 		return -1;
645 	}
646 	return 0;
647 }
648 
649 typedef struct _storage_class {
650 	uint8_t admin_only;
651 	uint8_t mode;
652 	uint16_t arch_delay;
653 	uint8_t create_labelscnt,keep_labelscnt,arch_labelscnt;
654 	uint32_t create_labelmasks[9][MASKORGROUP];
655 	uint32_t keep_labelmasks[9][MASKORGROUP];
656 	uint32_t arch_labelmasks[9][MASKORGROUP];
657 } storage_class;
658 
deserialize_sc(storage_class * sc)659 static inline int deserialize_sc(storage_class *sc) {
660 	uint8_t i,og;
661 	sc->admin_only = master_get8bit();
662 	sc->mode = master_get8bit();
663 	sc->arch_delay = master_get16bit();
664 	sc->create_labelscnt = master_get8bit();
665 	sc->keep_labelscnt = master_get8bit();
666 	sc->arch_labelscnt = master_get8bit();
667 	if (sc->create_labelscnt>9 || sc->create_labelscnt<1 || sc->keep_labelscnt>9 || sc->keep_labelscnt<1 || sc->arch_labelscnt>9 || sc->arch_labelscnt<1) {
668 		return -1;
669 	}
670 	for (i=0 ; i<sc->create_labelscnt ; i++) {
671 		for (og=0 ; og<MASKORGROUP ; og++) {
672 			sc->create_labelmasks[i][og] = master_get32bit();
673 		}
674 	}
675 	for (i=0 ; i<sc->keep_labelscnt ; i++) {
676 		for (og=0 ; og<MASKORGROUP ; og++) {
677 			sc->keep_labelmasks[i][og] = master_get32bit();
678 		}
679 	}
680 	for (i=0 ; i<sc->arch_labelscnt ; i++) {
681 		for (og=0 ; og<MASKORGROUP ; og++) {
682 			sc->arch_labelmasks[i][og] = master_get32bit();
683 		}
684 	}
685 	return 0;
686 }
687 
serialize_sc(const storage_class * sc)688 static inline void serialize_sc(const storage_class *sc) {
689 	uint8_t i,og;
690 	master_put8bit(sc->admin_only);
691 	master_put8bit(sc->mode);
692 	master_put16bit(sc->arch_delay);
693 	master_put8bit(sc->create_labelscnt);
694 	master_put8bit(sc->keep_labelscnt);
695 	master_put8bit(sc->arch_labelscnt);
696 	for (i=0 ; i<sc->create_labelscnt ; i++) {
697 		for (og=0 ; og<MASKORGROUP ; og++) {
698 			master_put32bit(sc->create_labelmasks[i][og]);
699 		}
700 	}
701 	for (i=0 ; i<sc->keep_labelscnt ; i++) {
702 		for (og=0 ; og<MASKORGROUP ; og++) {
703 			master_put32bit(sc->keep_labelmasks[i][og]);
704 		}
705 	}
706 	for (i=0 ; i<sc->arch_labelscnt ; i++) {
707 		for (og=0 ; og<MASKORGROUP ; og++) {
708 			master_put32bit(sc->arch_labelmasks[i][og]);
709 		}
710 	}
711 }
712 
printf_sc(const storage_class * sc,char * endstr)713 static inline void printf_sc(const storage_class *sc,char *endstr) {
714 	char labelsbuff[LABELS_BUFF_SIZE];
715 	if (sc->arch_delay==0) {
716 		if (sc->create_labelscnt==sc->keep_labelscnt) {
717 			printf("%"PRIu8,sc->create_labelscnt);
718 		} else {
719 			printf("%"PRIu8"->%"PRIu8,sc->create_labelscnt,sc->keep_labelscnt);
720 		}
721 		printf(" ; admin_only: %s",(sc->admin_only)?"YES":"NO");
722 		printf(" ; mode: %s",(sc->mode==SCLASS_MODE_LOOSE)?"LOOSE":(sc->mode==SCLASS_MODE_STRICT)?"STRICT":"STD");
723 		printf(" ; create_labels: %s",make_label_expr(labelsbuff,sc->create_labelscnt,(uint32_t (*)[MASKORGROUP])sc->create_labelmasks));
724 		printf(" ; keep_labels: %s",make_label_expr(labelsbuff,sc->keep_labelscnt,(uint32_t (*)[MASKORGROUP])sc->keep_labelmasks));
725 	} else {
726 		if (sc->create_labelscnt==sc->keep_labelscnt && sc->keep_labelscnt==sc->arch_labelscnt) {
727 			printf("%"PRIu8,sc->create_labelscnt);
728 		} else {
729 			printf("%"PRIu8"->%"PRIu8"->%"PRIu8,sc->create_labelscnt,sc->keep_labelscnt,sc->arch_labelscnt);
730 		}
731 		printf(" ; admin_only: %s",(sc->admin_only)?"YES":"NO");
732 		printf(" ; mode: %s",(sc->mode==SCLASS_MODE_LOOSE)?"LOOSE":(sc->mode==SCLASS_MODE_STRICT)?"STRICT":"STD");
733 		printf(" ; create_labels: %s",make_label_expr(labelsbuff,sc->create_labelscnt,(uint32_t (*)[MASKORGROUP])sc->create_labelmasks));
734 		printf(" ; keep_labels: %s",make_label_expr(labelsbuff,sc->keep_labelscnt,(uint32_t (*)[MASKORGROUP])sc->keep_labelmasks));
735 		printf(" ; arch_labels: %s",make_label_expr(labelsbuff,sc->arch_labelscnt,(uint32_t (*)[MASKORGROUP])sc->arch_labelmasks));
736 		printf(" ; arch_delay: %"PRIu16"d",sc->arch_delay);
737 	}
738 	printf("%s",endstr);
739 }
740 
get_sclass(const char * fname,uint8_t * goal,char storage_class_name[256],uint8_t mode)741 int get_sclass(const char *fname,uint8_t *goal,char storage_class_name[256],uint8_t mode) {
742 	uint32_t inode;
743 	uint8_t fn,dn,i;
744 	uint32_t cnt;
745 
746 	if (master_prepare_conn(fname,&inode,NULL,NULL,0,0)<0) {
747 		return -1;
748 	}
749 	master_new_packet();
750 	master_put32bit(inode);
751 	master_put8bit(mode);
752 	if (master_send_and_receive(CLTOMA_FUSE_GETSCLASS,MATOCL_FUSE_GETSCLASS)<0) {
753 		return -1;
754 	}
755 	if (master_get_leng()==1) {
756 		printf("%s: %s\n",fname,mfsstrerr(master_get8bit()));
757 		return -1;
758 	} else if (master_get_leng()<2) {
759 		printf("%s: master query: wrong answer (leng)\n",fname);
760 		master_error();
761 		return -1;
762 	}
763 	if (mode==GMODE_NORMAL) {
764 		fn = master_get8bit();
765 		dn = master_get8bit();
766 		if ((fn!=0 || dn!=1) && (fn!=1 || dn!=0)) {
767 			printf("%s: master query: wrong answer (fn,dn)\n",fname);
768 			master_error();
769 			return -1;
770 		}
771 		*goal = master_get8bit();
772 		if (*goal==0) {
773 			printf("%s: unsupported data format (upgrade master)\n",fname);
774 			return -1;
775 		} else if (*goal==0xFF) {
776 			master_getname(storage_class_name);
777 		}
778 		cnt = master_get32bit();
779 		if (cnt!=1) {
780 			printf("%s: master query: wrong answer (cnt)\n",fname);
781 			master_error();
782 			return -1;
783 		}
784 		if (*goal==0xFF) {
785 			printf("%s: '%s'\n",fname,storage_class_name);
786 		} else {
787 			printf("%s: %"PRIu8"\n",fname,*goal);
788 		}
789 	} else {
790 		fn = master_get8bit();
791 		dn = master_get8bit();
792 		printf("%s:\n",fname);
793 		for (i=0 ; i<fn ; i++) {
794 			*goal = master_get8bit();
795 			if (*goal==0) {
796 				printf("%s: unsupported data format (upgrade master)\n",fname);
797 				return -1;
798 			} else if (*goal==0xFF) {
799 				master_getname(storage_class_name);
800 			}
801 			cnt = master_get32bit();
802 			if (*goal==0xFF) {
803 				printf(" files with storage class       '%s' :",storage_class_name);
804 			} else {
805 				printf(" files with goal                %"PRIu8" :",*goal);
806 			}
807 			print_number(" ","\n",cnt,1,0,1);
808 		}
809 		for (i=0 ; i<dn ; i++) {
810 			*goal = master_get8bit();
811 			if (*goal==0) {
812 				printf("%s: unsupported data format (upgrade master)\n",fname);
813 				return -1;
814 			} else if (*goal==0xFF) {
815 				master_getname(storage_class_name);
816 			}
817 			cnt = master_get32bit();
818 			if (*goal==0xFF) {
819 				printf(" directories with storage class '%s' :",storage_class_name);
820 			} else {
821 				printf(" directories with goal          %"PRIu8" :",*goal);
822 			}
823 			print_number(" ","\n",cnt,1,0,1);
824 		}
825 	}
826 	if (master_end_packet()==0) {
827 		printf("%s: master query: packet size error\n",fname);
828 		return -1;
829 	}
830 	return 0;
831 }
832 
get_trashtime(const char * fname,uint32_t * trashtime,uint8_t mode)833 int get_trashtime(const char *fname,uint32_t *trashtime,uint8_t mode) {
834 	uint32_t inode;
835 	uint32_t fn,dn,i;
836 //	uint32_t trashtime;
837 	uint32_t cnt;
838 
839 	if (master_prepare_conn(fname,&inode,NULL,NULL,0,0)<0) {
840 		return -1;
841 	}
842 	master_new_packet();
843 	master_put32bit(inode);
844 	master_put8bit(mode);
845 	if (master_send_and_receive(CLTOMA_FUSE_GETTRASHTIME,MATOCL_FUSE_GETTRASHTIME)<0) {
846 		return -1;
847 	}
848 	if (master_get_leng()==1) {
849 		printf("%s: %s\n",fname,mfsstrerr(master_get8bit()));
850 		return -1;
851 	} else if (master_get_leng()<8 || master_get_leng()%8!=0) {
852 		printf("%s: master query: wrong answer (leng)\n",fname);
853 		master_error();
854 		return -1;
855 	} else if (mode==GMODE_NORMAL && master_get_leng()!=16) {
856 		printf("%s: master query: wrong answer (leng)\n",fname);
857 		master_error();
858 		return -1;
859 	}
860 	if (mode==GMODE_NORMAL) {
861 		fn = master_get32bit();
862 		dn = master_get32bit();
863 		*trashtime = master_get32bit();
864 		cnt = master_get32bit();
865 		if ((fn!=0 || dn!=1) && (fn!=1 || dn!=0)) {
866 			printf("%s: master query: wrong answer (fn,dn)\n",fname);
867 			master_error();
868 			return -1;
869 		}
870 		if (cnt!=1) {
871 			printf("%s: master query: wrong answer (cnt)\n",fname);
872 			master_error();
873 			return -1;
874 		}
875 		printf("%s: %"PRIu32"\n",fname,*trashtime);
876 	} else {
877 		fn = master_get32bit();
878 		dn = master_get32bit();
879 		printf("%s:\n",fname);
880 		for (i=0 ; i<fn ; i++) {
881 			*trashtime = master_get32bit();
882 			cnt = master_get32bit();
883 			printf(" files with trashtime        %10"PRIu32" :",*trashtime);
884 			print_number(" ","\n",cnt,1,0,1);
885 		}
886 		for (i=0 ; i<dn ; i++) {
887 			*trashtime = master_get32bit();
888 			cnt = master_get32bit();
889 			printf(" directories with trashtime  %10"PRIu32" :",*trashtime);
890 			print_number(" ","\n",cnt,1,0,1);
891 		}
892 	}
893 	if (master_end_packet()==0) {
894 		printf("%s: master query: packet size error\n",fname);
895 		return -1;
896 	}
897 	return 0;
898 }
899 
get_eattr(const char * fname,uint8_t * eattr,uint8_t mode)900 int get_eattr(const char *fname,uint8_t *eattr,uint8_t mode) {
901 	uint32_t inode;
902 	uint8_t fn,dn,i,j;
903 	uint32_t fcnt[EATTR_BITS];
904 	uint32_t dcnt[EATTR_BITS];
905 //	uint8_t eattr;
906 	uint32_t cnt;
907 
908 	if (master_prepare_conn(fname,&inode,NULL,NULL,0,0)<0) {
909 		return -1;
910 	}
911 	master_new_packet();
912 	master_put32bit(inode);
913 	master_put8bit(mode);
914 	if (master_send_and_receive(CLTOMA_FUSE_GETEATTR,MATOCL_FUSE_GETEATTR)<0) {
915 		return -1;
916 	}
917 	if (master_get_leng()==1) {
918 		printf("%s: %s\n",fname,mfsstrerr(master_get8bit()));
919 		return -1;
920 	} else if (master_get_leng()%5!=2) {
921 		printf("%s: master query: wrong answer (leng)\n",fname);
922 		master_error();
923 		return -1;
924 	} else if (mode==GMODE_NORMAL && master_get_leng()!=7) {
925 		printf("%s: master query: wrong answer (leng)\n",fname);
926 		master_error();
927 		return -1;
928 	}
929 	if (mode==GMODE_NORMAL) {
930 		fn = master_get8bit();
931 		dn = master_get8bit();
932 		*eattr = master_get8bit();
933 		cnt = master_get32bit();
934 		if ((fn!=0 || dn!=1) && (fn!=1 || dn!=0)) {
935 			printf("%s: master query: wrong answer (fn,dn)\n",fname);
936 			master_error();
937 			return -1;
938 		}
939 		if (cnt!=1) {
940 			printf("%s: master query: wrong answer (cnt)\n",fname);
941 			master_error();
942 			return -1;
943 		}
944 		printf("%s: ",fname);
945 		if (*eattr>0) {
946 			cnt=0;
947 			for (j=0 ; j<EATTR_BITS ; j++) {
948 				if ((*eattr) & (1<<j)) {
949 					printf("%s%s",(cnt)?",":"",eattrtab[j]);
950 					cnt=1;
951 				}
952 			}
953 			printf("\n");
954 		} else {
955 			printf("-\n");
956 		}
957 	} else {
958 		for (j=0 ; j<EATTR_BITS ; j++) {
959 			fcnt[j]=0;
960 			dcnt[j]=0;
961 		}
962 		fn = master_get8bit();
963 		dn = master_get8bit();
964 		for (i=0 ; i<fn ; i++) {
965 			*eattr = master_get8bit();
966 			cnt = master_get32bit();
967 			for (j=0 ; j<EATTR_BITS ; j++) {
968 				if ((*eattr) & (1<<j)) {
969 					fcnt[j]+=cnt;
970 				}
971 			}
972 		}
973 		for (i=0 ; i<dn ; i++) {
974 			*eattr = master_get8bit();
975 			cnt = master_get32bit();
976 			for (j=0 ; j<EATTR_BITS ; j++) {
977 				if ((*eattr) & (1<<j)) {
978 					dcnt[j]+=cnt;
979 				}
980 			}
981 		}
982 		printf("%s:\n",fname);
983 		for (j=0 ; j<EATTR_BITS ; j++) {
984 			if (eattrtab[j][0]) {
985 				printf(" not directory nodes with attribute %16s :",eattrtab[j]);
986 				print_number(" ","\n",fcnt[j],1,0,1);
987 				printf(" directories with attribute         %16s :",eattrtab[j]);
988 				print_number(" ","\n",dcnt[j],1,0,1);
989 			} else {
990 				if (fcnt[j]>0) {
991 					printf(" not directory nodes with attribute      'unknown-%u' :",j);
992 					print_number(" ","\n",fcnt[j],1,0,1);
993 				}
994 				if (dcnt[j]>0) {
995 					printf(" directories with attribute              'unknown-%u' :",j);
996 					print_number(" ","\n",dcnt[j],1,0,1);
997 				}
998 			}
999 		}
1000 	}
1001 	if (master_end_packet()==0) {
1002 		printf("%s: master query: packet size error\n",fname);
1003 		return -1;
1004 	}
1005 	return 0;
1006 }
1007 
set_sclass(const char * fname,uint8_t goal,const char src_storage_class_name[256],const char storage_class_name[256],uint8_t mode)1008 int set_sclass(const char *fname,uint8_t goal,const char src_storage_class_name[256],const char storage_class_name[256],uint8_t mode) {
1009 	uint8_t nleng,snleng;
1010 	uint32_t inode,uid;
1011 	uint32_t changed,notchanged,notpermitted,quotaexceeded;
1012 
1013 	nleng = strlen(storage_class_name);
1014 	if ((mode&SMODE_TMASK)==SMODE_EXCHANGE) {
1015 		snleng = strlen(src_storage_class_name);
1016 	} else {
1017 		snleng = 0;
1018 	}
1019 	if (master_prepare_conn(fname,&inode,NULL,NULL,0,1)<0) {
1020 		return -1;
1021 	}
1022 	if (goal==0xFF && master_get_version()<VERSION2INT(3,0,75)) {
1023 		printf("%s: storage classes not supported (master too old)\n",fname);
1024 		return -1;
1025 	}
1026 	if (goal==0 || (goal>9 && goal!=0xFF)) {
1027 		printf("%s: set storage class unsupported mode (internal error)\n",fname);
1028 		return -1;
1029 	}
1030 	uid = getuid();
1031 	master_new_packet();
1032 	master_put32bit(inode);
1033 	master_put32bit(uid);
1034 	master_put8bit(goal);
1035 	master_put8bit(mode);
1036 	if (goal==0xFF) {
1037 		if ((mode&SMODE_TMASK)==SMODE_EXCHANGE) {
1038 			master_putname(snleng,src_storage_class_name);
1039 		}
1040 		master_putname(nleng,storage_class_name);
1041 	}
1042 	if (master_send_and_receive(CLTOMA_FUSE_SETSCLASS,MATOCL_FUSE_SETSCLASS)<0) {
1043 		return -1;
1044 	}
1045 	if (master_get_leng()==1) {
1046 		printf("%s: %s\n",fname,mfsstrerr(master_get8bit()));
1047 		return -1;
1048 	} else if (master_get_leng()!=12 && master_get_leng()!=16) {
1049 		printf("%s: master query: wrong answer (leng)\n",fname);
1050 		master_error();
1051 		return -1;
1052 	}
1053 	changed = master_get32bit();
1054 	notchanged = master_get32bit();
1055 	notpermitted = master_get32bit();
1056 	if (master_get_leng()==16) {
1057 		quotaexceeded = master_get32bit();
1058 	} else {
1059 		quotaexceeded = 0;
1060 	}
1061 	if ((mode&SMODE_RMASK)==0) {
1062 		if (changed || mode==SMODE_SET) {
1063 			if (goal==0xFF) {
1064 				printf("%s: storage class: '%s'\n",fname,storage_class_name);
1065 			} else {
1066 				printf("%s: goal: %"PRIu8"\n",fname,goal);
1067 			}
1068 		} else {
1069 			if (goal==0xFF) {
1070 				printf("%s: storage class not changed\n",fname);
1071 			} else {
1072 				printf("%s: goal not changed\n",fname);
1073 			}
1074 		}
1075 	} else {
1076 		printf("%s:\n",fname);
1077 		if (goal==0xFF) {
1078 			print_number(" inodes with storage class changed:     ","\n",changed,1,0,1);
1079 			print_number(" inodes with storage class not changed: ","\n",notchanged,1,0,1);
1080 		} else {
1081 			print_number(" inodes with goal changed:              ","\n",changed,1,0,1);
1082 			print_number(" inodes with goal not changed:          ","\n",notchanged,1,0,1);
1083 		}
1084 		print_number(" inodes with permission denied:         ","\n",notpermitted,1,0,1);
1085 		if (master_get_leng()==16) {
1086 			print_number(" inodes with quota exceeded:            ","\n",quotaexceeded,1,0,1);
1087 		}
1088 	}
1089 	if (master_end_packet()==0) {
1090 		printf("%s: master query: packet size error\n",fname);
1091 		return -1;
1092 	}
1093 	return 0;
1094 }
1095 
set_trashtime(const char * fname,uint32_t trashtime,uint8_t mode)1096 int set_trashtime(const char *fname,uint32_t trashtime,uint8_t mode) {
1097 	uint32_t inode,uid;
1098 	uint32_t changed,notchanged,notpermitted;
1099 
1100 	if (master_prepare_conn(fname,&inode,NULL,NULL,0,1)<0) {
1101 		return -1;
1102 	}
1103 	uid = getuid();
1104 	master_new_packet();
1105 	master_put32bit(inode);
1106 	master_put32bit(uid);
1107 	master_put32bit(trashtime);
1108 	master_put8bit(mode);
1109 	if (master_send_and_receive(CLTOMA_FUSE_SETTRASHTIME,MATOCL_FUSE_SETTRASHTIME)<0) {
1110 		return -1;
1111 	}
1112 	if (master_get_leng()==1) {
1113 		printf("%s: %s\n",fname,mfsstrerr(master_get8bit()));
1114 		return -1;
1115 	} else if (master_get_leng()!=12) {
1116 		printf("%s: master query: wrong answer (leng)\n",fname);
1117 		master_error();
1118 		return -1;
1119 	}
1120 	changed = master_get32bit();
1121 	notchanged = master_get32bit();
1122 	notpermitted = master_get32bit();
1123 	if ((mode&SMODE_RMASK)==0) {
1124 		if (changed || mode==SMODE_SET) {
1125 			printf("%s: %"PRIu32"\n",fname,trashtime);
1126 		} else {
1127 			printf("%s: trashtime not changed\n",fname);
1128 		}
1129 	} else {
1130 		printf("%s:\n",fname);
1131 		print_number(" inodes with trashtime changed:     ","\n",changed,1,0,1);
1132 		print_number(" inodes with trashtime not changed: ","\n",notchanged,1,0,1);
1133 		print_number(" inodes with permission denied:     ","\n",notpermitted,1,0,1);
1134 	}
1135 	if (master_end_packet()==0) {
1136 		printf("%s: master query: packet size error\n",fname);
1137 		return -1;
1138 	}
1139 	return 0;
1140 }
1141 
set_eattr(const char * fname,uint8_t eattr,uint8_t mode)1142 int set_eattr(const char *fname,uint8_t eattr,uint8_t mode) {
1143 	uint32_t inode,uid;
1144 	uint32_t changed,notchanged,notpermitted;
1145 
1146 	if (master_prepare_conn(fname,&inode,NULL,NULL,0,1)<0) {
1147 		return -1;
1148 	}
1149 	uid = getuid();
1150 	master_new_packet();
1151 	master_put32bit(inode);
1152 	master_put32bit(uid);
1153 	master_put8bit(eattr);
1154 	master_put8bit(mode);
1155 	if (master_send_and_receive(CLTOMA_FUSE_SETEATTR,MATOCL_FUSE_SETEATTR)<0) {
1156 		return -1;
1157 	}
1158 	if (master_get_leng()==1) {
1159 		printf("%s: %s\n",fname,mfsstrerr(master_get8bit()));
1160 		return -1;
1161 	} else if (master_get_leng()!=12) {
1162 		printf("%s: master query: wrong answer (leng)\n",fname);
1163 		master_error();
1164 		return -1;
1165 	}
1166 	changed = master_get32bit();
1167 	notchanged = master_get32bit();
1168 	notpermitted = master_get32bit();
1169 	if ((mode&SMODE_RMASK)==0) {
1170 		if (changed) {
1171 			printf("%s: attribute(s) changed\n",fname);
1172 		} else {
1173 			printf("%s: attribute(s) not changed\n",fname);
1174 		}
1175 	} else {
1176 		printf("%s:\n",fname);
1177 		print_number(" inodes with attributes changed:     ","\n",changed,1,0,1);
1178 		print_number(" inodes with attributes not changed: ","\n",notchanged,1,0,1);
1179 		print_number(" inodes with permission denied:      ","\n",notpermitted,1,0,1);
1180 	}
1181 	if (master_end_packet()==0) {
1182 		printf("%s: master query: packet size error\n",fname);
1183 		return -1;
1184 	}
1185 	return 0;
1186 }
1187 
archive_control(const char * fname,uint8_t archcmd)1188 int archive_control(const char *fname,uint8_t archcmd) {
1189 	uint32_t inode,uid;
1190 
1191 	if (master_prepare_conn(fname,&inode,NULL,NULL,0,1)<0) {
1192 		return -1;
1193 	}
1194 	uid = getuid();
1195 	master_new_packet();
1196 	master_put32bit(inode);
1197 	master_put8bit(archcmd);
1198 	if (archcmd!=ARCHCTL_GET) {
1199 		master_put32bit(uid);
1200 	}
1201 	if (master_send_and_receive(CLTOMA_FUSE_ARCHCTL,MATOCL_FUSE_ARCHCTL)<0) {
1202 		return -1;
1203 	}
1204 	if (master_get_leng()==1) {
1205 		printf("%s: %s\n",fname,mfsstrerr(master_get8bit()));
1206 		return -1;
1207 	}
1208 	if (archcmd==ARCHCTL_GET) {
1209 		uint32_t archinodes,partinodes,notarchinodes;
1210 		uint64_t archchunks,notarchchunks;
1211 		if (master_get_leng()!=28) {
1212 			printf("%s: master query: wrong answer (leng)\n",fname);
1213 			master_error();
1214 			return -1;
1215 		}
1216 		archchunks = master_get64bit();
1217 		notarchchunks = master_get64bit();
1218 		archinodes = master_get32bit();
1219 		partinodes = master_get32bit();
1220 		notarchinodes = master_get32bit();
1221 		if (archinodes+partinodes+notarchinodes==1) {
1222 			if (archinodes==1) {
1223 				printf("%s: all chunks are archived\n",fname);
1224 			} else if (notarchinodes==1) {
1225 				printf("%s: all chunks are not archived\n",fname);
1226 			} else {
1227 				printf("%s: file is partially archived (archived chunks: %"PRIu64" ; not archived chunks: %"PRIu64")\n",fname,archchunks,notarchchunks);
1228 			}
1229 		} else {
1230 			printf("%s:\n",fname);
1231 			print_number(" files with all chunks archived:     ","\n",archinodes,1,0,1);
1232 			print_number(" files with all chunks not archived: ","\n",notarchinodes,1,0,1);
1233 			print_number(" files partially archived:           ","\n",partinodes,1,0,1);
1234 			print_number(" archived chunks:                    ","\n",archchunks,1,0,1);
1235 			print_number(" not archived chunks:                ","\n",notarchchunks,1,0,1);
1236 		}
1237 	} else {
1238 		uint64_t changed,notchanged;
1239 		uint32_t notpermitted;
1240 		if (master_get_leng()!=20) {
1241 			printf("%s: master query: wrong answer (leng)\n",fname);
1242 			master_error();
1243 			return -1;
1244 		}
1245 		changed = master_get64bit();
1246 		notchanged = master_get64bit();
1247 		notpermitted = master_get32bit();
1248 		printf("%s:\n",fname);
1249 		print_number(" chunks changed:               ","\n",changed,1,0,1);
1250 		print_number(" chunks not changed:           ","\n",notchanged,1,0,1);
1251 		print_number(" files with permission denied: ","\n",notpermitted,1,0,1);
1252 	}
1253 	if (master_end_packet()==0) {
1254 		printf("%s: master query: packet size error\n",fname);
1255 		return -1;
1256 	}
1257 	return 0;
1258 }
1259 
make_sc(const char * mfsmp,const char * scname,storage_class * sc)1260 int make_sc(const char *mfsmp,const char *scname,storage_class *sc) {
1261 	uint32_t nleng;
1262 	char cwdbuff[MAXPATHLEN];
1263 	uint8_t status;
1264 
1265 	nleng = strlen(scname);
1266 	if (nleng>=256) {
1267 		printf("%s: name too long\n",scname);
1268 		return -1;
1269 	}
1270 	if (mfsmp==NULL) {
1271 		mfsmp = getcwd(cwdbuff,MAXPATHLEN);
1272 	}
1273 	if (master_prepare_conn(mfsmp,NULL,NULL,NULL,0,0)<0) {
1274 		return -1;
1275 	}
1276 	master_new_packet();
1277 	master_putname(nleng,scname);
1278 	master_put8bit(0); // packet version
1279 	serialize_sc(sc);
1280 	if (master_send_and_receive(CLTOMA_SCLASS_CREATE,MATOCL_SCLASS_CREATE)<0) {
1281 		return -1;
1282 	}
1283 	if (master_get_leng()!=1) {
1284 		printf("master query: wrong answer (leng)\n");
1285 		master_error();
1286 		return -1;
1287 	}
1288 	status = master_get8bit();
1289 	if (status!=MFS_STATUS_OK) {
1290 		printf("storage class make %s: error: %s\n",scname,mfsstrerr(status));
1291 		return -1;
1292 	}
1293 	printf("storage class make %s: ok\n",scname);
1294 	if (master_end_packet()==0) { // pro forma
1295 		printf("master query: packet size error\n");
1296 		return -1;
1297 	}
1298 	return 0;
1299 }
1300 
change_sc(const char * mfsmp,const char * scname,uint16_t chgmask,storage_class * sc)1301 int change_sc(const char *mfsmp,const char *scname,uint16_t chgmask,storage_class *sc) {
1302 	uint32_t nleng;
1303 	char cwdbuff[MAXPATHLEN];
1304 
1305 	nleng = strlen(scname);
1306 	if (nleng>=256) {
1307 		printf("%s: name too long\n",scname);
1308 		return -1;
1309 	}
1310 	if (mfsmp==NULL) {
1311 		mfsmp = getcwd(cwdbuff,MAXPATHLEN);
1312 	}
1313 	if (master_prepare_conn(mfsmp,NULL,NULL,NULL,0,0)<0) {
1314 		return -1;
1315 	}
1316 	master_new_packet();
1317 	master_putname(nleng,scname);
1318 	master_put8bit(0); // packet version
1319 	master_put16bit(chgmask);
1320 	serialize_sc(sc);
1321 	if (master_send_and_receive(CLTOMA_SCLASS_CHANGE,MATOCL_SCLASS_CHANGE)<0) {
1322 		return -1;
1323 	}
1324 	if (master_get_leng()==0) {
1325 		printf("master query: wrong answer (leng)\n");
1326 		master_error();
1327 		return -1;
1328 	}
1329 	if (master_get_leng()==1) {
1330 		if (chgmask==0) {
1331 			printf("storage class show %s: error: %s\n",scname,mfsstrerr(master_get8bit()));
1332 		} else {
1333 			printf("storage class change %s: error: %s\n",scname,mfsstrerr(master_get8bit()));
1334 		}
1335 		return -1;
1336 	}
1337 	if (master_get8bit()!=0) {
1338 		printf("master query: wrong answer (wrong data format)\n");
1339 		master_error();
1340 		return -1;
1341 	}
1342 	if (deserialize_sc(sc)<0) {
1343 		printf("master query: wrong answer (deserialize storage class)\n");
1344 		master_error();
1345 		return -1;
1346 	}
1347 	printf("storage class change %s: ",scname);
1348 	printf_sc(sc,"\n");
1349 	if (master_end_packet()==0) {
1350 		printf("master query: packet size error\n");
1351 		return -1;
1352 	}
1353 	return 0;
1354 }
1355 
show_sc(const char * mfsmp,const char * scname)1356 int show_sc(const char *mfsmp,const char *scname) {
1357 	storage_class sc;
1358 	memset(&sc,0,sizeof(storage_class));
1359 	return change_sc(mfsmp,scname,0,&sc);
1360 }
1361 
remove_sc(const char * mfsmp,const char * scname)1362 int remove_sc(const char *mfsmp,const char *scname) {
1363 	uint32_t nleng;
1364 	char cwdbuff[MAXPATHLEN];
1365 	uint8_t status;
1366 
1367 	nleng = strlen(scname);
1368 	if (nleng>=256) {
1369 		printf("%s: name too long\n",scname);
1370 		return -1;
1371 	}
1372 	if (mfsmp==NULL) {
1373 		mfsmp = getcwd(cwdbuff,MAXPATHLEN);
1374 	}
1375 	if (master_prepare_conn(mfsmp,NULL,NULL,NULL,0,0)<0) {
1376 		return -1;
1377 	}
1378 	master_new_packet();
1379 	master_putname(nleng,scname);
1380 	if (master_send_and_receive(CLTOMA_SCLASS_DELETE,MATOCL_SCLASS_DELETE)<0) {
1381 		return -1;
1382 	}
1383 	if (master_get_leng()!=1) {
1384 		printf("master query: wrong answer (leng)\n");
1385 		master_error();
1386 		return -1;
1387 	}
1388 	status = master_get8bit();
1389 	if (status!=MFS_STATUS_OK) {
1390 		printf("storage class remove %s: error: %s\n",scname,mfsstrerr(status));
1391 		return -1;
1392 	}
1393 	printf("storage class remove %s: ok\n",scname);
1394 	if (master_end_packet()==0) { // pro forma
1395 		printf("master query: packet size error\n");
1396 		return -1;
1397 	}
1398 	return 0;
1399 }
1400 
copy_sc(const char * mfsmp,const char * oldscname,const char * newscname)1401 int copy_sc(const char *mfsmp,const char *oldscname,const char *newscname) {
1402 	uint32_t onleng,nnleng;
1403 	char cwdbuff[MAXPATHLEN];
1404 	uint8_t status;
1405 
1406 	onleng = strlen(oldscname);
1407 	nnleng = strlen(newscname);
1408 	if (onleng>=256) {
1409 		printf("%s: name too long\n",oldscname);
1410 		return -1;
1411 	}
1412 	if (nnleng>=256) {
1413 		printf("%s: name too long\n",newscname);
1414 		return -1;
1415 	}
1416 	if (mfsmp==NULL) {
1417 		mfsmp = getcwd(cwdbuff,MAXPATHLEN);
1418 	}
1419 	if (master_prepare_conn(mfsmp,NULL,NULL,NULL,0,0)<0) {
1420 		return -1;
1421 	}
1422 
1423 	master_new_packet();
1424 	master_putname(onleng,oldscname);
1425 	master_putname(nnleng,newscname);
1426 	if (master_send_and_receive(CLTOMA_SCLASS_DUPLICATE,MATOCL_SCLASS_DUPLICATE)<0) {
1427 		return -1;
1428 	}
1429 	if (master_get_leng()!=1) {
1430 		printf("master query: wrong answer (leng)\n");
1431 		master_error();
1432 		return -1;
1433 	}
1434 	status = master_get8bit();
1435 	if (status!=MFS_STATUS_OK) {
1436 		printf("storage class copy %s->%s: error: %s\n",oldscname,newscname,mfsstrerr(status));
1437 		return -1;
1438 	}
1439 	printf("storage class copy %s->%s: ok\n",oldscname,newscname);
1440 	if (master_end_packet()==0) { // pro forma
1441 		printf("master query: packet size error\n");
1442 		return -1;
1443 	}
1444 	return 0;
1445 }
1446 
move_sc(const char * mfsmp,const char * oldscname,const char * newscname)1447 int move_sc(const char *mfsmp,const char *oldscname,const char *newscname) {
1448 	uint32_t onleng,nnleng;
1449 	char cwdbuff[MAXPATHLEN];
1450 	uint8_t status;
1451 
1452 	onleng = strlen(oldscname);
1453 	nnleng = strlen(newscname);
1454 	if (onleng>=256) {
1455 		printf("%s: name too long\n",oldscname);
1456 		return -1;
1457 	}
1458 	if (nnleng>=256) {
1459 		printf("%s: name too long\n",newscname);
1460 		return -1;
1461 	}
1462 	if (mfsmp==NULL) {
1463 		mfsmp = getcwd(cwdbuff,MAXPATHLEN);
1464 	}
1465 	if (master_prepare_conn(mfsmp,NULL,NULL,NULL,0,0)<0) {
1466 		return -1;
1467 	}
1468 
1469 	master_new_packet();
1470 	master_putname(onleng,oldscname);
1471 	master_putname(nnleng,newscname);
1472 	if (master_send_and_receive(CLTOMA_SCLASS_RENAME,MATOCL_SCLASS_RENAME)<0) {
1473 		return -1;
1474 	}
1475 	if (master_get_leng()!=1) {
1476 		printf("master query: wrong answer (leng)\n");
1477 		master_error();
1478 		return -1;
1479 	}
1480 	status = master_get8bit();
1481 	if (status!=MFS_STATUS_OK) {
1482 		printf("storage class move %s->%s: error: %s\n",oldscname,newscname,mfsstrerr(status));
1483 		return -1;
1484 	}
1485 	printf("storage class move %s->%s: ok\n",oldscname,newscname);
1486 	if (master_end_packet()==0) { // pro forma
1487 		printf("master query: packet size error\n");
1488 		return -1;
1489 	}
1490 	return 0;
1491 }
1492 
list_sc(const char * mfsmp,uint8_t longmode)1493 int list_sc(const char *mfsmp,uint8_t longmode) {
1494 	char scname[256];
1495 	storage_class sc;
1496 	char cwdbuff[MAXPATHLEN];
1497 
1498 	if (mfsmp==NULL) {
1499 		mfsmp = getcwd(cwdbuff,MAXPATHLEN);
1500 	}
1501 	if (master_prepare_conn(mfsmp,NULL,NULL,NULL,0,0)<0) {
1502 		return -1;
1503 	}
1504 
1505 	master_new_packet();
1506 	master_put8bit(longmode);
1507 	if (master_send_and_receive(CLTOMA_SCLASS_LIST,MATOCL_SCLASS_LIST)<0) {
1508 		return -1;
1509 	}
1510 	if (master_get_leng()==1) {
1511 		printf("storage class list: error: %s\n",mfsstrerr(master_get8bit()));
1512 		return -1;
1513 	}
1514 	while (master_bytes_left()>0) {
1515 		master_getname(scname);
1516 		if (longmode&1) {
1517 			if (deserialize_sc(&sc)<0) {
1518 				printf("master query: wrong answer (deserialize storage class)\n");
1519 				master_error();
1520 				return -1;
1521 			}
1522 			printf("%s : ",scname);
1523 			printf_sc(&sc,"\n");
1524 		} else {
1525 			printf("%s\n",scname);
1526 		}
1527 	}
1528 	if (master_end_packet()==0) {
1529 		printf("master query: packet size error\n");
1530 		return -1;
1531 	}
1532 	return 0;
1533 }
1534 
1535 typedef struct _chunk_data {
1536 	uint32_t ip;
1537 	uint16_t port;
1538 	uint8_t status;
1539 } chunk_data;
1540 
chunk_data_cmp(const void * a,const void * b)1541 int chunk_data_cmp(const void*a,const void*b) {
1542 	chunk_data *aa = (chunk_data*)a;
1543 	chunk_data *bb = (chunk_data*)b;
1544 
1545 	if (aa->ip < bb->ip) {
1546 		return -1;
1547 	} else if (aa->ip > bb->ip) {
1548 		return 1;
1549 	} else if (aa->port < bb->port) {
1550 		return -1;
1551 	} else if (aa->port > bb->port) {
1552 		return 1;
1553 	}
1554 	return 0;
1555 }
1556 
get_checksum_block(const char * csstrip,uint32_t csip,uint16_t csport,uint64_t chunkid,uint32_t version,uint8_t crcblock[4096],uint16_t * blocks)1557 int get_checksum_block(const char *csstrip,uint32_t csip,uint16_t csport,uint64_t chunkid,uint32_t version,uint8_t crcblock[4096],uint16_t *blocks) {
1558 	uint8_t reqbuff[20],*wptr,*buff;
1559 	const uint8_t *rptr;
1560 	int fd;
1561 	uint32_t cmd,leng;
1562 	uint16_t cnt;
1563 	uint8_t status;
1564 
1565 	buff = NULL;
1566 	fd = -1;
1567 	cnt=0;
1568 	while (cnt<10) {
1569 		fd = tcpsocket();
1570 		if (fd<0) {
1571 			printf("can't create connection socket: %s\n",strerr(errno));
1572 			goto error;
1573 		}
1574 		if (tcpnumtoconnect(fd,csip,csport,(cnt%2)?(300*(1<<(cnt>>1))):(200*(1<<(cnt>>1))))<0) {
1575 			cnt++;
1576 			if (cnt==10) {
1577 				printf("can't connect to chunkserver %s:%"PRIu16": %s\n",csstrip,csport,strerr(errno));
1578 				goto error;
1579 			}
1580 			tcpclose(fd);
1581 			fd = -1;
1582 		} else {
1583 			cnt=10;
1584 		}
1585 	}
1586 
1587 	// 1 - get checksum block
1588 	buff = NULL;
1589 	wptr = reqbuff;
1590 	put32bit(&wptr,ANTOCS_GET_CHUNK_CHECKSUM_TAB);
1591 	put32bit(&wptr,12);
1592 	put64bit(&wptr,chunkid);
1593 	put32bit(&wptr,version);
1594 	if (tcpwrite(fd,reqbuff,20)!=20) {
1595 		printf("%s:%"PRIu16": cs query: send error\n",csstrip,csport);
1596 		goto error;
1597 	}
1598 	if (tcpread(fd,reqbuff,8)!=8) {
1599 		printf("%s:%"PRIu16" cs query: receive error\n",csstrip,csport);
1600 		goto error;
1601 	}
1602 	rptr = reqbuff;
1603 	cmd = get32bit(&rptr);
1604 	leng = get32bit(&rptr);
1605 	if (cmd!=CSTOAN_CHUNK_CHECKSUM_TAB) {
1606 		printf("%s:%"PRIu16" cs query: wrong answer (type)\n",csstrip,csport);
1607 		goto error;
1608 	}
1609 	if (leng!=13 && leng!=(4096+12)) {
1610 		printf("%s:%"PRIu16" cs query: wrong answer (size)\n",csstrip,csport);
1611 		goto error;
1612 	}
1613 	buff = malloc(leng);
1614 	if (tcpread(fd,buff,leng)!=(int32_t)leng) {
1615 		printf("%s:%"PRIu16" cs query: receive error\n",csstrip,csport);
1616 		goto error;
1617 	}
1618 	rptr = buff;
1619 	if (chunkid!=get64bit(&rptr)) {
1620 		printf("%s:%"PRIu16" cs query: wrong answer (chunkid)\n",csstrip,csport);
1621 		goto error;
1622 	}
1623 	if (version!=get32bit(&rptr)) {
1624 		printf("%s:%"PRIu16" cs query: wrong answer (version)\n",csstrip,csport);
1625 		goto error;
1626 	}
1627 	leng-=12;
1628 	if (leng==1) {
1629 		printf("%s:%"PRIu16" cs query error: %s\n",csstrip,csport,mfsstrerr(*rptr));
1630 		goto error;
1631 	}
1632 	memcpy(crcblock,rptr,4096);
1633 	free(buff);
1634 
1635 	// 2 - get number of blocks
1636 	buff = NULL;
1637 	wptr = reqbuff;
1638 	put32bit(&wptr,ANTOCS_GET_CHUNK_BLOCKS);
1639 	put32bit(&wptr,12);
1640 	put64bit(&wptr,chunkid);
1641 	put32bit(&wptr,version);
1642 	if (tcpwrite(fd,reqbuff,20)!=20) {
1643 		printf("%s:%"PRIu16": cs query: send error\n",csstrip,csport);
1644 		goto error;
1645 	}
1646 	if (tcpread(fd,reqbuff,8)!=8) {
1647 		printf("%s:%"PRIu16" cs query: receive error\n",csstrip,csport);
1648 		goto error;
1649 	}
1650 	rptr = reqbuff;
1651 	cmd = get32bit(&rptr);
1652 	leng = get32bit(&rptr);
1653 	if (cmd!=CSTOAN_CHUNK_BLOCKS) {
1654 		printf("%s:%"PRIu16" cs query: wrong answer (type)\n",csstrip,csport);
1655 		goto error;
1656 	}
1657 	if (leng!=15) {
1658 		printf("%s:%"PRIu16" cs query: wrong answer (size)\n",csstrip,csport);
1659 		goto error;
1660 	}
1661 	buff = malloc(leng);
1662 	if (tcpread(fd,buff,leng)!=(int32_t)leng) {
1663 		printf("%s:%"PRIu16" cs query: receive error\n",csstrip,csport);
1664 		goto error;
1665 	}
1666 	rptr = buff;
1667 	if (chunkid!=get64bit(&rptr)) {
1668 		printf("%s:%"PRIu16" cs query: wrong answer (chunkid)\n",csstrip,csport);
1669 		goto error;
1670 	}
1671 	if (version!=get32bit(&rptr)) {
1672 		printf("%s:%"PRIu16" cs query: wrong answer (version)\n",csstrip,csport);
1673 		goto error;
1674 	}
1675 	*blocks = get16bit(&rptr);
1676 	status = get8bit(&rptr);
1677 	if (status!=MFS_STATUS_OK) {
1678 		printf("%s:%"PRIu16" cs query error: %s\n",csstrip,csport,mfsstrerr(status));
1679 		goto error;
1680 	}
1681 	free(buff);
1682 
1683 	tcpclose(fd);
1684 	return 0;
1685 
1686 error:
1687 	if (buff!=NULL) {
1688 		free(buff);
1689 	}
1690 	if (fd>=0) {
1691 		tcpclose(fd);
1692 	}
1693 	return -1;
1694 }
1695 
digest_to_str(char strdigest[33],uint8_t digest[16])1696 void digest_to_str(char strdigest[33],uint8_t digest[16]) {
1697 	uint32_t i;
1698 	for (i=0 ; i<16 ; i++) {
1699 		snprintf(strdigest+2*i,3,"%02X",digest[i]);
1700 	}
1701 	strdigest[32]='\0';
1702 }
1703 
file_info(uint8_t fileinfomode,const char * fname)1704 int file_info(uint8_t fileinfomode,const char *fname) {
1705 	uint32_t fchunks;
1706 	uint8_t fchunksvalid;
1707 	uint32_t indx,inode,version;
1708 	uint32_t chunks,copies,vcopies,copy;
1709 	char *strtype;
1710 	char csstrip[16];
1711 	chunk_data *cdtab;
1712 	uint8_t protover;
1713 	uint64_t chunkid;
1714 	uint64_t fleng;
1715 	uint8_t crcblock[4096];
1716 	uint16_t blocks;
1717 	md5ctx filectx,chunkctx;
1718 	uint8_t chunkdigest[16],currentdigest[16];
1719 	uint8_t firstdigest;
1720 	uint8_t checksumerror;
1721 	char strdigest[33];
1722 
1723 	if (master_prepare_conn(fname,&inode,NULL,&fleng,0,0)<0) {
1724 		return -1;
1725 	}
1726 	master_new_packet();
1727 	master_put32bit(inode);
1728 	if (master_send_and_receive(CLTOMA_FUSE_CHECK,MATOCL_FUSE_CHECK)<0) {
1729 		return -1;
1730 	}
1731 	if (master_get_leng()==1) {
1732 		printf("%s: %s\n",fname,mfsstrerr(master_get8bit()));
1733 		return -1;
1734 	} else if ((master_get_leng()%3!=0 || master_get_leng()>33) && master_get_leng()!=44 && master_get_leng()!=48) {
1735 		printf("%s: master query: wrong answer (leng)\n",fname);
1736 		master_error();
1737 		return -1;
1738 	}
1739 	if (fileinfomode&FILEINFO_QUICK) {
1740 		printf("%s:\n",fname);
1741 	}
1742 	fchunks = 0;
1743 	fchunksvalid = 0;
1744 	if (master_get_leng()%3==0 && master_get_leng()<=33) {
1745 		while (master_bytes_left()>0) {
1746 			copies = master_get8bit();
1747 			chunks = master_get16bit();
1748 			if (fileinfomode&FILEINFO_QUICK) {
1749 				if (copies==1) {
1750 					printf("1 copy:");
1751 				} else {
1752 					printf("%"PRIu32" copies:",copies);
1753 				}
1754 				print_number(" ","\n",chunks,1,0,1);
1755 			}
1756 			fchunks += chunks;
1757 		}
1758 	} else {
1759 		for (copies=0 ; copies<11 ; copies++) {
1760 			chunks = master_get32bit();
1761 			if (chunks>0 && (fileinfomode&FILEINFO_QUICK)) {
1762 				if (copies==1) {
1763 					printf(" chunks with 1 copy:    ");
1764 				} else if (copies>=10) {
1765 					printf(" chunks with 10+ copies:");
1766 				} else {
1767 					printf(" chunks with %u copies:  ",copies);
1768 				}
1769 				print_number(" ","\n",chunks,1,0,1);
1770 			}
1771 			fchunks += chunks;
1772 		}
1773 		if (master_get_leng()==48) {
1774 			chunks = master_get32bit();
1775 			if (chunks>0 && (fileinfomode&FILEINFO_QUICK)) {
1776 				printf(" empty (zero) chunks:   ");
1777 				print_number(" ","\n",chunks,1,0,1);
1778 			}
1779 			fchunks += chunks;
1780 			fchunksvalid = 1;
1781 		}
1782 	}
1783 	if (master_end_packet()==0) {
1784 		printf("%s: master query: packet size error\n",fname);
1785 		return -1;
1786 	}
1787 	if ((fileinfomode&FILEINFO_QUICK)==0) {
1788 		if (fchunksvalid==0) { // in this case fchunks doesn't include 'empty' chunks, so use file size to fix 'fchunks' if necessary
1789 			if (fchunks < ((fleng+MFSCHUNKMASK)>>MFSCHUNKBITS)) {
1790 				fchunks = ((fleng+MFSCHUNKMASK)>>MFSCHUNKBITS);
1791 			}
1792 		}
1793 //	printf("masterversion: %08X\n",masterversion);
1794 		if (fileinfomode&FILEINFO_SIGNATURE) {
1795 			md5_init(&filectx);
1796 		}
1797 		printf("%s:\n",fname);
1798 		if (fchunks==0) {
1799 			printf("\tno chunks - empty file\n");
1800 		}
1801 		for (indx=0 ; indx<fchunks ; indx++) {
1802 			master_new_packet();
1803 			if (master_get_version()<VERSION2INT(3,0,26)) {
1804 				uint32_t leng;
1805 				master_put32bit(inode);
1806 				master_put32bit(indx);
1807 				if (master_get_version()>=VERSION2INT(3,0,3)) {
1808 					master_put8bit(0); // canmodatime
1809 				}
1810 				if (master_send_and_receive(CLTOMA_FUSE_READ_CHUNK,MATOCL_FUSE_READ_CHUNK)<0) {
1811 					return -1;
1812 				}
1813 				leng = master_get_leng();
1814 				if (leng==1) {
1815 					printf("%s [%"PRIu32"]: %s\n",fname,indx,mfsstrerr(master_get8bit()));
1816 					return -1;
1817 				} else if (leng&1) {
1818 					protover = master_get8bit();
1819 					if (protover!=1 && protover!=2) {
1820 						printf("%s [%"PRIu32"]: master query: unknown protocol id (%"PRIu8")\n",fname,indx,protover);
1821 						master_error();
1822 						return -1;
1823 					}
1824 					if (leng<21 || (protover==1 && ((leng-21)%10)!=0) || (protover==2 && ((leng-21)%14)!=0)) {
1825 						printf("%s [%"PRIu32"]: master query: wrong answer (leng)\n",fname,indx);
1826 						master_error();
1827 						return -1;
1828 					}
1829 				} else {
1830 					if (leng<20 || ((leng-20)%6)!=0) {
1831 						printf("%s [%"PRIu32"]: master query: wrong answer (leng)\n",fname,indx);
1832 						master_error();
1833 						return -1;
1834 					}
1835 					protover = 0;
1836 				}
1837 				(void)master_get64bit(); // fleng
1838 				if (protover==2) {
1839 					copies = (leng-21)/14;
1840 				} else if (protover==1) {
1841 					copies = (leng-21)/10;
1842 				} else {
1843 					copies = (leng-20)/6;
1844 				}
1845 			} else {
1846 				master_put32bit(inode);
1847 				master_put32bit(indx);
1848 				if (master_send_and_receive(CLTOMA_FUSE_CHECK,MATOCL_FUSE_CHECK)<0) {
1849 					return -1;
1850 				}
1851 				if (master_get_leng()==1) {
1852 					printf("%s [%"PRIu32"]: %s\n",fname,indx,mfsstrerr(master_get8bit()));
1853 					return -1;
1854 				} else {
1855 					if (master_get_leng()<12 || ((master_get_leng()-12)%7)!=0) {
1856 						printf("%s [%"PRIu32"]: master query: wrong answer (leng)\n",fname,indx);
1857 						master_error();
1858 						return -1;
1859 					}
1860 					protover = 255;
1861 					copies = (master_get_leng()-12)/7;
1862 				}
1863 			}
1864 			chunkid = master_get64bit();
1865 			version = master_get32bit();
1866 			if (chunkid==0 && version==0) {
1867 				printf("\tchunk %"PRIu32": empty\n",indx);
1868 			} else {
1869 				printf("\tchunk %"PRIu32": %016"PRIX64"_%08"PRIX32" / (id:%"PRIu64" ver:%"PRIu32")\n",indx,chunkid,version,chunkid,version);
1870 				vcopies = 0;
1871 				if (copies>0) {
1872 					cdtab = malloc(copies*sizeof(chunk_data));
1873 				} else {
1874 					cdtab = NULL;
1875 				}
1876 				for (copy=0 ; copy<copies ; copy++) {
1877 					cdtab[copy].ip = master_get32bit();
1878 					cdtab[copy].port = master_get16bit();
1879 					if (protover==255) {
1880 						cdtab[copy].status = master_get8bit();
1881 					} else {
1882 						cdtab[copy].status = CHECK_VALID;
1883 						if (protover>=1) {
1884 							(void)master_get32bit();
1885 						}
1886 						if (protover>=2) {
1887 							(void)master_get32bit();
1888 						}
1889 					}
1890 				}
1891 				if (copies>0) {
1892 					qsort(cdtab,copies,sizeof(chunk_data),chunk_data_cmp);
1893 				}
1894 				firstdigest = 1;
1895 				checksumerror = 0;
1896 				for (copy=0 ; copy<copies ; copy++) {
1897 					snprintf(csstrip,16,"%"PRIu8".%"PRIu8".%"PRIu8".%"PRIu8,(uint8_t)((cdtab[copy].ip>>24)&0xFF),(uint8_t)((cdtab[copy].ip>>16)&0xFF),(uint8_t)((cdtab[copy].ip>>8)&0xFF),(uint8_t)(cdtab[copy].ip&0xFF));
1898 					csstrip[15]=0;
1899 					if (protover==255) {
1900 						switch (cdtab[copy].status) {
1901 							case CHECK_VALID:
1902 								strtype = "VALID";
1903 								vcopies++;
1904 								break;
1905 							case CHECK_MARKEDFORREMOVAL:
1906 								strtype = "MARKED FOR REMOVAL";
1907 								break;
1908 							case CHECK_WRONGVERSION:
1909 								strtype = "WRONG VERSION";
1910 								break;
1911 							case CHECK_WV_AND_MFR:
1912 								strtype = "WRONG VERSION , MARKED FOR REMOVAL";
1913 								break;
1914 							case CHECK_INVALID:
1915 								strtype = "INVALID";
1916 								break;
1917 							default:
1918 								strtype = "???";
1919 						}
1920 					} else if (protover==2) {
1921 						strtype = "VALID";
1922 						vcopies++;
1923 					} else if (protover==1) {
1924 						strtype = "VALID";
1925 						vcopies++;
1926 					} else {
1927 						strtype = "VALID";
1928 						vcopies++;
1929 					}
1930 					if (fileinfomode&(FILEINFO_CRC|FILEINFO_SIGNATURE)) {
1931 						if (get_checksum_block(csstrip,cdtab[copy].ip,cdtab[copy].port,chunkid,version,crcblock,&blocks)==0) {
1932 							md5_init(&chunkctx);
1933 							md5_update(&chunkctx,crcblock,4*blocks);
1934 							if ((fileinfomode&FILEINFO_SIGNATURE) && firstdigest) {
1935 								md5_update(&filectx,crcblock,4*blocks);
1936 							}
1937 							md5_final(currentdigest,&chunkctx);
1938 							if (firstdigest) {
1939 								memcpy(chunkdigest,currentdigest,16);
1940 							} else {
1941 								if (memcmp(chunkdigest,currentdigest,16)!=0) {
1942 									checksumerror = 1;
1943 								}
1944 							}
1945 							firstdigest = 0;
1946 							if (fileinfomode&FILEINFO_CRC) {
1947 								digest_to_str(strdigest,currentdigest);
1948 								printf("\t\tcopy %"PRIu32": %s:%"PRIu16" (status:%s ; blocks: %u ; checksum digest: %s)\n",copy+1,csstrip,cdtab[copy].port,strtype,blocks,strdigest);
1949 							} else {
1950 								printf("\t\tcopy %"PRIu32": %s:%"PRIu16" (status:%s)\n",copy+1,csstrip,cdtab[copy].port,strtype);
1951 							}
1952 						} else {
1953 							if (fileinfomode&FILEINFO_CRC) {
1954 								printf("\t\tcopy %"PRIu32": %s:%"PRIu16" (status:%s) - can't get checksum\n",copy+1,csstrip,cdtab[copy].port,strtype);
1955 							} else {
1956 								printf("\t\tcopy %"PRIu32": %s:%"PRIu16" (status:%s)\n",copy+1,csstrip,cdtab[copy].port,strtype);
1957 							}
1958 						}
1959 					} else {
1960 						printf("\t\tcopy %"PRIu32": %s:%"PRIu16" (status:%s)\n",copy+1,csstrip,cdtab[copy].port,strtype);
1961 					}
1962 				}
1963 				if (checksumerror) {
1964 					printf("\t\tcopies have different checksums !!!\n");
1965 				}
1966 				if ((fileinfomode&FILEINFO_SIGNATURE) && firstdigest) {
1967 					printf("\t\tcouldn't add this chunk to signature !!!\n");
1968 				}
1969 				if (vcopies==0) {
1970 					printf("\t\tno valid copies !!!\n");
1971 				}
1972 				if (cdtab!=NULL) {
1973 					free(cdtab);
1974 				}
1975 			}
1976 			if (master_end_packet()==0) {
1977 				printf("%s: master query: packet size error\n",fname);
1978 				return -1;
1979 			}
1980 		}
1981 		if (fileinfomode&FILEINFO_SIGNATURE) {
1982 			md5_final(currentdigest,&filectx);
1983 			digest_to_str(strdigest,currentdigest);
1984 			printf("%s signature: %s\n",fname,strdigest);
1985 		}
1986 	}
1987 	return 0;
1988 }
1989 
append_file(const char * fname,const char * afname,int64_t slice_from,int64_t slice_to)1990 int append_file(const char *fname,const char *afname,int64_t slice_from,int64_t slice_to) {
1991 	uint32_t inode,ainode,uid,gid;
1992 	uint32_t slice_from_abs,slice_to_abs;
1993 	uint8_t flags;
1994 	gid_t grouplist[NGROUPS_MAX];
1995 	uint32_t i,gids;
1996 	uint8_t addmaingroup;
1997 	mode_t dmode,smode;
1998 	uint8_t status;
1999 
2000 	if (slice_from < INT64_C(-0xFFFFFFFF) || slice_to > INT64_C(0xFFFFFFFF) || slice_to < INT64_C(-0xFFFFFFFF) || slice_to > INT64_C(0xFFFFFFFF)) {
2001 		printf("bad slice indexes\n");
2002 		return -1;
2003 	}
2004 	flags = 0;
2005 	if (slice_from<0) {
2006 		slice_from_abs = -slice_from;
2007 		flags |= APPEND_SLICE_FROM_NEG;
2008 	} else {
2009 		slice_from_abs = slice_from;
2010 	}
2011 	if (slice_to<0) {
2012 		slice_to_abs = -slice_to;
2013 		flags |= APPEND_SLICE_TO_NEG;
2014 	} else {
2015 		slice_to_abs = slice_to;
2016 	}
2017 
2018 	if (master_prepare_conn(fname,&inode,&dmode,NULL,0,1)<0) {
2019 		return -1;
2020 	}
2021 	if (master_prepare_conn(afname,&ainode,&smode,NULL,1,1)<0) {
2022 		return -1;
2023 	}
2024 
2025 	if ((slice_from!=0 || slice_to!=0x80000000) && master_get_version()<VERSION2INT(3,0,92)) {
2026 		printf("slices not supported in your master - please upgrade it\n");
2027 		return -1;
2028 	}
2029 	if ((smode&S_IFMT)!=S_IFREG) {
2030 		printf("%s: not a file\n",afname);
2031 		return -1;
2032 	}
2033 	if ((dmode&S_IFMT)!=S_IFREG) {
2034 		printf("%s: not a file\n",fname);
2035 		return -1;
2036 	}
2037 	uid = getuid();
2038 	gid = getgid();
2039 	if (master_get_version()>=VERSION2INT(2,0,0)) {
2040 		gids = getgroups(NGROUPS_MAX,grouplist);
2041 		addmaingroup = 1;
2042 		for (i=0 ; i<gids ; i++) {
2043 			if (grouplist[i]==gid) {
2044 				addmaingroup = 0;
2045 			}
2046 		}
2047 	} else {
2048 		gids = 0;
2049 		addmaingroup = 0;
2050 	}
2051 	master_new_packet();
2052 	if (master_get_version()>=VERSION2INT(3,0,92)) {
2053 		master_put8bit(flags);
2054 		master_put32bit(inode);
2055 		master_put32bit(ainode);
2056 		master_put32bit(slice_from_abs);
2057 		master_put32bit(slice_to_abs);
2058 	} else {
2059 		master_put32bit(inode);
2060 		master_put32bit(ainode);
2061 	}
2062 	master_put32bit(uid);
2063 	if (master_get_version()<VERSION2INT(2,0,0)) {
2064 		master_put32bit(gid);
2065 	} else {
2066 		master_put32bit(addmaingroup+gids);
2067 		if (addmaingroup) {
2068 			master_put32bit(gid);
2069 		}
2070 		for (i=0 ; i<gids ; i++) {
2071 			master_put32bit(grouplist[i]);
2072 		}
2073 	}
2074 	if (master_send_and_receive(CLTOMA_FUSE_APPEND_SLICE,MATOCL_FUSE_APPEND_SLICE)<0) {
2075 		return -1;
2076 	}
2077 	if (master_get_leng()!=1) {
2078 		printf("%s: master query: wrong answer (leng)\n",fname);
2079 		master_error();
2080 		return -1;
2081 	}
2082 	status = master_get8bit();
2083 	if (status!=MFS_STATUS_OK) {
2084 		printf("%s: %s\n",fname,mfsstrerr(status));
2085 		return -1;
2086 	}
2087 	if (master_end_packet()==0) {
2088 		printf("%s: master query: packet size error\n",fname);
2089 		return -1;
2090 	}
2091 	return 0;
2092 }
2093 
2094 static uint32_t dirnode_cnt;
2095 static uint32_t filenode_cnt;
2096 static uint32_t touched_inodes;
2097 static uint64_t sumlength;
2098 static uint64_t chunk_size_cnt;
2099 static uint64_t chunk_rsize_cnt;
2100 
sc_node_info(uint32_t inode)2101 int sc_node_info(uint32_t inode) {
2102 	uint16_t anstype;
2103 	uint64_t fleng;
2104 	uint64_t chunkid;
2105 	uint32_t chunksize;
2106 	uint32_t childinode;
2107 	uint64_t continueid;
2108 	uint8_t copies;
2109 
2110 //	printf("inode: %"PRIu32"\n",inode);
2111 	continueid = 0;
2112 	touched_inodes++;
2113 	do {
2114 		master_new_packet();
2115 		master_put32bit(inode);
2116 		master_put32bit(500); // 500 !!!
2117 		master_put64bit(continueid);
2118 		if (master_send_and_receive(CLTOMA_NODE_INFO,MATOCL_NODE_INFO)<0) {
2119 			return -1;
2120 		}
2121 		if (master_get_leng()==1) {
2122 			// error - ignore
2123 			return 0;
2124 		}
2125 		if (master_get_leng()<2) {
2126 			printf("inode: %"PRIu32" ; master query: wrong answer (size)\n",inode);
2127 			master_error();
2128 			return -1;
2129 		}
2130 		anstype = master_get16bit();
2131 		if (anstype==1 && ((master_get_leng()-2)%4)==0) { // directory
2132 //			printf("directory\n");
2133 			if (continueid==0) {
2134 				dirnode_cnt++;
2135 			}
2136 			continueid = master_get64bit();
2137 //			printf("continueid: %"PRIX64"\n",continueid);
2138 			while (master_bytes_left()>0) {
2139 				childinode = master_get32bit();
2140 //				printf("inode: %"PRIu32"\n",childinode);
2141 				if (sc_enqueue(childinode)==0) {
2142 					touched_inodes++; // repeated nodes - increment here
2143 				}
2144 			}
2145 		} else if (anstype==2 && (master_get_leng()-2-16)%13==0) { // file
2146 //			printf("file\n");
2147 			if (continueid==0) {
2148 				filenode_cnt++;
2149 			}
2150 			continueid = master_get64bit();
2151 			fleng = master_get64bit();
2152 //			printf("continueid: %"PRIu64" ; fleng: %"PRIu64"\n",continueid,fleng);
2153 			sumlength += fleng;
2154 			while (master_bytes_left()>0) {
2155 				chunkid = master_get64bit();
2156 				chunksize = master_get32bit();
2157 				copies = master_get8bit();
2158 //				printf("chunk: %016"PRIX64" ; chunksize: %"PRIu32" ; copies:%"PRIu8"\n",chunkid,chunksize,copies);
2159 				if (liset_addval(chunk_liset,chunkid)==0) { // new chunk ?
2160 					chunk_size_cnt += chunksize;
2161 					chunk_rsize_cnt += copies * chunksize;
2162 				}
2163 			}
2164 		} else {
2165 			continueid = 0;
2166 		}
2167 		if (master_end_packet()==0) { // pro forma
2168 			printf("master query: packet size error\n");
2169 			return -1;
2170 		}
2171 	} while (continueid!=0);
2172 	return 0;
2173 }
2174 
2175 
dir_info(uint8_t dirinfomode,const char * fname)2176 int dir_info(uint8_t dirinfomode,const char *fname) {
2177 	uint32_t inode;
2178 	uint32_t inodes,dirs,files,chunks;
2179 	uint64_t length,size,realsize;
2180 
2181 	if (master_prepare_conn(fname,&inode,NULL,NULL,0,0)<0) {
2182 		return -1;
2183 	}
2184 	master_new_packet();
2185 	master_put32bit(inode);
2186 	if (master_send_and_receive(CLTOMA_FUSE_GETDIRSTATS,MATOCL_FUSE_GETDIRSTATS)<0) {
2187 		return -1;
2188 	}
2189 	if (master_get_leng()==1) {
2190 		printf("%s: %s\n",fname,mfsstrerr(master_get8bit()));
2191 		return -1;
2192 	} else if (master_get_leng()!=56 && master_get_leng()!=40) {
2193 		printf("%s: master query: wrong answer (leng)\n",fname);
2194 		master_error();
2195 		return -1;
2196 	}
2197 	inodes = master_get32bit();
2198 	dirs = master_get32bit();
2199 	files = master_get32bit();
2200 	if (master_get_leng()==56) {
2201 		(void)master_get64bit();
2202 	}
2203 	chunks = master_get32bit();
2204 	if (master_get_leng()==56) {
2205 		(void)master_get64bit();
2206 	}
2207 	length = master_get64bit();
2208 	size = master_get64bit();
2209 	realsize = master_get64bit();
2210 	if (dirinfomode==0 || dirinfomode==DIRINFO_PRECISE) {
2211 		printf("%s:\n",fname);
2212 		print_number(" inodes:       ","\n",inodes,0,0,1);
2213 		print_number("  directories: ","\n",dirs,0,0,1);
2214 		print_number("  files:       ","\n",files,0,0,1);
2215 		print_number(" chunks:       ","\n",chunks,0,0,1);
2216 		print_number(" length:       ","\n",length,0,1,1);
2217 		print_number(" size:         ","\n",size,0,1,1);
2218 		print_number(" realsize:     ","\n",realsize,0,1,1);
2219 	} else {
2220 		if (dirinfomode&DIRINFO_INODES) {
2221 			print_number_only(inodes,0);
2222 			printf("\t");
2223 		}
2224 		if (dirinfomode&DIRINFO_DIRS) {
2225 			print_number_only(dirs,0);
2226 			printf("\t");
2227 		}
2228 		if (dirinfomode&DIRINFO_FILES) {
2229 			print_number_only(files,0);
2230 			printf("\t");
2231 		}
2232 		if (dirinfomode&DIRINFO_CHUNKS) {
2233 			print_number_only(chunks,0);
2234 			printf("\t");
2235 		}
2236 		if (dirinfomode&DIRINFO_LENGTH) {
2237 			print_number_only(length,1);
2238 			printf("\t");
2239 		}
2240 		if (dirinfomode&DIRINFO_SIZE) {
2241 			print_number_only(size,1);
2242 			printf("\t");
2243 		}
2244 		if (dirinfomode&DIRINFO_REALSIZE) {
2245 			print_number_only(realsize,1);
2246 			printf("\t");
2247 		}
2248 		printf("%s\n",fname);
2249 	}
2250 	if (master_end_packet()==0) {
2251 		printf("%s: master query: packet size error\n",fname);
2252 		return -1;
2253 	}
2254 	if (dirinfomode&DIRINFO_PRECISE) {
2255 		uint16_t progress;
2256 		double seconds,lseconds;
2257 		uint8_t err;
2258 
2259 		if (master_get_version()<VERSION2INT(3,0,73)) {
2260 			printf("precise data calculation needs master at least in version 3.0.73 - upgrade your unit\n");
2261 		} else {
2262 			err = 0;
2263 
2264 			qhead = NULL;
2265 			qtail = &qhead;
2266 
2267 			dirnode_cnt = 0;
2268 			filenode_cnt = 0;
2269 			touched_inodes = 0;
2270 			sumlength = 0;
2271 			chunk_size_cnt = 0;
2272 			chunk_rsize_cnt = 0;
2273 			lseconds = monotonic_seconds();
2274 
2275 			inode_liset = liset_new();
2276 			chunk_liset = liset_new();
2277 			sc_enqueue(inode);
2278 			while (sc_dequeue(&inode)) {
2279 				if (err==0) {
2280 					if (sc_node_info(inode)<0) {
2281 						err = 1;
2282 					}
2283 					progress = ((uint64_t)touched_inodes * 10000ULL) / (uint64_t)inodes;
2284 					if (progress>9999) {
2285 						progress=9999;
2286 					}
2287 					seconds = monotonic_seconds();
2288 					if (lseconds+0.1<seconds) {
2289 						lseconds = seconds;
2290 						printf("\r%2u.%02u%% complete ",(unsigned int)(progress/100),(unsigned int)(progress%100));fflush(stdout);
2291 					}
2292 				}
2293 			}
2294 			printf("\r");
2295 			if (err==0) {
2296 				if (dirinfomode==DIRINFO_PRECISE) {
2297 					printf("%s (precise data):\n",fname);
2298 					print_number(" inodes:       ","\n",liset_card(inode_liset),0,0,1);
2299 					print_number("  directories: ","\n",dirnode_cnt,0,0,1);
2300 					print_number("  files:       ","\n",filenode_cnt,0,0,1);
2301 					print_number(" chunks:       ","\n",liset_card(chunk_liset),0,0,1);
2302 					print_number(" length:       ","\n",sumlength,0,1,1);
2303 					print_number(" size:         ","\n",chunk_size_cnt,0,1,1);
2304 					print_number(" realsize:     ","\n",chunk_rsize_cnt,0,1,1);
2305 				} else {
2306 					if (dirinfomode&DIRINFO_INODES) {
2307 						print_number_only(liset_card(inode_liset),0);
2308 						printf("\t");
2309 					}
2310 					if (dirinfomode&DIRINFO_DIRS) {
2311 						print_number_only(dirnode_cnt,0);
2312 						printf("\t");
2313 					}
2314 					if (dirinfomode&DIRINFO_FILES) {
2315 						print_number_only(filenode_cnt,0);
2316 						printf("\t");
2317 					}
2318 					if (dirinfomode&DIRINFO_CHUNKS) {
2319 						print_number_only(liset_card(chunk_liset),0);
2320 						printf("\t");
2321 					}
2322 					if (dirinfomode&DIRINFO_LENGTH) {
2323 						print_number_only(sumlength,1);
2324 						printf("\t");
2325 					}
2326 					if (dirinfomode&DIRINFO_SIZE) {
2327 						print_number_only(chunk_size_cnt,1);
2328 						printf("\t");
2329 					}
2330 					if (dirinfomode&DIRINFO_REALSIZE) {
2331 						print_number_only(chunk_rsize_cnt,1);
2332 						printf("\t");
2333 					}
2334 					printf("%s (precise data)\n",fname);
2335 				}
2336 			}
2337 			liset_remove(chunk_liset);
2338 			liset_remove(inode_liset);
2339 		}
2340 	}
2341 	return 0;
2342 }
2343 
file_repair(const char * fname)2344 int file_repair(const char *fname) {
2345 	uint32_t inode,uid,gid;
2346 	gid_t grouplist[NGROUPS_MAX];
2347 	uint32_t i,gids;
2348 	uint8_t addmaingroup;
2349 	uint32_t notchanged,erased,repaired;
2350 
2351 	if (master_prepare_conn(fname,&inode,NULL,NULL,0,1)<0) {
2352 		return -1;
2353 	}
2354 	uid = getuid();
2355 	gid = getgid();
2356 	if (master_get_version()>=VERSION2INT(2,0,0)) {
2357 		gids = getgroups(NGROUPS_MAX,grouplist);
2358 		addmaingroup = 1;
2359 		for (i=0 ; i<gids ; i++) {
2360 			if (grouplist[i]==gid) {
2361 				addmaingroup = 0;
2362 			}
2363 		}
2364 	} else {
2365 		gids = 0;
2366 		addmaingroup = 0;
2367 	}
2368 	master_new_packet();
2369 	master_put32bit(inode);
2370 	master_put32bit(uid);
2371 	if (master_get_version()<VERSION2INT(2,0,0)) {
2372 		master_put32bit(gid);
2373 	} else {
2374 		master_put32bit(addmaingroup+gids);
2375 		if (addmaingroup) {
2376 			master_put32bit(gid);
2377 		}
2378 		for (i=0 ; i<gids ; i++) {
2379 			master_put32bit(grouplist[i]);
2380 		}
2381 	}
2382 	if (master_send_and_receive(CLTOMA_FUSE_REPAIR,MATOCL_FUSE_REPAIR)<0) {
2383 		return -1;
2384 	}
2385 	if (master_get_leng()==1) {
2386 		printf("%s: %s\n",fname,mfsstrerr(master_get8bit()));
2387 		return -1;
2388 	} else if (master_get_leng()!=12) {
2389 		printf("%s: master query: wrong answer (leng)\n",fname);
2390 		master_error();
2391 		return -1;
2392 	}
2393 	notchanged = master_get32bit();
2394 	erased = master_get32bit();
2395 	repaired = master_get32bit();
2396 	printf("%s:\n",fname);
2397 	print_number(" chunks not changed: ","\n",notchanged,1,0,1);
2398 	print_number(" chunks erased:      ","\n",erased,1,0,1);
2399 	print_number(" chunks repaired:    ","\n",repaired,1,0,1);
2400 	if (master_end_packet()==0) {
2401 		printf("%s: master query: packet size error\n",fname);
2402 		return -1;
2403 	}
2404 	return 0;
2405 }
2406 
2407 /*
2408 int eattr_control(const char *fname,uint8_t mode,uint8_t eattr) {
2409 	uint8_t reqbuff[22],*wptr,*buff;
2410 	const uint8_t *rptr;
2411 	uint32_t cmd,leng,inode;
2412 	uint8_t nodeeattr,functioneattr;
2413 //	uint32_t curinodes;
2414 //	uint64_t curlength,cursize,currealsize;
2415 	int fd;
2416 	fd = open_master_conn(fname,&inode,NULL,NULL,0,(mode<2)?1:0);
2417 	if (fd<0) {
2418 		return -1;
2419 	}
2420 	wptr = reqbuff;
2421 	put32bit(&wptr,CLTOMA_FUSE_EATTR);
2422 	put32bit(&wptr,14);
2423 	put32bit(&wptr,0);
2424 	put32bit(&wptr,inode);
2425 	put32bit(&wptr,getuid());
2426 	put8bit(&wptr,mode&1);
2427 	put8bit(&wptr,(mode>1)?0:eattr);
2428 	if (tcpwrite(fd,reqbuff,22)!=22) {
2429 		printf("%s: master query: send error\n",fname);
2430 		close_master_conn(1);
2431 		return -1;
2432 	}
2433 	if (tcpread(fd,reqbuff,8)!=8) {
2434 		printf("%s: master query: receive error\n",fname);
2435 		close_master_conn(1);
2436 		return -1;
2437 	}
2438 	rptr = reqbuff;
2439 	cmd = get32bit(&rptr);
2440 	leng = get32bit(&rptr);
2441 	if (cmd!=MATOCL_FUSE_EATTR) {
2442 		printf("%s: master query: wrong answer (type)\n",fname);
2443 		close_master_conn(1);
2444 		return -1;
2445 	}
2446 	buff = malloc(leng);
2447 	if (tcpread(fd,buff,leng)!=(int32_t)leng) {
2448 		printf("%s: master query: receive error\n",fname);
2449 		free(buff);
2450 		close_master_conn(1);
2451 		return -1;
2452 	}
2453 	rptr = buff;
2454 	cmd = get32bit(&rptr);	// queryid
2455 	if (cmd!=0) {
2456 		printf("%s: master query: wrong answer (queryid)\n",fname);
2457 		free(buff);
2458 		close_master_conn(1);
2459 		return -1;
2460 	}
2461 	leng-=4;
2462 	if (leng==1) {
2463 		printf("%s: %s\n",fname,mfsstrerr(*rptr));
2464 		free(buff);
2465 		close_master_conn(1);
2466 		return -1;
2467 	} else if (leng!=2) {
2468 		printf("%s: master query: wrong answer (leng)\n",fname);
2469 		free(buff);
2470 		close_master_conn(1);
2471 		return -1;
2472 	}
2473 	close_master_conn(0);
2474 	nodeeattr = get8bit(&rptr) & eattr;
2475 	functioneattr = get8bit(&rptr) & eattr;
2476 	free(buff);
2477 	printf("%s:",fname);
2478 	printf(" nodeeattr:");
2479 	if (nodeeattr==0) {
2480 		printf("-");
2481 	} else {
2482 		// as for now there is only one eattr: noowner
2483 		if (nodeeattr&EATTR_NOOWNER) {
2484 			printf("noowner");
2485 		} else {
2486 			printf("?");
2487 		}
2488 	}
2489 	printf("; workingeattr:");
2490 	if (functioneattr==0) {
2491 		printf("-");
2492 	} else {
2493 		// as for now there is only one eattr: noowner
2494 		if (functioneattr&EATTR_NOOWNER) {
2495 			printf("noowner");
2496 		} else {
2497 			printf("?");
2498 		}
2499 	}
2500 	printf("\n");
2501 	return 0;
2502 }
2503 */
2504 
quota_control(const char * fname,uint8_t mode,uint8_t * qflags,uint32_t * graceperiod,uint32_t * sinodes,uint64_t * slength,uint64_t * ssize,uint64_t * srealsize,uint32_t * hinodes,uint64_t * hlength,uint64_t * hsize,uint64_t * hrealsize)2505 int quota_control(const char *fname,uint8_t mode,uint8_t *qflags,uint32_t *graceperiod,uint32_t *sinodes,uint64_t *slength,uint64_t *ssize,uint64_t *srealsize,uint32_t *hinodes,uint64_t *hlength,uint64_t *hsize,uint64_t *hrealsize) {
2506 	uint32_t inode;
2507 	uint32_t curinodes;
2508 	uint64_t curlength,cursize,currealsize;
2509 
2510 //	printf("set quota: %s (soft:%1X,i:%"PRIu32",l:%"PRIu64",w:%"PRIu64",r:%"PRIu64"),(hard:%1X,i:%"PRIu32",l:%"PRIu64",w:%"PRIu64",r:%"PRIu64")\n",fname,sflags,sinodes,slength,ssize,srealsize,hflags,hinodes,hlength,hsize,hrealsize);
2511 	if (mode==2) {
2512 		*qflags = 0;
2513 	}
2514 	if (master_prepare_conn(fname,&inode,NULL,NULL,0,(*qflags)?1:0)<0) {
2515 		return -1;
2516 	}
2517 	master_new_packet();
2518 	master_put32bit(inode);
2519 	master_put8bit(*qflags);
2520 	if (mode==0) {
2521 		if (master_get_version()>=VERSION2INT(3,0,9)) {
2522 			master_put32bit(*graceperiod);
2523 		}
2524 		master_put32bit(*sinodes);
2525 		master_put64bit(*slength);
2526 		master_put64bit(*ssize);
2527 		master_put64bit(*srealsize);
2528 		master_put32bit(*hinodes);
2529 		master_put64bit(*hlength);
2530 		master_put64bit(*hsize);
2531 		master_put64bit(*hrealsize);
2532 	}
2533 	if (master_send_and_receive(CLTOMA_FUSE_QUOTACONTROL,MATOCL_FUSE_QUOTACONTROL)<0) {
2534 		return -1;
2535 	}
2536 	if (master_get_leng()==1) {
2537 		printf("%s: %s\n",fname,mfsstrerr(master_get8bit()));
2538 		return -1;
2539 	} else if (master_get_leng()!=85 && master_get_leng()!=89) {
2540 		printf("%s: master query: wrong answer (leng)\n",fname);
2541 		master_error();
2542 		return -1;
2543 	}
2544 	*qflags = master_get8bit();
2545 	if (master_get_leng()==89) {
2546 		*graceperiod = master_get32bit();
2547 	} else {
2548 		*graceperiod = 0;
2549 	}
2550 	*sinodes = master_get32bit();
2551 	*slength = master_get64bit();
2552 	*ssize = master_get64bit();
2553 	*srealsize = master_get64bit();
2554 	*hinodes = master_get32bit();
2555 	*hlength = master_get64bit();
2556 	*hsize = master_get64bit();
2557 	*hrealsize = master_get64bit();
2558 	curinodes = master_get32bit();
2559 	curlength = master_get64bit();
2560 	cursize = master_get64bit();
2561 	currealsize = master_get64bit();
2562 	if ((*graceperiod)>0) {
2563 		printf("%s: (current values | soft quota | hard quota) ; soft quota grace period: %u seconds\n",fname,*graceperiod);
2564 	} else {
2565 		printf("%s: (current values | soft quota | hard quota) ; soft quota grace period: default\n",fname);
2566 	}
2567 	print_number(" inodes   | ",NULL,curinodes,0,0,1);
2568 	print_number(" | ",NULL,*sinodes,0,0,(*qflags)&QUOTA_FLAG_SINODES);
2569 	print_number(" | "," |\n",*hinodes,0,0,(*qflags)&QUOTA_FLAG_HINODES);
2570 	print_number(" length   | ",NULL,curlength,0,1,1);
2571 	print_number(" | ",NULL,*slength,0,1,(*qflags)&QUOTA_FLAG_SLENGTH);
2572 	print_number(" | "," |\n",*hlength,0,1,(*qflags)&QUOTA_FLAG_HLENGTH);
2573 	print_number(" size     | ",NULL,cursize,0,1,1);
2574 	print_number(" | ",NULL,*ssize,0,1,(*qflags)&QUOTA_FLAG_SSIZE);
2575 	print_number(" | "," |\n",*hsize,0,1,(*qflags)&QUOTA_FLAG_HSIZE);
2576 	print_number(" realsize | ",NULL,currealsize,0,1,1);
2577 	print_number(" | ",NULL,*srealsize,0,1,(*qflags)&QUOTA_FLAG_SREALSIZE);
2578 	print_number(" | "," |\n",*hrealsize,0,1,(*qflags)&QUOTA_FLAG_HREALSIZE);
2579 	if (master_end_packet()==0) {
2580 		printf("%s: master query: packet size error\n",fname);
2581 		return -1;
2582 	}
2583 	return 0;
2584 }
2585 
2586 /*
2587 int get_quota(const char *fname) {
2588 	printf("get quota: %s\n",fname);
2589 	return 0;
2590 }
2591 
2592 int delete_quota(const char *fname,uint8_t sflags,uint8_t hflags) {
2593 	printf("delete quota: %s (soft:%1X,hard:%1X)\n",fname,sflags,hflags);
2594 	return 0;
2595 }
2596 */
2597 
snapshot_ctl(const char * dstdir,const char * dstbase,const char * srcname,uint32_t srcinode,uint8_t smode)2598 int snapshot_ctl(const char *dstdir,const char *dstbase,const char *srcname,uint32_t srcinode,uint8_t smode) {
2599 	uint32_t dstinode,uid,gid;
2600 	gid_t grouplist[NGROUPS_MAX];
2601 	uint32_t i,gids;
2602 	uint8_t addmaingroup;
2603 	uint32_t nleng;
2604 	uint16_t umsk;
2605 	uint8_t status;
2606 
2607 	umsk = umask(0);
2608 	umask(umsk);
2609 	nleng = strlen(dstbase);
2610 	if (nleng>255) {
2611 		printf("%s: name too long\n",dstbase);
2612 		return -1;
2613 	}
2614 	if (master_prepare_conn(dstdir,&dstinode,NULL,NULL,0,1)<0) {
2615 		return -1;
2616 	}
2617 	uid = getuid();
2618 	gid = getgid();
2619 	if (master_get_version()>=VERSION2INT(2,0,0)) {
2620 		gids = getgroups(NGROUPS_MAX,grouplist);
2621 		addmaingroup = 1;
2622 		for (i=0 ; i<gids ; i++) {
2623 			if (grouplist[i]==gid) {
2624 				addmaingroup = 0;
2625 			}
2626 		}
2627 	} else {
2628 		gids = 0;
2629 		addmaingroup = 0;
2630 	}
2631 	master_new_packet();
2632 	master_put32bit(srcinode);
2633 	master_put32bit(dstinode);
2634 	master_putname(nleng,dstbase);
2635 	master_put32bit(uid);
2636 	if (master_get_version()<VERSION2INT(2,0,0)) {
2637 		master_put32bit(gid);
2638 	} else {
2639 		master_put32bit(addmaingroup+gids);
2640 		if (addmaingroup) {
2641 			master_put32bit(gid);
2642 		}
2643 		for (i=0 ; i<gids ; i++) {
2644 			master_put32bit(grouplist[i]);
2645 		}
2646 	}
2647 	master_put8bit(smode);
2648 	if (master_get_version()>=VERSION2INT(1,7,0)) {
2649 		master_put16bit(umsk);
2650 	}
2651 	if (master_send_and_receive(CLTOMA_FUSE_SNAPSHOT,MATOCL_FUSE_SNAPSHOT)<0) {
2652 		return -1;
2653 	}
2654 	if (master_get_leng()!=1) {
2655 		if (srcname==NULL) {
2656 			printf("%s/%s: master query: wrong answer (leng)\n",dstdir,dstbase);
2657 		} else {
2658 			printf("%s->%s/%s: master query: wrong answer (leng)\n",srcname,dstdir,dstbase);
2659 		}
2660 		return -1;
2661 	}
2662 	status = master_get8bit();
2663 	if (status!=0) {
2664 		if (srcname==NULL) {
2665 			printf("%s/%s: %s\n",dstdir,dstbase,mfsstrerr(status));
2666 		} else {
2667 			printf("%s->%s/%s: %s\n",srcname,dstdir,dstbase,mfsstrerr(status));
2668 		}
2669 		return -1;
2670 	}
2671 	if (master_end_packet()==0) {
2672 		if (srcname==NULL) {
2673 			printf("%s/%s: master query: packet size error\n",dstdir,dstbase);
2674 		} else {
2675 			printf("%s->%s/%s: master query: packet size error\n",srcname,dstdir,dstbase);
2676 		}
2677 		return -1;
2678 	}
2679 	return 0;
2680 }
2681 
remove_snapshot(const char * dstname,uint8_t smode)2682 int remove_snapshot(const char *dstname,uint8_t smode) {
2683 	char dstpath[PATH_MAX+1],base[PATH_MAX+1],dir[PATH_MAX+1];
2684 
2685 	if (realpath(dstname,dstpath)==NULL) {
2686 		printf("%s: realpath error on %s: %s\n",dstname,dstpath,strerr(errno));
2687 	}
2688 	memcpy(dir,dstpath,PATH_MAX+1);
2689 	dirname_inplace(dir);
2690 	if (bsd_basename(dstpath,base)<0) {
2691 		printf("%s: basename error\n",dstpath);
2692 		return -1;
2693 	}
2694 	return snapshot_ctl(dir,base,NULL,0,smode | SNAPSHOT_MODE_DELETE);
2695 }
2696 
make_snapshot(const char * dstname,char * const * srcnames,uint32_t srcelements,uint8_t smode)2697 int make_snapshot(const char *dstname,char * const *srcnames,uint32_t srcelements,uint8_t smode) {
2698 	char to[PATH_MAX+1],base[PATH_MAX+1],dir[PATH_MAX+1];
2699 	char src[PATH_MAX+1];
2700 	struct stat sst,dst;
2701 	int status;
2702 	uint32_t i,l;
2703 
2704 	if (stat(dstname,&dst)<0) {	// dst does not exist
2705 		if (errno!=ENOENT) {
2706 			printf("%s: stat error: %s\n",dstname,strerr(errno));
2707 			return -1;
2708 		}
2709 		if (srcelements>1) {
2710 			printf("can snapshot multiple elements only into existing directory\n");
2711 			return -1;
2712 		}
2713 		if (lstat(srcnames[0],&sst)<0) {
2714 			printf("%s: lstat error: %s\n",srcnames[0],strerr(errno));
2715 			return -1;
2716 		}
2717 		if (bsd_dirname(dstname,dir)<0) {
2718 			printf("%s: dirname error\n",dstname);
2719 			return -1;
2720 		}
2721 		if (stat(dir,&dst)<0) {
2722 			printf("%s: stat error: %s\n",dir,strerr(errno));
2723 			return -1;
2724 		}
2725 		if (sst.st_dev != dst.st_dev) {
2726 			printf("(%s,%s): both elements must be on the same device\n",dstname,srcnames[0]);
2727 			return -1;
2728 		}
2729 		if (realpath(dir,to)==NULL) {
2730 			printf("%s: realpath error on %s: %s\n",dir,to,strerr(errno));
2731 			return -1;
2732 		}
2733 		if (bsd_basename(dstname,base)<0) {
2734 			printf("%s: basename error\n",dstname);
2735 			return -1;
2736 		}
2737 		if (strlen(dstname)>0 && dstname[strlen(dstname)-1]=='/' && !S_ISDIR(sst.st_mode)) {
2738 			printf("directory %s does not exist\n",dstname);
2739 			return -1;
2740 		}
2741 		return snapshot_ctl(to,base,srcnames[0],sst.st_ino,smode);
2742 	} else {	// dst exists
2743 		if (realpath(dstname,to)==NULL) {
2744 			printf("%s: realpath error on %s: %s\n",dstname,to,strerr(errno));
2745 			return -1;
2746 		}
2747 		if (!S_ISDIR(dst.st_mode)) {	// dst id not a directory
2748 			if (srcelements>1) {
2749 				printf("can snapshot multiple elements only into existing directory\n");
2750 				return -1;
2751 			}
2752 			if (lstat(srcnames[0],&sst)<0) {
2753 				printf("%s: lstat error: %s\n",srcnames[0],strerr(errno));
2754 				return -1;
2755 			}
2756 			if (sst.st_dev != dst.st_dev) {
2757 				printf("(%s,%s): both elements must be on the same device\n",dstname,srcnames[0]);
2758 				return -1;
2759 			}
2760 			memcpy(dir,to,PATH_MAX+1);
2761 			dirname_inplace(dir);
2762 //			if (bsd_dirname(to,dir)<0) {
2763 //				printf("%s: dirname error\n",to);
2764 //				return -1;
2765 //			}
2766 			if (bsd_basename(to,base)<0) {
2767 				printf("%s: basename error\n",to);
2768 				return -1;
2769 			}
2770 			return snapshot_ctl(dir,base,srcnames[0],sst.st_ino,smode);
2771 		} else {	// dst is a directory
2772 			status = 0;
2773 			for (i=0 ; i<srcelements ; i++) {
2774 				if (lstat(srcnames[i],&sst)<0) {
2775 					printf("%s: lstat error: %s\n",srcnames[i],strerr(errno));
2776 					status=-1;
2777 					continue;
2778 				}
2779 				if (sst.st_dev != dst.st_dev) {
2780 					printf("(%s,%s): both elements must be on the same device\n",dstname,srcnames[i]);
2781 					status=-1;
2782 					continue;
2783 				}
2784 				if (!S_ISDIR(sst.st_mode)) {	// src is not a directory
2785 					if (!S_ISLNK(sst.st_mode)) {	// src is not a symbolic link
2786 						if (realpath(srcnames[i],src)==NULL) {
2787 							printf("%s: realpath error on %s: %s\n",srcnames[i],src,strerr(errno));
2788 							status=-1;
2789 							continue;
2790 						}
2791 						if (bsd_basename(src,base)<0) {
2792 							printf("%s: basename error\n",src);
2793 							status=-1;
2794 							continue;
2795 						}
2796 					} else {	// src is a symbolic link
2797 						if (bsd_basename(srcnames[i],base)<0) {
2798 							printf("%s: basename error\n",srcnames[i]);
2799 							status=-1;
2800 							continue;
2801 						}
2802 					}
2803 					if (snapshot_ctl(to,base,srcnames[i],sst.st_ino,smode)<0) {
2804 						status=-1;
2805 					}
2806 				} else {	// src is a directory
2807 					l = strlen(srcnames[i]);
2808 					if (l>0 && srcnames[i][l-1]!='/') {	// src is a directory and name has trailing slash
2809 						if (realpath(srcnames[i],src)==NULL) {
2810 							printf("%s: realpath error on %s: %s\n",srcnames[i],src,strerr(errno));
2811 							status=-1;
2812 							continue;
2813 						}
2814 						if (bsd_basename(src,base)<0) {
2815 							printf("%s: basename error\n",src);
2816 							status=-1;
2817 							continue;
2818 						}
2819 						if (snapshot_ctl(to,base,srcnames[i],sst.st_ino,smode)<0) {
2820 							status=-1;
2821 						}
2822 					} else {	// src is a directory and name has not trailing slash
2823 						memcpy(dir,to,PATH_MAX+1);
2824 						dirname_inplace(dir);
2825 						//if (bsd_dirname(to,dir)<0) {
2826 						//	printf("%s: dirname error\n",to);
2827 						//	status=-1;
2828 						//	continue;
2829 						//}
2830 						if (bsd_basename(to,base)<0) {
2831 							printf("%s: basename error\n",to);
2832 							status=-1;
2833 							continue;
2834 						}
2835 						if (snapshot_ctl(dir,base,srcnames[i],sst.st_ino,smode)<0) {
2836 							status=-1;
2837 						}
2838 					}
2839 				}
2840 			}
2841 			return status;
2842 		}
2843 	}
2844 }
2845 
2846 enum {
2847 	MFSGETGOAL=1,
2848 	MFSSETGOAL,
2849 	MFSCOPYGOAL,
2850 	MFSGETSCLASS,
2851 	MFSSETSCLASS,
2852 	MFSXCHGSCLASS,
2853 	MFSCOPYSCLASS,
2854 	MFSLISTSCLASS,
2855 	MFSGETTRASHTIME,
2856 	MFSSETTRASHTIME,
2857 	MFSCOPYTRASHTIME,
2858 	MFSCHECKFILE,
2859 	MFSFILEINFO,
2860 	MFSAPPENDCHUNKS,
2861 	MFSDIRINFO,
2862 	MFSFILEREPAIR,
2863 	MFSMAKESNAPSHOT,
2864 	MFSRMSNAPSHOT,
2865 	MFSGETEATTR,
2866 	MFSSETEATTR,
2867 	MFSDELEATTR,
2868 	MFSCOPYEATTR,
2869 	MFSGETQUOTA,
2870 	MFSSETQUOTA,
2871 	MFSDELQUOTA,
2872 	MFSCOPYQUOTA,
2873 	MFSFILEPATHS,
2874 	MFSCHKARCHIVE,
2875 	MFSSETARCHIVE,
2876 	MFSCLRARCHIVE,
2877 	MFSSCADMIN,
2878 	MFSMKSC,
2879 	MFSCHSC,
2880 	MFSRMSC,
2881 	MFSCPSC,
2882 	MFSMVSC,
2883 	MFSLSSC
2884 };
2885 
print_numberformat_options()2886 static inline void print_numberformat_options() {
2887 	fprintf(stderr," -n - show numbers in plain format\n");
2888 	fprintf(stderr," -h - \"human-readable\" numbers using base 2 prefixes (IEC 60027)\n");
2889 	fprintf(stderr," -H - \"human-readable\" numbers using base 10 prefixes (SI)\n");
2890 	fprintf(stderr," -k - show plain numbers in kibis (binary kilo - 1024)\n");
2891 	fprintf(stderr," -m - show plain numbers in mebis (binary mega - 1024^2)\n");
2892 	fprintf(stderr," -g - show plain numbers in gibis (binary giga - 1024^3)\n");
2893 }
2894 
print_recursive_option()2895 static inline void print_recursive_option() {
2896 	fprintf(stderr," -r - do it recursively\n");
2897 }
2898 
print_extra_attributes()2899 static inline void print_extra_attributes() {
2900 	int j;
2901 	fprintf(stderr,"\nattributes:\n");
2902 	for (j=0 ; j<EATTR_BITS ; j++) {
2903 		if (eattrtab[j][0]) {
2904 			fprintf(stderr," %s - %s\n",eattrtab[j],eattrdesc[j]);
2905 		}
2906 	}
2907 }
2908 
usage(int f)2909 void usage(int f) {
2910 	switch (f) {
2911 		case MFSGETGOAL:
2912 			fprintf(stderr,"get objects goal (desired number of copies)\n\nusage: mfsgetgoal [-nhHkmgr] name [name ...]\n");
2913 			print_numberformat_options();
2914 			print_recursive_option();
2915 			break;
2916 		case MFSSETGOAL:
2917 			fprintf(stderr,"set objects goal (desired number of copies)\n\nusage: mfssetgoal [-nhHkmgr] GOAL[-|+] name [name ...]\n");
2918 			print_numberformat_options();
2919 			print_recursive_option();
2920 			fprintf(stderr," GOAL+ - increase goal to given value\n");
2921 			fprintf(stderr," GOAL- - decrease goal to given value\n");
2922 			fprintf(stderr," GOAL - just set goal to given value\n");
2923 			break;
2924 		case MFSCOPYGOAL:
2925 			fprintf(stderr,"copy object goal (desired number of copies)\n\nusage: mfscopygoal [-nhHkmgr] srcname dstname [dstname ...]\n");
2926 			print_numberformat_options();
2927 			print_recursive_option();
2928 			break;
2929 		case MFSGETSCLASS:
2930 			fprintf(stderr,"get objects storage class (desired number of copies / labels)\n\nusage: mfsgetsclass [-nhHkmgr] name [name ...]\n");
2931 			print_numberformat_options();
2932 			print_recursive_option();
2933 			break;
2934 		case MFSSETSCLASS:
2935 			fprintf(stderr,"set objects storage class (desired number of copies / labels)\n\nusage: mfssetsclass [-nhHkmgr] STORAGE_CLASS_NAME name [name ...]\n");
2936 			print_numberformat_options();
2937 			print_recursive_option();
2938 			break;
2939 		case MFSCOPYSCLASS:
2940 			fprintf(stderr,"copy object storage class (desired number of copies / labels)\n\nusage: mfscopysclass [-nhHkmgr] srcname dstname [dstname ...]\n");
2941 			print_numberformat_options();
2942 			print_recursive_option();
2943 			break;
2944 		case MFSXCHGSCLASS:
2945 			fprintf(stderr,"exchange objects storage class (desired number of copies / labels)\n\nusage: mfsxchgsclass [-nhHkmgr] OLD_STORAGE_CLASS_NAME NEW_STORAGE_CLASS_NAME name [name ...]\n");
2946 			print_numberformat_options();
2947 			print_recursive_option();
2948 			break;
2949 		case MFSLISTSCLASS:
2950 			fprintf(stderr,"lists available storage classes (same as mfsscadmin list)\n\nusage: mfslistsclass [-al] [mountpoint_or_any_subfolder]\n");
2951 			fprintf(stderr," -a - lists all storage classes (including standard goal classes)\n");
2952 			fprintf(stderr," -l - lists storage classes with definitions (long format)\n");
2953 			fprintf(stderr,"If mountpoint_or_any_subfolder is not specified then current directory will be used\n");
2954 			break;
2955 		case MFSGETTRASHTIME:
2956 			fprintf(stderr,"get objects trashtime (how many seconds file should be left in trash)\n\nusage: mfsgettrashtime [-nhHkmgr] name [name ...]\n");
2957 			print_numberformat_options();
2958 			print_recursive_option();
2959 			break;
2960 		case MFSSETTRASHTIME:
2961 			fprintf(stderr,"set objects trashtime (how many seconds file should be left in trash)\n\nusage: mfssettrashtime [-nhHkmgr] SECONDS[-|+] name [name ...]\n");
2962 			print_numberformat_options();
2963 			print_recursive_option();
2964 			fprintf(stderr," SECONDS+ - increase trashtime to given value\n");
2965 			fprintf(stderr," SECONDS- - decrease trashtime to given value\n");
2966 			fprintf(stderr," SECONDS - just set trashtime to given value\n");
2967 			break;
2968 		case MFSCOPYTRASHTIME:
2969 			fprintf(stderr,"copy objects trashtime (how many seconds file should be left in trash)\n\nusage: mfscopytrashtime [-nhHkmgr] srcname dstname [dstname ...]\n");
2970 			print_numberformat_options();
2971 			print_recursive_option();
2972 			break;
2973 		case MFSCHECKFILE:
2974 			fprintf(stderr,"check files\n\nusage: mfscheckfile [-nhHkmg] name [name ...]\n");
2975 			break;
2976 		case MFSFILEINFO:
2977 			fprintf(stderr,"show files info (shows detailed info of each file chunk)\n\nusage: mfsfileinfo [-qcs] name [name ...]\n");
2978 			fprintf(stderr,"switches:\n");
2979 			fprintf(stderr," -q - quick info (show only number of valid copies)\n");
2980 			fprintf(stderr," -c - receive chunk checksums from chunkservers\n");
2981 			fprintf(stderr," -s - calculate file signature (using checksums)\n");
2982 			break;
2983 		case MFSAPPENDCHUNKS:
2984 			fprintf(stderr,"append file chunks to another file. If destination file doesn't exist then it's created as empty file and then chunks are appended\n\nusage: mfsappendchunks [-s slice_from:slice_to] dstfile name [name ...]\n");
2985 			break;
2986 		case MFSDIRINFO:
2987 			fprintf(stderr,"show directories stats\n\nusage: mfsdirinfo [-nhHkmg] [-idfclsr] [-p] name [name ...]\n");
2988 			print_numberformat_options();
2989 			fprintf(stderr,"'show' switches:\n");
2990 			fprintf(stderr," -i - show number of inodes\n");
2991 			fprintf(stderr," -d - show number of directories\n");
2992 			fprintf(stderr," -f - show number of files\n");
2993 			fprintf(stderr," -c - show number of chunks\n");
2994 			fprintf(stderr," -l - show length\n");
2995 			fprintf(stderr," -s - show size\n");
2996 			fprintf(stderr," -r - show realsize\n");
2997 			fprintf(stderr,"'mode' switch:\n");
2998 			fprintf(stderr," -p - precise mode\n");
2999 			fprintf(stderr,"\nIf no 'show' switches are present then show everything\n");
3000 			fprintf(stderr,"\nMeaning of some not obvious output data:\n 'length' is just sum of files lengths\n 'size' is sum of chunks lengths\n 'realsize' is estimated hdd usage (usually size multiplied by current goal)\n");
3001 			fprintf(stderr,"\nPrecise mode means that system takes into account repeated nodes/chunks\nand count them once, also uses current number of copies instead of goal.\n");
3002 			break;
3003 		case MFSFILEREPAIR:
3004 			fprintf(stderr,"repair given file. Use it with caution. It forces file to be readable, so it could erase (fill with zeros) file when chunkservers are not currently connected.\n\nusage: mfsfilerepair [-nhHkmg] name [name ...]\n");
3005 			print_numberformat_options();
3006 			break;
3007 		case MFSMAKESNAPSHOT:
3008 			fprintf(stderr,"make snapshot (lazy copy)\n\nusage: mfsmakesnapshot [-ocp] src [src ...] dst\n");
3009 			fprintf(stderr," -o - allow to overwrite existing objects\n");
3010 			fprintf(stderr," -c - 'cp' mode for attributes (create objects using current uid,gid,umask etc.)\n");
3011 			fprintf(stderr," -p - preserve hardlinks\n");
3012 			break;
3013 		case MFSRMSNAPSHOT:
3014 			fprintf(stderr,"remove snapshot (quick rm -r)\n\nusage: mfsrmsnapshot [-f] name [name ...]\n");
3015 			fprintf(stderr," -f - remove as much as possible (according to access rights and snapshot flags)\n");
3016 			break;
3017 		case MFSGETEATTR:
3018 			fprintf(stderr,"get objects extra attributes\n\nusage: mfsgeteattr [-nhHkmgr] name [name ...]\n");
3019 			print_numberformat_options();
3020 			print_recursive_option();
3021 			break;
3022 		case MFSSETEATTR:
3023 			fprintf(stderr,"set objects extra attributes\n\nusage: mfsseteattr [-nhHkmgr] -f attrname [-f attrname ...] name [name ...]\n");
3024 			print_numberformat_options();
3025 			print_recursive_option();
3026 			fprintf(stderr," -f attrname - specify attribute to set\n");
3027 			print_extra_attributes();
3028 			break;
3029 		case MFSDELEATTR:
3030 			fprintf(stderr,"delete objects extra attributes\n\nusage: mfsdeleattr [-nhHkmgr] -f attrname [-f attrname ...] name [name ...]\n");
3031 			print_numberformat_options();
3032 			print_recursive_option();
3033 			fprintf(stderr," -f attrname - specify attribute to delete\n");
3034 			print_extra_attributes();
3035 			break;
3036 		case MFSCOPYEATTR:
3037 			fprintf(stderr,"copy objects extra attributes\n\nusage: mfscopyeattr [-nhHkmgr] srcname dstname [dstname ...]\n");
3038 			print_numberformat_options();
3039 			print_recursive_option();
3040 			break;
3041 		case MFSGETQUOTA:
3042 			fprintf(stderr,"get quota for given directory (directories)\n\nusage: mfsgetquota [-nhHkmg] dirname [dirname ...]\n");
3043 			print_numberformat_options();
3044 			break;
3045 		case MFSSETQUOTA:
3046 			fprintf(stderr,"set quota for given directory (directories)\n\nusage: mfssetquota [-nhHkmg] [-iI inodes] [-p grace_period] [-lL length] [-sS size] [-rR realsize] dirname [dirname ...]\n");
3047 			print_numberformat_options();
3048 			fprintf(stderr," -p - set grace period in seconds for soft quota\n");
3049 			fprintf(stderr," -i/-I - set soft/hard limit for number of filesystem objects\n");
3050 			fprintf(stderr," -l/-L - set soft/hard limit for sum of files lengths\n");
3051 			fprintf(stderr," -s/-S - set soft/hard limit for sum of file sizes (chunk sizes)\n");
3052 			fprintf(stderr," -r/-R - set soft/hard limit for estimated hdd usage (usually size multiplied by goal)\n");
3053 			fprintf(stderr,"\nAll numbers can have decimal point and SI/IEC symbol prefix at the end\ndecimal (SI): (k - 10^3 , M - 10^6 , G - 10^9 , T - 10^12 , P - 10^15 , E - 10^18)\nbinary (IEC 60027): (Ki - 2^10 , Mi - 2^20 , Gi - 2^30 , Ti - 2^40 , Pi - 2^50 , Ei - 2^60 )\n");
3054 			break;
3055 		case MFSDELQUOTA:
3056 			fprintf(stderr,"delete quota for given directory (directories)\n\nusage: mfsdelquota [-nhHkmgailsrAILSR] dirname [dirname ...]\n");
3057 			print_numberformat_options();
3058 			fprintf(stderr," -i/-I - delete inodes soft/hard quota\n");
3059 			fprintf(stderr," -l/-L - delete length soft/hard quota\n");
3060 			fprintf(stderr," -s/-S - delete size soft/hard quota\n");
3061 			fprintf(stderr," -r/-R - delete real size soft/hard quota\n");
3062 			fprintf(stderr," -a/-A - delete all soft/hard quotas\n");
3063 			break;
3064 		case MFSCOPYQUOTA:
3065 			fprintf(stderr,"copy quota settings from one directory to another directory (directories)\n\nusage: mfscopyquota [-nhHkmg] srcdirname dstdirname [dstdirname ...]\n");
3066 			print_numberformat_options();
3067 			break;
3068 		case MFSFILEPATHS:
3069 			fprintf(stderr,"show all paths of given files or node numbers\n\nusage: mfsfilepaths name/inode [name/inode ...]\n");
3070 			fprintf(stderr,"\nIn case of converting node to path, tool has to be run in mfs-mounted directory\n");
3071 			break;
3072 		case MFSCHKARCHIVE:
3073 			fprintf(stderr,"checks if archive flag is set or not (when directory is specified then command will check it recursivelly)\n\nusage: mfschgarchive [-nhHkmg] name [name ...]\n");
3074 			print_numberformat_options();
3075 			break;
3076 		case MFSSETARCHIVE:
3077 			fprintf(stderr,"set archive flags in chunks (recursivelly for directories) - moves files to archive (use 'archive' goal/labels instead of 'keep' goal/labels)\n\nusage: mfssetarchive [-nhHkmg] name [name ...]\n");
3078 			print_numberformat_options();
3079 			break;
3080 		case MFSCLRARCHIVE:
3081 			fprintf(stderr,"clear archive flags in chunks (recursivelly for directories) - moves files from archive (use 'keep' goal/labels instead of 'archive' goal/labels) - it also changes ctime, so files will move back to archive after time specified in mfssetgoal\n\nusage: mfsclrarchive [-nhHkmg] name [name ...]\n");
3082 			print_numberformat_options();
3083 			break;
3084 		case MFSSCADMIN:
3085 		case MFSMKSC:
3086 		case MFSCHSC:
3087 		case MFSRMSC:
3088 		case MFSCPSC:
3089 		case MFSMVSC:
3090 		case MFSLSSC:
3091 			fprintf(stderr,"mfs storage class admin tool\n\nusage:\n");
3092 			fprintf(stderr,"\tmfsscadmin [/mountpoint] create|make [-a admin_only] [-m mode] [-C create_labels] -K keep_labels [-A archive_labels -d archive_delay] sclass [sclass ...]\n");
3093 			fprintf(stderr,"\tmfsscadmin [/mountpoint] create|make [-a admin_only] [-m mode] LABELS sclass [sclass ...]\n");
3094 			fprintf(stderr,"\tmfsscadmin [/mountpoint] modify|change [-f] [-a admin_only] [-m mode] [-C create_labels] [-K keep_labels] [-A archive_labels] [-d archive_delay] sclass [sclass ...]\n");
3095 			fprintf(stderr,"\tmfsscadmin [/mountpoint] delete|remove sclass [sclass ...]\n");
3096 			fprintf(stderr,"\tmfsscadmin [/mountpoint] copy|duplicate src_sclass dst_sclass [dst_sclass ...]\n");
3097 			fprintf(stderr,"\tmfsscadmin [/mountpoint] rename src_sclass_name dst_sclass_name\n");
3098 			fprintf(stderr,"\tmfsscadmin [/mountpoint] list [-l]\n");
3099 			fprintf(stderr,"\n");
3100 			fprintf(stderr,"create/modify options:\n");
3101 			fprintf(stderr," -m - set mode (options are: 'l' for 'loose', 's' for 'strict' and 'd' or not specified for 'default')\n");
3102 			fprintf(stderr,"    'default' mode: if there are overloaded servers, system will wait for them, but in case of no space available will use other servers (disregarding the labels).\n");
3103 			fprintf(stderr,"    'strict' mode: the system will wait for overloaded servers, but when there is no space on servers with correct labels then will not use them (return ENOSPC or leave chunk as undergoal).\n");
3104 			fprintf(stderr,"    'loose' mode: the system will disregard the labels in both cases.\n");
3105 			fprintf(stderr," -a - set admin only mode ( 0 - anybody can use this storage class, 1 - only admin can use this storage class ) - by default it set to 0\n");
3106 			fprintf(stderr," -C - set labels used for creation chunks - when not specified then 'keep' labels are used\n");
3107 			fprintf(stderr," -K - set labels used for keeping chunks - must be specified\n");
3108 			fprintf(stderr," -A - set labels used for archiving chunks - when not specified then 'keep' labels are used\n");
3109 			fprintf(stderr," -d - set number of days used to switch labels from 'keep' to 'archive' - must be specified when '-A' option is given\n");
3110 			fprintf(stderr," -f - force modification of classes 1 to 9 (modify only)\n");
3111 			fprintf(stderr,"\n");
3112 			fprintf(stderr,"list options:\n");
3113 			fprintf(stderr," -l - lists storage classes with definitions (long format)\n");
3114 			fprintf(stderr,"\n");
3115 			fprintf(stderr,"If '/mountpoint' parameter is not specified then current directory is used (it might be any subfolder of mountpoint).\n");
3116 			fprintf(stderr,"All actions but list need 'admin' flag specified in mfsexports.cfg\n");
3117 			break;
3118 	}
3119 	exit(1);
3120 }
3121 
main(int argc,char ** argv)3122 int main(int argc,char **argv) {
3123 	int l,f,status;
3124 	int i,j,found;
3125 	int ch;
3126 	int longmode = 0;
3127 	int snapmode = 0;
3128 	int rflag = 0;
3129 	uint8_t dirinfomode = 0;
3130 	uint8_t fileinfomode = 0;
3131 	uint64_t v;
3132 	uint8_t eattr = 0,goal = 1,smode = SMODE_SET;
3133 	storage_class sc;
3134 	uint16_t chgmask = 0;
3135 	uint32_t trashtime = 86400;
3136 	uint32_t sinodes = 0,hinodes = 0;
3137 	uint64_t slength = 0,hlength = 0,ssize = 0,hsize = 0,srealsize = 0,hrealsize = 0;
3138 	uint32_t graceperiod = 0;
3139 	uint8_t qflags = 0;
3140 	uint32_t scnleng;
3141 	int64_t slice_from = 0,slice_to = 0x80000000;
3142 	char *scadmin_mp = NULL;
3143 	char *appendfname = NULL;
3144 	char *srcname = NULL;
3145 	char *hrformat;
3146 	char storage_class_name[256];
3147 	char src_storage_class_name[256];
3148 	char *p;
3149 
3150 	memset(&sc,0,sizeof(sc));
3151 	sc.mode = SCLASS_MODE_STD;
3152 	strerr_init();
3153 	master_init();
3154 
3155 	l = strlen(argv[0]);
3156 #define CHECKNAME(name) ((strcmp(argv[0],name)==0) || (l>(int)(sizeof(name)-1) && strcmp((argv[0])+(l-sizeof(name)),"/" name)==0))
3157 
3158 	if (CHECKNAME("mfstools")) {
3159 		if (argc==2 && strcmp(argv[1],"create")==0) {
3160 			fprintf(stderr,"create symlinks\n");
3161 #define SYMLINK(name)	if (symlink(argv[0],name)<0) { \
3162 				perror("error creating symlink '"name"'"); \
3163 			}
3164 			SYMLINK("mfsgetgoal")
3165 			SYMLINK("mfssetgoal")
3166 			SYMLINK("mfscopygoal")
3167 			SYMLINK("mfsgetsclass")
3168 			SYMLINK("mfssetsclass")
3169 			SYMLINK("mfscopysclass")
3170 			SYMLINK("mfsxchgsclass")
3171 			SYMLINK("mfslistsclass")
3172 			SYMLINK("mfsgettrashtime")
3173 			SYMLINK("mfssettrashtime")
3174 			SYMLINK("mfscopytrashtime")
3175 			SYMLINK("mfscheckfile")
3176 			SYMLINK("mfsfileinfo")
3177 			SYMLINK("mfsappendchunks")
3178 			SYMLINK("mfsdirinfo")
3179 			SYMLINK("mfsfilerepair")
3180 			SYMLINK("mfsmakesnapshot")
3181 			SYMLINK("mfsrmsnapshot")
3182 			SYMLINK("mfsgeteattr")
3183 			SYMLINK("mfsseteattr")
3184 			SYMLINK("mfsdeleattr")
3185 			SYMLINK("mfscopyeattr")
3186 			SYMLINK("mfsgetquota")
3187 			SYMLINK("mfssetquota")
3188 			SYMLINK("mfsdelquota")
3189 			SYMLINK("mfscopyquota")
3190 			SYMLINK("mfsfilepaths")
3191 			SYMLINK("mfschkarchive")
3192 			SYMLINK("mfssetarchive")
3193 			SYMLINK("mfsclrarchive")
3194 			SYMLINK("mfsscadmin")
3195 			// deprecated tools:
3196 			SYMLINK("mfsrgetgoal")
3197 			SYMLINK("mfsrsetgoal")
3198 			SYMLINK("mfsrgettrashtime")
3199 			SYMLINK("mfsrsettrashtime")
3200 			return 0;
3201 		} else if (argc==1) {
3202 			fprintf(stderr,"mfs multi tool\n\nusage:\n\tmfstools create - create symlinks (mfs<toolname> -> %s)\n",argv[0]);
3203 			fprintf(stderr,"\tmfstools mfs<toolname> ... - work as a given tool\n");
3204 			fprintf(stderr,"\ntools:\n");
3205 			fprintf(stderr,"\tmfsgetgoal\n\tmfssetgoal\n\tmfscopygoal\n");
3206 			fprintf(stderr,"\tmfsgetsclass\n\tmfssetsclass\n\tmfscopysclass\n\tmfsxchgsclass\n\tmfslistsclass\n");
3207 			fprintf(stderr,"\tmfsgettrashtime\n\tmfssettrashtime\n\tmfscopytrashtime\n");
3208 			fprintf(stderr,"\tmfsgeteattr\n\tmfsseteattr\n\tmfsdeleattr\n\tmfscopyeattr\n");
3209 			fprintf(stderr,"\tmfsgetquota\n\tmfssetquota\n\tmfsdelquota\n\tmfscopyquota\n");
3210 			fprintf(stderr,"\tmfscheckfile\n\tmfsfileinfo\n\tmfsappendchunks\n\tmfsdirinfo\n");
3211 			fprintf(stderr,"\tmfsfilerepair\n\tmfsmakesnapshot\n\tmfsfilepaths\n");
3212 			fprintf(stderr,"\tmfschkarchive\n\tmfssetarchive\n\tmfsclrarchive\n");
3213 			fprintf(stderr,"\tmfsscadmin\n");
3214 			return 1;
3215 		}
3216 		argv++;
3217 		argc--;
3218 		l = 0;
3219 	}
3220 	if (CHECKNAME("mfsscadmin")) {
3221 		f = MFSSCADMIN;
3222 		if (argc<=1) {
3223 			usage(MFSSCADMIN);
3224 		} else {
3225 			argv++;
3226 			argc--;
3227 			l = 0;
3228 			if (*argv[0]=='/') {
3229 				scadmin_mp = *argv;
3230 				argv++;
3231 				argc--;
3232 				if (argc==0) {
3233 					fprintf(stderr,"missing command after mountpoint\n\n");
3234 					usage(MFSSCADMIN);
3235 				}
3236 			}
3237 			if (CHECKNAME("create")) {
3238 				f = MFSMKSC;
3239 			} else if (CHECKNAME("make")) {
3240 				f = MFSMKSC;
3241 			} else if (CHECKNAME("modify")) {
3242 				f = MFSCHSC;
3243 			} else if (CHECKNAME("change")) {
3244 				f = MFSCHSC;
3245 			} else if (CHECKNAME("delete")) {
3246 				f = MFSRMSC;
3247 			} else if (CHECKNAME("remove")) {
3248 				f = MFSRMSC;
3249 			} else if (CHECKNAME("copy")) {
3250 				f = MFSCPSC;
3251 			} else if (CHECKNAME("duplicate")) {
3252 				f = MFSCPSC;
3253 			} else if (CHECKNAME("rename")) {
3254 				f = MFSMVSC;
3255 			} else if (CHECKNAME("list")) {
3256 				f = MFSLSSC;
3257 			} else {
3258 				fprintf(stderr,"unknown storage class admin command\n\n");
3259 				usage(MFSSCADMIN);
3260 			}
3261 		}
3262 	} else if (CHECKNAME("mfsgetgoal")) {
3263 		f=MFSGETGOAL;
3264 	} else if (CHECKNAME("mfsrgetgoal")) {
3265 		f=MFSGETGOAL;
3266 		rflag=1;
3267 		fprintf(stderr,"deprecated tool - use \"mfsgetgoal -r\"\n");
3268 	} else if (CHECKNAME("mfssetgoal")) {
3269 		f=MFSSETGOAL;
3270 	} else if (CHECKNAME("mfsrsetgoal")) {
3271 		f=MFSSETGOAL;
3272 		rflag=1;
3273 		fprintf(stderr,"deprecated tool - use \"mfssetgoal -r\"\n");
3274 	} else if (CHECKNAME("mfscopygoal")) {
3275 		f=MFSCOPYGOAL;
3276 	} else if (CHECKNAME("mfsgetsclass")) {
3277 		f=MFSGETSCLASS;
3278 	} else if (CHECKNAME("mfssetsclass")) {
3279 		f=MFSSETSCLASS;
3280 	} else if (CHECKNAME("mfsxchgsclass")) {
3281 		f=MFSXCHGSCLASS;
3282 	} else if (CHECKNAME("mfscopysclass")) {
3283 		f=MFSCOPYSCLASS;
3284 	} else if (CHECKNAME("mfslistsclass")) {
3285 		f=MFSLISTSCLASS;
3286 	} else if (CHECKNAME("mfsgettrashtime")) {
3287 		f=MFSGETTRASHTIME;
3288 	} else if (CHECKNAME("mfsrgettrashtime")) {
3289 		f=MFSGETTRASHTIME;
3290 		rflag=1;
3291 		fprintf(stderr,"deprecated tool - use \"mfsgettrashtime -r\"\n");
3292 	} else if (CHECKNAME("mfssettrashtime")) {
3293 		f=MFSSETTRASHTIME;
3294 	} else if (CHECKNAME("mfsrsettrashtime")) {
3295 		f=MFSSETTRASHTIME;
3296 		rflag=1;
3297 		fprintf(stderr,"deprecated tool - use \"mfssettrashtime -r\"\n");
3298 	} else if (CHECKNAME("mfscopytrashtime")) {
3299 		f=MFSCOPYTRASHTIME;
3300 	} else if (CHECKNAME("mfscheckfile")) {
3301 		f=MFSCHECKFILE;
3302 	} else if (CHECKNAME("mfsfileinfo")) {
3303 		f=MFSFILEINFO;
3304 	} else if (CHECKNAME("mfsappendchunks")) {
3305 		f=MFSAPPENDCHUNKS;
3306 	} else if (CHECKNAME("mfsdirinfo")) {
3307 		f=MFSDIRINFO;
3308 	} else if (CHECKNAME("mfsgeteattr")) {
3309 		f=MFSGETEATTR;
3310 	} else if (CHECKNAME("mfsseteattr")) {
3311 		f=MFSSETEATTR;
3312 	} else if (CHECKNAME("mfsdeleattr")) {
3313 		f=MFSDELEATTR;
3314 	} else if (CHECKNAME("mfscopyeattr")) {
3315 		f=MFSCOPYEATTR;
3316 	} else if (CHECKNAME("mfsgetquota")) {
3317 		f=MFSGETQUOTA;
3318 	} else if (CHECKNAME("mfssetquota")) {
3319 		f=MFSSETQUOTA;
3320 	} else if (CHECKNAME("mfsdelquota")) {
3321 		f=MFSDELQUOTA;
3322 	} else if (CHECKNAME("mfscopyquota")) {
3323 		f=MFSCOPYQUOTA;
3324 	} else if (CHECKNAME("mfsfilerepair")) {
3325 		f=MFSFILEREPAIR;
3326 	} else if (CHECKNAME("mfsmakesnapshot")) {
3327 		f=MFSMAKESNAPSHOT;
3328 	} else if (CHECKNAME("mfsrmsnapshot")) {
3329 		f=MFSRMSNAPSHOT;
3330 	} else if (CHECKNAME("mfsfilepaths")) {
3331 		f=MFSFILEPATHS;
3332 	} else if (CHECKNAME("mfschkarchive")) {
3333 		f=MFSCHKARCHIVE;
3334 	} else if (CHECKNAME("mfssetarchive")) {
3335 		f=MFSSETARCHIVE;
3336 	} else if (CHECKNAME("mfsclrarchive")) {
3337 		f=MFSCLRARCHIVE;
3338 	} else if (CHECKNAME("mfsmksc")) {
3339 		f=MFSMKSC;
3340 	} else if (CHECKNAME("mfschsc")) {
3341 		f=MFSCHSC;
3342 	} else if (CHECKNAME("mfsrmsc")) {
3343 		f=MFSRMSC;
3344 	} else if (CHECKNAME("mfscpsc")) {
3345 		f=MFSCPSC;
3346 	} else if (CHECKNAME("mfsmvsc")) {
3347 		f=MFSMVSC;
3348 	} else if (CHECKNAME("mfslssc")) {
3349 		f=MFSLSSC;
3350 	} else {
3351 		fprintf(stderr,"unknown binary name\n");
3352 		return 1;
3353 	}
3354 //	argc--;
3355 //	argv++;
3356 
3357 	hrformat = getenv("MFSHRFORMAT");
3358 	if (hrformat) {
3359 		if (hrformat[0]>='0' && hrformat[0]<='4') {
3360 			humode=hrformat[0]-'0';
3361 		}
3362 		if (hrformat[0]=='h') {
3363 			if (hrformat[1]=='+') {
3364 				humode=3;
3365 			} else {
3366 				humode=1;
3367 			}
3368 		}
3369 		if (hrformat[0]=='H') {
3370 			if (hrformat[1]=='+') {
3371 				humode=4;
3372 			} else {
3373 				humode=2;
3374 			}
3375 		}
3376 	}
3377 
3378 	// parse options
3379 	switch (f) {
3380 	case MFSMAKESNAPSHOT:
3381 		while ((ch=getopt(argc,argv,"ocp"))!=-1) {
3382 			switch(ch) {
3383 			case 'o':
3384 				snapmode |= SNAPSHOT_MODE_CAN_OVERWRITE;
3385 				break;
3386 			case 'c':
3387 				snapmode |= SNAPSHOT_MODE_CPLIKE_ATTR;
3388 				break;
3389 			case 'p':
3390 				snapmode |= SNAPSHOT_MODE_PRESERVE_HARDLINKS;
3391 				break;
3392 			default:
3393 				usage(f);
3394 			}
3395 		}
3396 		argc -= optind;
3397 		argv += optind;
3398 		if (argc<2) {
3399 			usage(f);
3400 		}
3401 		return make_snapshot(argv[argc-1],argv,argc-1,snapmode);
3402 	case MFSRMSNAPSHOT:
3403 		while ((ch=getopt(argc,argv,"f"))!=-1) {
3404 			switch (ch) {
3405 			case 'f':
3406 				snapmode |= SNAPSHOT_MODE_FORCE_REMOVAL;
3407 				break;
3408 			default:
3409 				usage(f);
3410 			}
3411 		}
3412 		argc -= optind;
3413 		argv += optind;
3414 		break;
3415 	case MFSCOPYGOAL:
3416 	case MFSCOPYSCLASS:
3417 	case MFSCOPYTRASHTIME:
3418 	case MFSCOPYEATTR:
3419 		while ((ch=getopt(argc,argv,"rnhHkmg"))!=-1) {
3420 			switch(ch) {
3421 			case 'n':
3422 				humode=0;
3423 				break;
3424 			case 'h':
3425 				humode=1;
3426 				break;
3427 			case 'H':
3428 				humode=2;
3429 				break;
3430 			case 'k':
3431 				numbermode=1;
3432 				break;
3433 			case 'm':
3434 				numbermode=2;
3435 				break;
3436 			case 'g':
3437 				numbermode=3;
3438 				break;
3439 			case 'r':
3440 				rflag=1;
3441 				break;
3442 			default:
3443 				usage(f);
3444 			}
3445 		}
3446 		argc -= optind;
3447 		argv += optind;
3448 		if (argc<2) {
3449 			usage(f);
3450 		}
3451 		srcname = *argv;
3452 		argc--;
3453 		argv++;
3454 		break;
3455 	case MFSCOPYQUOTA:
3456 		while ((ch=getopt(argc,argv,"nhHkmg"))!=-1) {
3457 			switch(ch) {
3458 			case 'n':
3459 				humode=0;
3460 				break;
3461 			case 'h':
3462 				humode=1;
3463 				break;
3464 			case 'H':
3465 				humode=2;
3466 				break;
3467 			case 'k':
3468 				numbermode=1;
3469 				break;
3470 			case 'm':
3471 				numbermode=2;
3472 				break;
3473 			case 'g':
3474 				numbermode=3;
3475 				break;
3476 			default:
3477 				usage(f);
3478 			}
3479 		}
3480 		argc -= optind;
3481 		argv += optind;
3482 		if (argc<2) {
3483 			usage(f);
3484 		}
3485 		srcname = *argv;
3486 		argc--;
3487 		argv++;
3488 		break;
3489 	case MFSSETGOAL:
3490 	case MFSSETSCLASS:
3491 	case MFSXCHGSCLASS:
3492 		while ((ch=getopt(argc,argv,"rnhHkmg"))!=-1) {
3493 			switch(ch) {
3494 			case 'n':
3495 				humode=0;
3496 				break;
3497 			case 'h':
3498 				humode=1;
3499 				break;
3500 			case 'H':
3501 				humode=2;
3502 				break;
3503 			case 'k':
3504 				numbermode=1;
3505 				break;
3506 			case 'm':
3507 				numbermode=2;
3508 				break;
3509 			case 'g':
3510 				numbermode=3;
3511 				break;
3512 			case 'r':
3513 				rflag=1;
3514 				break;
3515 			default:
3516 				usage(f);
3517 			}
3518 		}
3519 		argc -= optind;
3520 		argv += optind;
3521 		if (argc==0) {
3522 			usage(f);
3523 		}
3524 		if (f==MFSSETGOAL) {
3525 			p = argv[0];
3526 			// [1-9] | [1-9]+ | [1-9]-
3527 			if (p[0]>'0' && p[0]<='9' && (p[1]=='\0' || ((p[1]=='-' || p[1]=='+') && p[2]=='\0'))) {
3528 				goal = p[0]-'0';
3529 				srcname = NULL;
3530 				if (p[1]=='-') {
3531 					smode = SMODE_DECREASE;
3532 				} else if (p[1]=='+') {
3533 					smode = SMODE_INCREASE;
3534 				} else {
3535 					smode = SMODE_SET;
3536 				}
3537 			} else {
3538 				printf("%s: wrong goal definition\n",p);
3539 				usage(f);
3540 			}
3541 		} else {
3542 			goal = 0xFF;
3543 			smode = SMODE_SET;
3544 			if (f==MFSXCHGSCLASS) {
3545 				p = argv[0];
3546 				scnleng = strlen(p);
3547 				if (scnleng>=256) {
3548 					printf("%s: storage class name too long\n",p);
3549 					usage(f);
3550 				}
3551 				memcpy(src_storage_class_name,p,scnleng);
3552 				src_storage_class_name[scnleng]=0;
3553 				argc--;
3554 				argv++;
3555 				smode |= SMODE_EXCHANGE;
3556 			}
3557 			p = argv[0];
3558 			scnleng = strlen(p);
3559 			if (scnleng>=256) {
3560 				printf("%s: storage class name too long\n",p);
3561 				usage(f);
3562 			}
3563 			memcpy(storage_class_name,p,scnleng);
3564 			storage_class_name[scnleng]=0;
3565 		}
3566 		argc--;
3567 		argv++;
3568 		break;
3569 	case MFSGETGOAL:
3570 	case MFSGETSCLASS:
3571 	case MFSGETTRASHTIME:
3572 	case MFSSETTRASHTIME:
3573 	case MFSGETEATTR:
3574 		while ((ch=getopt(argc,argv,"rnhHkmg"))!=-1) {
3575 			switch(ch) {
3576 			case 'n':
3577 				humode=0;
3578 				break;
3579 			case 'h':
3580 				humode=1;
3581 				break;
3582 			case 'H':
3583 				humode=2;
3584 				break;
3585 			case 'k':
3586 				numbermode=1;
3587 				break;
3588 			case 'm':
3589 				numbermode=2;
3590 				break;
3591 			case 'g':
3592 				numbermode=3;
3593 				break;
3594 			case 'r':
3595 				rflag=1;
3596 				break;
3597 			default:
3598 				usage(f);
3599 			}
3600 		}
3601 		argc -= optind;
3602 		argv += optind;
3603 		if (f==MFSSETTRASHTIME) {
3604 			p = argv[0];
3605 			if (argc==0) {
3606 				usage(f);
3607 			}
3608 			if (p[0]>='0' && p[0]<='9') {
3609 				trashtime = parse_period(p,&p);
3610 			}
3611 			while (p[0]==' ') {
3612 				p++;
3613 			}
3614 			if (p[0]=='\0' || ((p[0]=='-' || p[0]=='+') && p[1]=='\0')) {
3615 				if (p[0]=='-') {
3616 					smode=SMODE_DECREASE;
3617 				} else if (p[0]=='+') {
3618 					smode=SMODE_INCREASE;
3619 				}
3620 			} else {
3621 				fprintf(stderr,"trashtime should be given as number of seconds optionally folowed by '-' or '+'\n");
3622 				usage(f);
3623 			}
3624 			argc--;
3625 			argv++;
3626 		}
3627 		break;
3628 	case MFSSETEATTR:
3629 	case MFSDELEATTR:
3630 		while ((ch=getopt(argc,argv,"rnhHkmgf:"))!=-1) {
3631 			switch(ch) {
3632 			case 'n':
3633 				humode=0;
3634 				break;
3635 			case 'h':
3636 				humode=1;
3637 				break;
3638 			case 'H':
3639 				humode=2;
3640 				break;
3641 			case 'k':
3642 				numbermode=1;
3643 				break;
3644 			case 'm':
3645 				numbermode=2;
3646 				break;
3647 			case 'g':
3648 				numbermode=3;
3649 				break;
3650 			case 'r':
3651 				rflag=1;
3652 				break;
3653 			case 'f':
3654 				found=0;
3655 				for (i=0 ; found==0 && i<EATTR_BITS ; i++) {
3656 					if (strcmp(optarg,eattrtab[i])==0) {
3657 						found=1;
3658 						eattr|=1<<i;
3659 					}
3660 				}
3661 				if (!found) {
3662 					fprintf(stderr,"unknown flag\n");
3663 					usage(f);
3664 				}
3665 				break;
3666 			default:
3667 				usage(f);
3668 			}
3669 		}
3670 		argc -= optind;
3671 		argv += optind;
3672 		if (eattr==0 && argc>=1) {
3673 			if (f==MFSSETEATTR) {
3674 				fprintf(stderr,"no attribute(s) to set\n");
3675 			} else {
3676 				fprintf(stderr,"no attribute(s) to delete\n");
3677 			}
3678 			usage(f);
3679 		}
3680 		if (f==MFSSETEATTR) {
3681 			smode = SMODE_INCREASE;
3682 		} else {
3683 			smode = SMODE_DECREASE;
3684 		}
3685 		break;
3686 	case MFSFILEREPAIR:
3687 	case MFSGETQUOTA:
3688 	case MFSCHECKFILE:
3689 	case MFSCHKARCHIVE:
3690 	case MFSSETARCHIVE:
3691 	case MFSCLRARCHIVE:
3692 		while ((ch=getopt(argc,argv,"nhHkmg"))!=-1) {
3693 			switch(ch) {
3694 			case 'n':
3695 				humode=0;
3696 				break;
3697 			case 'h':
3698 				humode=1;
3699 				break;
3700 			case 'H':
3701 				humode=2;
3702 				break;
3703 			case 'k':
3704 				numbermode=1;
3705 				break;
3706 			case 'm':
3707 				numbermode=2;
3708 				break;
3709 			case 'g':
3710 				numbermode=3;
3711 				break;
3712 			default:
3713 				usage(f);
3714 			}
3715 		}
3716 		argc -= optind;
3717 		argv += optind;
3718 		break;
3719 	case MFSFILEINFO:
3720 		humode = 0;
3721 		numbermode = 0;
3722 		while ((ch=getopt(argc,argv,"qcs"))!=-1) {
3723 			switch(ch) {
3724 			case 'q':
3725 				fileinfomode |= FILEINFO_QUICK;
3726 				break;
3727 			case 'c':
3728 				fileinfomode |= FILEINFO_CRC;
3729 				break;
3730 			case 's':
3731 				fileinfomode |= FILEINFO_SIGNATURE;
3732 				break;
3733 			default:
3734 				usage(f);
3735 			}
3736 		}
3737 		argc -= optind;
3738 		argv += optind;
3739 		break;
3740 	case MFSDIRINFO:
3741 		while ((ch=getopt(argc,argv,"nhHkmgidfclsrp"))!=-1) {
3742 			switch(ch) {
3743 			case 'n':
3744 				humode=0;
3745 				break;
3746 			case 'h':
3747 				humode=1;
3748 				break;
3749 			case 'H':
3750 				humode=2;
3751 				break;
3752 			case 'k':
3753 				numbermode=1;
3754 				break;
3755 			case 'm':
3756 				numbermode=2;
3757 				break;
3758 			case 'g':
3759 				numbermode=3;
3760 				break;
3761 			case 'i':
3762 				dirinfomode |= DIRINFO_INODES;
3763 				break;
3764 			case 'd':
3765 				dirinfomode |= DIRINFO_DIRS;
3766 				break;
3767 			case 'f':
3768 				dirinfomode |= DIRINFO_FILES;
3769 				break;
3770 			case 'c':
3771 				dirinfomode |= DIRINFO_CHUNKS;
3772 				break;
3773 			case 'l':
3774 				dirinfomode |= DIRINFO_LENGTH;
3775 				break;
3776 			case 's':
3777 				dirinfomode |= DIRINFO_SIZE;
3778 				break;
3779 			case 'r':
3780 				dirinfomode |= DIRINFO_REALSIZE;
3781 				break;
3782 			case 'p':
3783 				dirinfomode |= DIRINFO_PRECISE;
3784 				break;
3785 			default:
3786 				usage(f);
3787 			}
3788 		}
3789 		argc -= optind;
3790 		argv += optind;
3791 		break;
3792 	case MFSSETQUOTA:
3793 		if (getuid()) {
3794 			fprintf(stderr,"only root can change quota\n");
3795 			usage(f);
3796 		}
3797 		while ((ch=getopt(argc,argv,"nhHkmgp:i:I:l:L:s:S:r:R:"))!=-1) {
3798 			switch(ch) {
3799 			case 'n':
3800 				humode=0;
3801 				break;
3802 			case 'h':
3803 				humode=1;
3804 				break;
3805 			case 'H':
3806 				humode=2;
3807 				break;
3808 			case 'k':
3809 				numbermode=1;
3810 				break;
3811 			case 'm':
3812 				numbermode=2;
3813 				break;
3814 			case 'g':
3815 				numbermode=3;
3816 				break;
3817 			case 'p':
3818 				graceperiod = parse_period(optarg,&p);
3819 				if (p[0]!='\0') {
3820 					fprintf(stderr,"bad grace period\n");
3821 					usage(f);
3822 				}
3823 				break;
3824 			case 'i':
3825 				if (my_get_number(optarg,&v,UINT32_MAX,0)<0) {
3826 					fprintf(stderr,"bad inodes limit\n");
3827 					usage(f);
3828 				}
3829 				if (qflags & QUOTA_FLAG_SINODES) {
3830 					fprintf(stderr,"'soft inodes' quota defined twice\n");
3831 					usage(f);
3832 				}
3833 				sinodes = v;
3834 				qflags |= QUOTA_FLAG_SINODES;
3835 				break;
3836 			case 'I':
3837 				if (my_get_number(optarg,&v,UINT32_MAX,0)<0) {
3838 					fprintf(stderr,"bad inodes limit\n");
3839 					usage(f);
3840 				}
3841 				if (qflags & QUOTA_FLAG_HINODES) {
3842 					fprintf(stderr,"'hard inodes' quota defined twice\n");
3843 					usage(f);
3844 				}
3845 				hinodes = v;
3846 				qflags |= QUOTA_FLAG_HINODES;
3847 				break;
3848 			case 'l':
3849 				if (my_get_number(optarg,&v,UINT64_MAX,1)<0) {
3850 					fprintf(stderr,"bad length limit\n");
3851 					usage(f);
3852 				}
3853 				if (qflags & QUOTA_FLAG_SLENGTH) {
3854 					fprintf(stderr,"'soft length' quota defined twice\n");
3855 					usage(f);
3856 				}
3857 				slength = v;
3858 				qflags |= QUOTA_FLAG_SLENGTH;
3859 				break;
3860 			case 'L':
3861 				if (my_get_number(optarg,&v,UINT64_MAX,1)<0) {
3862 					fprintf(stderr,"bad length limit\n");
3863 					usage(f);
3864 				}
3865 				if (qflags & QUOTA_FLAG_HLENGTH) {
3866 					fprintf(stderr,"'hard length' quota defined twice\n");
3867 					usage(f);
3868 				}
3869 				hlength = v;
3870 				qflags |= QUOTA_FLAG_HLENGTH;
3871 				break;
3872 			case 's':
3873 				if (my_get_number(optarg,&v,UINT64_MAX,1)<0) {
3874 					fprintf(stderr,"bad size limit\n");
3875 					usage(f);
3876 				}
3877 				if (qflags & QUOTA_FLAG_SSIZE) {
3878 					fprintf(stderr,"'soft size' quota defined twice\n");
3879 					usage(f);
3880 				}
3881 				ssize = v;
3882 				qflags |= QUOTA_FLAG_SSIZE;
3883 				break;
3884 			case 'S':
3885 				if (my_get_number(optarg,&v,UINT64_MAX,1)<0) {
3886 					fprintf(stderr,"bad size limit\n");
3887 					usage(f);
3888 				}
3889 				if (qflags & QUOTA_FLAG_HSIZE) {
3890 					fprintf(stderr,"'hard size' quota defined twice\n");
3891 					usage(f);
3892 				}
3893 				hsize = v;
3894 				qflags |= QUOTA_FLAG_HSIZE;
3895 				break;
3896 			case 'r':
3897 				if (my_get_number(optarg,&v,UINT64_MAX,1)<0) {
3898 					fprintf(stderr,"bad real size limit\n");
3899 					usage(f);
3900 				}
3901 				if (qflags & QUOTA_FLAG_SREALSIZE) {
3902 					fprintf(stderr,"'soft realsize' quota defined twice\n");
3903 					usage(f);
3904 				}
3905 				srealsize = v;
3906 				qflags |= QUOTA_FLAG_SREALSIZE;
3907 				break;
3908 			case 'R':
3909 				if (my_get_number(optarg,&v,UINT64_MAX,1)<0) {
3910 					fprintf(stderr,"bad real size limit\n");
3911 					usage(f);
3912 				}
3913 				if (qflags & QUOTA_FLAG_HREALSIZE) {
3914 					fprintf(stderr,"'hard realsize' quota defined twice\n");
3915 					usage(f);
3916 				}
3917 				hrealsize = v;
3918 				qflags |= QUOTA_FLAG_HREALSIZE;
3919 				break;
3920 			default:
3921 				usage(f);
3922 			}
3923 		}
3924 		if (qflags==0) {
3925 			fprintf(stderr,"quota options not defined\n");
3926 			usage(f);
3927 		}
3928 		argc -= optind;
3929 		argv += optind;
3930 		break;
3931 	case MFSDELQUOTA:
3932 		if (getuid()) {
3933 			fprintf(stderr,"only root can change quota\n");
3934 			usage(f);
3935 		}
3936 		while ((ch=getopt(argc,argv,"nhHkmgiIlLsSrRaA"))!=-1) {
3937 			switch(ch) {
3938 			case 'n':
3939 				humode=0;
3940 				break;
3941 			case 'h':
3942 				humode=1;
3943 				break;
3944 			case 'H':
3945 				humode=2;
3946 				break;
3947 			case 'k':
3948 				numbermode=1;
3949 				break;
3950 			case 'm':
3951 				numbermode=2;
3952 				break;
3953 			case 'g':
3954 				numbermode=3;
3955 				break;
3956 			case 'i':
3957 				if (qflags & QUOTA_FLAG_SINODES) {
3958 					fprintf(stderr,"'soft inodes' option given twice\n");
3959 					usage(f);
3960 				}
3961 				qflags |= QUOTA_FLAG_SINODES;
3962 				break;
3963 			case 'I':
3964 				if (qflags & QUOTA_FLAG_HINODES) {
3965 					fprintf(stderr,"'hard inodes' option given twice\n");
3966 					usage(f);
3967 				}
3968 				qflags |= QUOTA_FLAG_HINODES;
3969 				break;
3970 			case 'l':
3971 				if (qflags & QUOTA_FLAG_SLENGTH) {
3972 					fprintf(stderr,"'soft length' option given twice\n");
3973 					usage(f);
3974 				}
3975 				qflags |= QUOTA_FLAG_SLENGTH;
3976 				break;
3977 			case 'L':
3978 				if (qflags & QUOTA_FLAG_HLENGTH) {
3979 					fprintf(stderr,"'hard length' option given twice\n");
3980 					usage(f);
3981 				}
3982 				qflags |= QUOTA_FLAG_HLENGTH;
3983 				break;
3984 			case 's':
3985 				if (qflags & QUOTA_FLAG_SSIZE) {
3986 					fprintf(stderr,"'soft size' option given twice\n");
3987 					usage(f);
3988 				}
3989 				qflags |= QUOTA_FLAG_SSIZE;
3990 				break;
3991 			case 'S':
3992 				if (qflags & QUOTA_FLAG_HSIZE) {
3993 					fprintf(stderr,"'hard size' option given twice\n");
3994 					usage(f);
3995 				}
3996 				qflags |= QUOTA_FLAG_HSIZE;
3997 				break;
3998 			case 'r':
3999 				if (qflags & QUOTA_FLAG_SREALSIZE) {
4000 					fprintf(stderr,"'soft realsize' option given twice\n");
4001 					usage(f);
4002 				}
4003 				qflags |= QUOTA_FLAG_SREALSIZE;
4004 				break;
4005 			case 'R':
4006 				if (qflags & QUOTA_FLAG_HREALSIZE) {
4007 					fprintf(stderr,"'hard realsize' option given twice\n");
4008 					usage(f);
4009 				}
4010 				qflags |= QUOTA_FLAG_HREALSIZE;
4011 				break;
4012 			case 'a':
4013 				if (qflags & QUOTA_FLAG_SALL) {
4014 					fprintf(stderr,"'all soft quotas' defined together with other soft quota options\n");
4015 					usage(f);
4016 				}
4017 				qflags |= QUOTA_FLAG_SALL;
4018 				break;
4019 			case 'A':
4020 				if (qflags & QUOTA_FLAG_HALL) {
4021 					fprintf(stderr,"'all hard quotas' defined together with other hard quota options\n");
4022 					usage(f);
4023 				}
4024 				qflags |= QUOTA_FLAG_HALL;
4025 				break;
4026 			default:
4027 				usage(f);
4028 			}
4029 		}
4030 		if (qflags==0) {
4031 			fprintf(stderr,"quota options not defined\n");
4032 			usage(f);
4033 		}
4034 		argc -= optind;
4035 		argv += optind;
4036 		break;
4037 	case MFSMKSC:
4038 	case MFSCHSC:
4039 		while ((ch=getopt(argc,argv,(f==MFSCHSC)?"d:A:K:C:m:a:f":"d:A:K:C:m:a:"))!=-1) {
4040 			switch (ch) {
4041 			case 'd':
4042 				if (chgmask & SCLASS_CHG_ARCH_DELAY) {
4043 					fprintf(stderr,"option '-d' defined more than once\n");
4044 					usage(f);
4045 				}
4046 				sc.arch_delay = strtoul(optarg,NULL,10);
4047 				chgmask |= SCLASS_CHG_ARCH_DELAY;
4048 				break;
4049 			case 'A':
4050 				if (chgmask & SCLASS_CHG_ARCH_MASKS) {
4051 					fprintf(stderr,"option '-A' defined more than once\n");
4052 					usage(f);
4053 				}
4054 				if (parse_label_expr(optarg,&(sc.arch_labelscnt),sc.arch_labelmasks)<0) {
4055 					usage(f);
4056 				}
4057 				chgmask |= SCLASS_CHG_ARCH_MASKS;
4058 				break;
4059 			case 'K':
4060 				if (chgmask & SCLASS_CHG_KEEP_MASKS) {
4061 					fprintf(stderr,"option '-K' defined more than once\n");
4062 					usage(f);
4063 				}
4064 				if (parse_label_expr(optarg,&(sc.keep_labelscnt),sc.keep_labelmasks)<0) {
4065 					usage(f);
4066 				}
4067 				chgmask |= SCLASS_CHG_KEEP_MASKS;
4068 				break;
4069 			case 'C':
4070 				if (chgmask & SCLASS_CHG_CREATE_MASKS) {
4071 					fprintf(stderr,"option '-C' defined more than once\n");
4072 					usage(f);
4073 				}
4074 				if (parse_label_expr(optarg,&(sc.create_labelscnt),sc.create_labelmasks)<0) {
4075 					usage(f);
4076 				}
4077 				chgmask |= SCLASS_CHG_CREATE_MASKS;
4078 				break;
4079 			case 'm':
4080 				if (chgmask & SCLASS_CHG_MODE) {
4081 					fprintf(stderr,"option '-m' defined more than once\n");
4082 					usage(f);
4083 				}
4084 				if (optarg[0]=='l' || optarg[0]=='L') {
4085 					sc.mode = SCLASS_MODE_LOOSE;
4086 				} else if (optarg[0]=='s' || optarg[0]=='S') {
4087 					sc.mode = SCLASS_MODE_STRICT;
4088 				} else if (optarg[0]=='d' || optarg[0]=='D') {
4089 					sc.mode = SCLASS_MODE_STD;
4090 				} else {
4091 					fprintf(stderr,"unknown create mode (option '-m')\n");
4092 					usage(f);
4093 				}
4094 				chgmask |= SCLASS_CHG_MODE;
4095 				break;
4096 			case 'a':
4097 				if (chgmask & SCLASS_CHG_ADMIN_ONLY) {
4098 					fprintf(stderr,"option '-a' defined more than once\n");
4099 					usage(f);
4100 				}
4101 				if (optarg[0]=='0' || optarg[0]=='n' || optarg[0]=='N' || optarg[0]=='f' || optarg[0]=='F') {
4102 					sc.admin_only = 0;
4103 				} else if (optarg[0]=='1' || optarg[0]=='y' || optarg[0]=='Y' || optarg[0]=='t' || optarg[0]=='T') {
4104 					sc.admin_only = 1;
4105 				} else {
4106 					fprintf(stderr,"unknown value for admin only flag (option '-a')\n");
4107 					usage(f);
4108 				}
4109 				chgmask |= SCLASS_CHG_ADMIN_ONLY;
4110 				break;
4111 			case 'f':
4112 				if (chgmask & SCLASS_CHG_FORCE) {
4113 					fprintf(stderr,"option '-f' defined more than once\n");
4114 					usage(f);
4115 				}
4116 				chgmask |= SCLASS_CHG_FORCE;
4117 				break;
4118 			default:
4119 				usage(f);
4120 			}
4121 		}
4122 		argc -= optind;
4123 		argv += optind;
4124 		if (f==MFSMKSC) {
4125 			if ((chgmask & (SCLASS_CHG_ARCH_MASKS|SCLASS_CHG_KEEP_MASKS|SCLASS_CHG_CREATE_MASKS)) == 0) {
4126 				if (argc<2) {
4127 					usage(f);
4128 				}
4129 				if (parse_label_expr(argv[0],&(sc.create_labelscnt),sc.create_labelmasks)<0) {
4130 					usage(f);
4131 				}
4132 				argc--;
4133 				argv++;
4134 				sc.keep_labelscnt = sc.create_labelscnt;
4135 				sc.arch_labelscnt = sc.create_labelscnt;
4136 				for (i=0 ; i<sc.create_labelscnt ; i++) {
4137 					for (j=0 ; j<MASKORGROUP ; j++) {
4138 						sc.arch_labelmasks[i][j] = sc.keep_labelmasks[i][j] = sc.create_labelmasks[i][j];
4139 					}
4140 				}
4141 			} else {
4142 				if ((chgmask & SCLASS_CHG_ARCH_MASKS) && ((chgmask & SCLASS_CHG_KEEP_MASKS)==0)) {
4143 					fprintf(stderr,"option '-A' without '-K'\n");
4144 					usage(f);
4145 				}
4146 				if ((chgmask & SCLASS_CHG_CREATE_MASKS) && ((chgmask & SCLASS_CHG_KEEP_MASKS)==0)) {
4147 					fprintf(stderr,"option '-C' without '-K'\n");
4148 					usage(f);
4149 				}
4150 				if ((chgmask & SCLASS_CHG_ARCH_MASKS) && ((chgmask & SCLASS_CHG_ARCH_DELAY)==0)) {
4151 					fprintf(stderr,"option '-A' without '-d'\n");
4152 					usage(f);
4153 				}
4154 				if ((chgmask & SCLASS_CHG_ARCH_DELAY) && ((chgmask & SCLASS_CHG_ARCH_MASKS)==0)) {
4155 					fprintf(stderr,"option '-A' without '-d'\n");
4156 					usage(f);
4157 				}
4158 				if ((chgmask & SCLASS_CHG_KEEP_MASKS) && ((chgmask & SCLASS_CHG_ARCH_MASKS)==0)) {
4159 					sc.arch_labelscnt = sc.keep_labelscnt;
4160 					for (i=0 ; i<sc.keep_labelscnt ; i++) {
4161 						for (j=0 ; j<MASKORGROUP ; j++) {
4162 							sc.arch_labelmasks[i][j] = sc.keep_labelmasks[i][j];
4163 						}
4164 					}
4165 				}
4166 				if ((chgmask & SCLASS_CHG_KEEP_MASKS) && ((chgmask & SCLASS_CHG_CREATE_MASKS)==0)) {
4167 					sc.create_labelscnt = sc.keep_labelscnt;
4168 					for (i=0 ; i<sc.keep_labelscnt ; i++) {
4169 						for (j=0 ; j<MASKORGROUP ; j++) {
4170 							sc.create_labelmasks[i][j] = sc.keep_labelmasks[i][j];
4171 						}
4172 					}
4173 				}
4174 			}
4175 		}
4176 		break;
4177 	case MFSCPSC:
4178 		if (getopt(argc,argv,"")!=-1) {
4179 			usage(f);
4180 		}
4181 		argc -= optind;
4182 		argv += optind;
4183 		if (argc<2) {
4184 			usage(f);
4185 		}
4186 		srcname = *argv;
4187 		argc--;
4188 		argv++;
4189 		break;
4190 	case MFSMVSC:
4191 		if (getopt(argc,argv,"")!=-1) {
4192 			usage(f);
4193 		}
4194 		argc -= optind;
4195 		argv += optind;
4196 		if (argc!=2) {
4197 			usage(f);
4198 		}
4199 		return move_sc(scadmin_mp,argv[0],argv[1]);
4200 	case MFSLSSC:
4201 	case MFSLISTSCLASS:
4202 		while ((ch=getopt(argc,argv,"l"))!=-1) {
4203 			switch(ch) {
4204 			case 'l':
4205 				longmode |= 1;
4206 				break;
4207 			default:
4208 				usage(f);
4209 			}
4210 		}
4211 		argc -= optind;
4212 		argv += optind;
4213 		if (f==MFSLISTSCLASS) {
4214 			if (argc==1) {
4215 				scadmin_mp = *argv;
4216 			} else if (argc>1) {
4217 				usage(f);
4218 			}
4219 		} else {
4220 			if (argc>0) {
4221 				usage(f);
4222 			}
4223 		}
4224 		return list_sc(scadmin_mp,longmode);
4225 	case MFSAPPENDCHUNKS:
4226 		while ((ch=getopt(argc,argv,"s:"))!=-1) {
4227 			switch(ch) {
4228 			case 's':
4229 				if (parse_slice_expr(optarg,&slice_from,&slice_to)<0) {
4230 					usage(f);
4231 				}
4232 				break;
4233 			default:
4234 				usage(f);
4235 			}
4236 		}
4237 		argc -= optind;
4238 		argv += optind;
4239 		break;
4240 	case MFSRMSC:
4241 	default:
4242 		if (getopt(argc,argv,"")!=-1) {
4243 			usage(f);
4244 		}
4245 		argc -= optind;
4246 		argv += optind;
4247 //		argc--;	// skip appname
4248 //		argv++;
4249 	}
4250 
4251 	if (f==MFSAPPENDCHUNKS) {
4252 		if (argc<=1) {
4253 			usage(f);
4254 		}
4255 		appendfname = argv[0];
4256 		i = open(appendfname,O_RDWR | O_CREAT,0666);
4257 		if (i<0) {
4258 			fprintf(stderr,"can't create/open file: %s\n",appendfname);
4259 			return 1;
4260 		}
4261 		close(i);
4262 		argc--;
4263 		argv++;
4264 	}
4265 
4266 	if (argc<1) {
4267 		usage(f);
4268 	}
4269 	status=0;
4270 	if (f==MFSCOPYGOAL || f==MFSCOPYSCLASS) {
4271 		if (get_sclass(srcname,&goal,storage_class_name,GMODE_NORMAL)<0) {
4272 			return 1;
4273 		}
4274 		smode = SMODE_SET;
4275 	} else if (f==MFSCOPYTRASHTIME) {
4276 		if (get_trashtime(srcname,&trashtime,GMODE_NORMAL)<0) {
4277 			return 1;
4278 		}
4279 		smode = SMODE_SET;
4280 	} else if (f==MFSCOPYEATTR) {
4281 		if (get_eattr(srcname,&eattr,GMODE_NORMAL)<0) {
4282 			return 1;
4283 		}
4284 		smode = SMODE_SET;
4285 	} else if (f==MFSCOPYQUOTA) {
4286 		if (quota_control(srcname,2,&qflags,&graceperiod,&sinodes,&slength,&ssize,&srealsize,&hinodes,&hlength,&hsize,&hrealsize)<0) {
4287 			return 1;
4288 		}
4289 	}
4290 	while (argc>0) {
4291 		switch (f) {
4292 		case MFSGETGOAL:
4293 		case MFSGETSCLASS:
4294 			if (get_sclass(*argv,&goal,storage_class_name,(rflag)?GMODE_RECURSIVE:GMODE_NORMAL)<0) {
4295 				status = 1;
4296 			}
4297 			break;
4298 		case MFSSETGOAL:
4299 		case MFSSETSCLASS:
4300 		case MFSCOPYGOAL:
4301 		case MFSCOPYSCLASS:
4302 		case MFSXCHGSCLASS:
4303 			if (set_sclass(*argv,goal,src_storage_class_name,storage_class_name,(rflag)?(smode | SMODE_RMASK):smode)<0) {
4304 				status = 1;
4305 			}
4306 			break;
4307 		case MFSGETTRASHTIME:
4308 			if (get_trashtime(*argv,&trashtime,(rflag)?GMODE_RECURSIVE:GMODE_NORMAL)<0) {
4309 				status = 1;
4310 			}
4311 			break;
4312 		case MFSSETTRASHTIME:
4313 		case MFSCOPYTRASHTIME:
4314 			if (set_trashtime(*argv,trashtime,(rflag)?(smode | SMODE_RMASK):smode)<0) {
4315 				status = 1;
4316 			}
4317 			break;
4318 		case MFSCHECKFILE:
4319 			if (file_info(FILEINFO_QUICK,*argv)<0) {
4320 				status = 1;
4321 			}
4322 			break;
4323 		case MFSFILEINFO:
4324 			if (file_info(fileinfomode,*argv)<0) {
4325 				status = 1;
4326 			}
4327 			break;
4328 		case MFSAPPENDCHUNKS:
4329 			if (append_file(appendfname,*argv,slice_from,slice_to)<0) {
4330 				status = 1;
4331 			}
4332 			break;
4333 		case MFSDIRINFO:
4334 			if (dir_info(dirinfomode,*argv)<0) {
4335 				status = 1;
4336 			}
4337 			break;
4338 		case MFSFILEREPAIR:
4339 			if (file_repair(*argv)<0) {
4340 				status = 1;
4341 			}
4342 			break;
4343 		case MFSGETEATTR:
4344 			if (get_eattr(*argv,&eattr,(rflag)?GMODE_RECURSIVE:GMODE_NORMAL)<0) {
4345 				status = 1;
4346 			}
4347 			break;
4348 		case MFSSETEATTR:
4349 		case MFSDELEATTR:
4350 		case MFSCOPYEATTR:
4351 			if (set_eattr(*argv,eattr,(rflag)?(smode | SMODE_RMASK):smode)<0) {
4352 				status = 1;
4353 			}
4354 			break;
4355 		case MFSGETQUOTA:
4356 			if (quota_control(*argv,2,&qflags,&graceperiod,&sinodes,&slength,&ssize,&srealsize,&hinodes,&hlength,&hsize,&hrealsize)<0) {
4357 				status = 1;
4358 			}
4359 			break;
4360 		case MFSSETQUOTA:
4361 		case MFSCOPYQUOTA:
4362 			if (quota_control(*argv,0,&qflags,&graceperiod,&sinodes,&slength,&ssize,&srealsize,&hinodes,&hlength,&hsize,&hrealsize)<0) {
4363 				status = 1;
4364 			}
4365 			break;
4366 		case MFSDELQUOTA:
4367 			if (quota_control(*argv,1,&qflags,&graceperiod,&sinodes,&slength,&ssize,&srealsize,&hinodes,&hlength,&hsize,&hrealsize)<0) {
4368 				status = 1;
4369 			}
4370 			break;
4371 		case MFSFILEPATHS:
4372 			if (file_paths(*argv)<0) {
4373 				status = 1;
4374 			}
4375 			break;
4376 		case MFSCHKARCHIVE:
4377 			if (archive_control(*argv,ARCHCTL_GET)<0) {
4378 				status = 1;
4379 			}
4380 			break;
4381 		case MFSSETARCHIVE:
4382 			if (archive_control(*argv,ARCHCTL_SET)<0) {
4383 				status = 1;
4384 			}
4385 			break;
4386 		case MFSCLRARCHIVE:
4387 			if (archive_control(*argv,ARCHCTL_CLR)<0) {
4388 				status = 1;
4389 			}
4390 			break;
4391 		case MFSRMSNAPSHOT:
4392 			if (remove_snapshot(*argv,snapmode)<0) {
4393 				status = 1;
4394 			}
4395 			break;
4396 		case MFSMKSC:
4397 			if (make_sc(scadmin_mp,*argv,&sc)<0) {
4398 				status = 1;
4399 			}
4400 			break;
4401 		case MFSCHSC:
4402 			if (change_sc(scadmin_mp,*argv,chgmask,&sc)<0) {
4403 				status = 1;
4404 			}
4405 			break;
4406 		case MFSRMSC:
4407 			if (remove_sc(scadmin_mp,*argv)<0) {
4408 				status = 1;
4409 			}
4410 			break;
4411 		case MFSCPSC:
4412 			if (copy_sc(scadmin_mp,srcname,*argv)<0) {
4413 				status = 1;
4414 			}
4415 			break;
4416 		}
4417 		argc--;
4418 		argv++;
4419 	}
4420 	return status;
4421 }
4422