]> CyberLeo.Net >> Repos - FreeBSD/stable/8.git/blob - sbin/tunefs/tunefs.c
MFC r230377:
[FreeBSD/stable/8.git] / sbin / tunefs / tunefs.c
1 /*
2  * Copyright (c) 1983, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 4. Neither the name of the University nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 #if 0
31 #ifndef lint
32 static const char copyright[] =
33 "@(#) Copyright (c) 1983, 1993\n\
34         The Regents of the University of California.  All rights reserved.\n";
35 #endif /* not lint */
36
37 #ifndef lint
38 static char sccsid[] = "@(#)tunefs.c    8.2 (Berkeley) 4/19/94";
39 #endif /* not lint */
40 #endif
41 #include <sys/cdefs.h>
42 __FBSDID("$FreeBSD$");
43
44 /*
45  * tunefs: change layout parameters to an existing file system.
46  */
47 #include <sys/param.h>
48 #include <sys/mount.h>
49 #include <sys/disklabel.h>
50 #include <sys/stat.h>
51
52 #include <ufs/ufs/ufsmount.h>
53 #include <ufs/ufs/dinode.h>
54 #include <ufs/ffs/fs.h>
55
56 #include <ctype.h>
57 #include <err.h>
58 #include <fcntl.h>
59 #include <fstab.h>
60 #include <libufs.h>
61 #include <paths.h>
62 #include <stdio.h>
63 #include <stdlib.h>
64 #include <string.h>
65 #include <unistd.h>
66
67 /* the optimization warning string template */
68 #define OPTWARN "should optimize for %s with minfree %s %d%%"
69
70 struct uufsd disk;
71 #define sblock disk.d_fs
72
73 void usage(void);
74 void printfs(void);
75
76 int
77 main(int argc, char *argv[])
78 {
79         char *avalue, *Jvalue, *Lvalue, *lvalue, *Nvalue, *nvalue;
80         char *tvalue;
81         const char *special, *on;
82         const char *name;
83         int active;
84         int Aflag, aflag, eflag, evalue, fflag, fvalue, Jflag, Lflag, lflag;
85         int mflag, mvalue, Nflag, nflag, oflag, ovalue, pflag, sflag, svalue;
86         int tflag;
87         int ch, found_arg, i;
88         const char *chg[2];
89         struct ufs_args args;
90         struct statfs stfs;
91
92         if (argc < 3)
93                 usage();
94         Aflag = aflag = eflag = fflag = Jflag = Lflag = lflag = mflag = 0;
95         Nflag = nflag = oflag = pflag = sflag = tflag = 0;
96         avalue = Jvalue = Lvalue = lvalue = Nvalue = nvalue = NULL;
97         evalue = fvalue = mvalue = ovalue = svalue = 0;
98         active = 0;
99         found_arg = 0;          /* At least one arg is required. */
100         while ((ch = getopt(argc, argv, "Aa:e:f:J:L:l:m:N:n:o:ps:t:")) != -1)
101                 switch (ch) {
102
103                 case 'A':
104                         found_arg = 1;
105                         Aflag++;
106                         break;
107
108                 case 'a':
109                         found_arg = 1;
110                         name = "POSIX.1e ACLs";
111                         avalue = optarg;
112                         if (strcmp(avalue, "enable") &&
113                             strcmp(avalue, "disable")) {
114                                 errx(10, "bad %s (options are %s)",
115                                     name, "`enable' or `disable'");
116                         }
117                         aflag = 1;
118                         break;
119
120                 case 'e':
121                         found_arg = 1;
122                         name = "maximum blocks per file in a cylinder group";
123                         evalue = atoi(optarg);
124                         if (evalue < 1)
125                                 errx(10, "%s must be >= 1 (was %s)",
126                                     name, optarg);
127                         eflag = 1;
128                         break;
129
130                 case 'f':
131                         found_arg = 1;
132                         name = "average file size";
133                         fvalue = atoi(optarg);
134                         if (fvalue < 1)
135                                 errx(10, "%s must be >= 1 (was %s)",
136                                     name, optarg);
137                         fflag = 1;
138                         break;
139
140                 case 'J':
141                         found_arg = 1;
142                         name = "gjournaled file system";
143                         Jvalue = optarg;
144                         if (strcmp(Jvalue, "enable") &&
145                             strcmp(Jvalue, "disable")) {
146                                 errx(10, "bad %s (options are %s)",
147                                     name, "`enable' or `disable'");
148                         }
149                         Jflag = 1;
150                         break;
151
152
153                 case 'L':
154                         found_arg = 1;
155                         name = "volume label";
156                         Lvalue = optarg;
157                         i = -1;
158                         while (isalnum(Lvalue[++i]));
159                         if (Lvalue[i] != '\0') {
160                                 errx(10,
161                                 "bad %s. Valid characters are alphanumerics.",
162                                     name);
163                         }
164                         if (strlen(Lvalue) >= MAXVOLLEN) {
165                                 errx(10, "bad %s. Length is longer than %d.",
166                                     name, MAXVOLLEN - 1);
167                         }
168                         Lflag = 1;
169                         break;
170
171                 case 'l':
172                         found_arg = 1;
173                         name = "multilabel MAC file system";
174                         lvalue = optarg;
175                         if (strcmp(lvalue, "enable") &&
176                             strcmp(lvalue, "disable")) {
177                                 errx(10, "bad %s (options are %s)",
178                                     name, "`enable' or `disable'");
179                         }
180                         lflag = 1;
181                         break;
182
183                 case 'm':
184                         found_arg = 1;
185                         name = "minimum percentage of free space";
186                         mvalue = atoi(optarg);
187                         if (mvalue < 0 || mvalue > 99)
188                                 errx(10, "bad %s (%s)", name, optarg);
189                         mflag = 1;
190                         break;
191
192                 case 'N':
193                         found_arg = 1;
194                         name = "NFSv4 ACLs";
195                         Nvalue = optarg;
196                         if (strcmp(Nvalue, "enable") &&
197                             strcmp(Nvalue, "disable")) {
198                                 errx(10, "bad %s (options are %s)",
199                                     name, "`enable' or `disable'");
200                         }
201                         Nflag = 1;
202                         break;
203
204                 case 'n':
205                         found_arg = 1;
206                         name = "soft updates";
207                         nvalue = optarg;
208                         if (strcmp(nvalue, "enable") != 0 &&
209                             strcmp(nvalue, "disable") != 0) {
210                                 errx(10, "bad %s (options are %s)",
211                                     name, "`enable' or `disable'");
212                         }
213                         nflag = 1;
214                         break;
215
216                 case 'o':
217                         found_arg = 1;
218                         name = "optimization preference";
219                         if (strcmp(optarg, "space") == 0)
220                                 ovalue = FS_OPTSPACE;
221                         else if (strcmp(optarg, "time") == 0)
222                                 ovalue = FS_OPTTIME;
223                         else
224                                 errx(10,
225                                     "bad %s (options are `space' or `time')",
226                                     name);
227                         oflag = 1;
228                         break;
229
230                 case 'p':
231                         found_arg = 1;
232                         pflag = 1;
233                         break;
234
235                 case 's':
236                         found_arg = 1;
237                         name = "expected number of files per directory";
238                         svalue = atoi(optarg);
239                         if (svalue < 1)
240                                 errx(10, "%s must be >= 1 (was %s)",
241                                     name, optarg);
242                         sflag = 1;
243                         break;
244
245                 case 't':
246                         found_arg = 1;
247                         name = "trim";
248                         tvalue = optarg;
249                         if (strcmp(tvalue, "enable") != 0 &&
250                             strcmp(tvalue, "disable") != 0) {
251                                 errx(10, "bad %s (options are %s)",
252                                     name, "`enable' or `disable'");
253                         }
254                         tflag = 1;
255                         break;
256
257                 default:
258                         usage();
259                 }
260         argc -= optind;
261         argv += optind;
262         if (found_arg == 0 || argc != 1)
263                 usage();
264
265         on = special = argv[0];
266         if (ufs_disk_fillout(&disk, special) == -1)
267                 goto err;
268         if (disk.d_name != special) {
269                 special = disk.d_name;
270                 if (statfs(special, &stfs) == 0 &&
271                     strcmp(special, stfs.f_mntonname) == 0)
272                         active = 1;
273         }
274
275         if (pflag) {
276                 printfs();
277                 exit(0);
278         }
279         if (Lflag) {
280                 name = "volume label";
281                 strlcpy(sblock.fs_volname, Lvalue, MAXVOLLEN);
282         }
283         if (aflag) {
284                 name = "POSIX.1e ACLs";
285                 if (strcmp(avalue, "enable") == 0) {
286                         if (sblock.fs_flags & FS_ACLS) {
287                                 warnx("%s remains unchanged as enabled", name);
288                         } else if (sblock.fs_flags & FS_NFS4ACLS) {
289                                 warnx("%s and NFSv4 ACLs are mutually "
290                                     "exclusive", name);
291                         } else {
292                                 sblock.fs_flags |= FS_ACLS;
293                                 warnx("%s set", name);
294                         }
295                 } else if (strcmp(avalue, "disable") == 0) {
296                         if ((~sblock.fs_flags & FS_ACLS) ==
297                             FS_ACLS) {
298                                 warnx("%s remains unchanged as disabled",
299                                     name);
300                         } else {
301                                 sblock.fs_flags &= ~FS_ACLS;
302                                 warnx("%s cleared", name);
303                         }
304                 }
305         }
306         if (eflag) {
307                 name = "maximum blocks per file in a cylinder group";
308                 if (sblock.fs_maxbpg == evalue)
309                         warnx("%s remains unchanged as %d", name, evalue);
310                 else {
311                         warnx("%s changes from %d to %d",
312                             name, sblock.fs_maxbpg, evalue);
313                         sblock.fs_maxbpg = evalue;
314                 }
315         }
316         if (fflag) {
317                 name = "average file size";
318                 if (sblock.fs_avgfilesize == (unsigned)fvalue) {
319                         warnx("%s remains unchanged as %d", name, fvalue);
320                 }
321                 else {
322                         warnx("%s changes from %d to %d",
323                                         name, sblock.fs_avgfilesize, fvalue);
324                         sblock.fs_avgfilesize = fvalue;
325                 }
326         }
327         if (Jflag) {
328                 name = "gjournal";
329                 if (strcmp(Jvalue, "enable") == 0) {
330                         if (sblock.fs_flags & FS_GJOURNAL) {
331                                 warnx("%s remains unchanged as enabled", name);
332                         } else {
333                                 sblock.fs_flags |= FS_GJOURNAL;
334                                 warnx("%s set", name);
335                         }
336                 } else if (strcmp(Jvalue, "disable") == 0) {
337                         if ((~sblock.fs_flags & FS_GJOURNAL) ==
338                             FS_GJOURNAL) {
339                                 warnx("%s remains unchanged as disabled",
340                                     name);
341                         } else {
342                                 sblock.fs_flags &= ~FS_GJOURNAL;
343                                 warnx("%s cleared", name);
344                         }
345                 }
346         }
347         if (lflag) {
348                 name = "multilabel";
349                 if (strcmp(lvalue, "enable") == 0) {
350                         if (sblock.fs_flags & FS_MULTILABEL) {
351                                 warnx("%s remains unchanged as enabled", name);
352                         } else {
353                                 sblock.fs_flags |= FS_MULTILABEL;
354                                 warnx("%s set", name);
355                         }
356                 } else if (strcmp(lvalue, "disable") == 0) {
357                         if ((~sblock.fs_flags & FS_MULTILABEL) ==
358                             FS_MULTILABEL) {
359                                 warnx("%s remains unchanged as disabled",
360                                     name);
361                         } else {
362                                 sblock.fs_flags &= ~FS_MULTILABEL;
363                                 warnx("%s cleared", name);
364                         }
365                 }
366         }
367         if (mflag) {
368                 name = "minimum percentage of free space";
369                 if (sblock.fs_minfree == mvalue)
370                         warnx("%s remains unchanged as %d%%", name, mvalue);
371                 else {
372                         warnx("%s changes from %d%% to %d%%",
373                                     name, sblock.fs_minfree, mvalue);
374                         sblock.fs_minfree = mvalue;
375                         if (mvalue >= MINFREE && sblock.fs_optim == FS_OPTSPACE)
376                                 warnx(OPTWARN, "time", ">=", MINFREE);
377                         if (mvalue < MINFREE && sblock.fs_optim == FS_OPTTIME)
378                                 warnx(OPTWARN, "space", "<", MINFREE);
379                 }
380         }
381         if (Nflag) {
382                 name = "NFSv4 ACLs";
383                 if (strcmp(Nvalue, "enable") == 0) {
384                         if (sblock.fs_flags & FS_NFS4ACLS) {
385                                 warnx("%s remains unchanged as enabled", name);
386                         } else if (sblock.fs_flags & FS_ACLS) {
387                                 warnx("%s and POSIX.1e ACLs are mutually "
388                                     "exclusive", name);
389                         } else {
390                                 sblock.fs_flags |= FS_NFS4ACLS;
391                                 warnx("%s set", name);
392                         }
393                 } else if (strcmp(Nvalue, "disable") == 0) {
394                         if ((~sblock.fs_flags & FS_NFS4ACLS) ==
395                             FS_NFS4ACLS) {
396                                 warnx("%s remains unchanged as disabled",
397                                     name);
398                         } else {
399                                 sblock.fs_flags &= ~FS_NFS4ACLS;
400                                 warnx("%s cleared", name);
401                         }
402                 }
403         }
404         if (nflag) {
405                 name = "soft updates";
406                 if (strcmp(nvalue, "enable") == 0) {
407                         if (sblock.fs_flags & FS_DOSOFTDEP)
408                                 warnx("%s remains unchanged as enabled", name);
409                         else if (sblock.fs_clean == 0) {
410                                 warnx("%s cannot be enabled until fsck is run",
411                                     name);
412                         } else {
413                                 sblock.fs_flags |= FS_DOSOFTDEP;
414                                 warnx("%s set", name);
415                         }
416                 } else if (strcmp(nvalue, "disable") == 0) {
417                         if ((~sblock.fs_flags & FS_DOSOFTDEP) == FS_DOSOFTDEP)
418                                 warnx("%s remains unchanged as disabled", name);
419                         else {
420                                 sblock.fs_flags &= ~FS_DOSOFTDEP;
421                                 warnx("%s cleared", name);
422                         }
423                 }
424         }
425         if (oflag) {
426                 name = "optimization preference";
427                 chg[FS_OPTSPACE] = "space";
428                 chg[FS_OPTTIME] = "time";
429                 if (sblock.fs_optim == ovalue)
430                         warnx("%s remains unchanged as %s", name, chg[ovalue]);
431                 else {
432                         warnx("%s changes from %s to %s",
433                                     name, chg[sblock.fs_optim], chg[ovalue]);
434                         sblock.fs_optim = ovalue;
435                         if (sblock.fs_minfree >= MINFREE &&
436                             ovalue == FS_OPTSPACE)
437                                 warnx(OPTWARN, "time", ">=", MINFREE);
438                         if (sblock.fs_minfree < MINFREE && ovalue == FS_OPTTIME)
439                                 warnx(OPTWARN, "space", "<", MINFREE);
440                 }
441         }
442         if (sflag) {
443                 name = "expected number of files per directory";
444                 if (sblock.fs_avgfpdir == (unsigned)svalue) {
445                         warnx("%s remains unchanged as %d", name, svalue);
446                 }
447                 else {
448                         warnx("%s changes from %d to %d",
449                                         name, sblock.fs_avgfpdir, svalue);
450                         sblock.fs_avgfpdir = svalue;
451                 }
452         }
453         if (tflag) {
454                 name = "issue TRIM to the disk";
455                 if (strcmp(tvalue, "enable") == 0) {
456                         if (sblock.fs_flags & FS_TRIM)
457                                 warnx("%s remains unchanged as enabled", name);
458                         else {
459                                 sblock.fs_flags |= FS_TRIM;
460                                 warnx("%s set", name);
461                         }
462                 } else if (strcmp(tvalue, "disable") == 0) {
463                         if ((~sblock.fs_flags & FS_TRIM) == FS_TRIM)
464                                 warnx("%s remains unchanged as disabled", name);
465                         else {
466                                 sblock.fs_flags &= ~FS_TRIM;
467                                 warnx("%s cleared", name);
468                         }
469                 }
470         }
471
472         if (sbwrite(&disk, Aflag) == -1)
473                 goto err;
474         ufs_disk_close(&disk);
475         if (active) {
476                 bzero(&args, sizeof(args));
477                 if (mount("ufs", on,
478                     stfs.f_flags | MNT_UPDATE | MNT_RELOAD, &args) < 0)
479                         err(9, "%s: reload", special);
480                 warnx("file system reloaded");
481         }
482         exit(0);
483 err:
484         if (disk.d_error != NULL)
485                 errx(11, "%s: %s", special, disk.d_error);
486         else
487                 err(12, "%s", special);
488 }
489
490 void
491 usage(void)
492 {
493         fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n",
494 "usage: tunefs [-A] [-a enable | disable] [-e maxbpg] [-f avgfilesize]",
495 "              [-J enable | disable ] [-L volname] [-l enable | disable]",
496 "              [-m minfree] [-N enable | disable] [-n enable | disable]",
497 "              [-o space | time] [-p] [-s avgfpdir] [-t enable | disable]",
498 "              special | filesystem");
499         exit(2);
500 }
501
502 void
503 printfs(void)
504 {
505         warnx("POSIX.1e ACLs: (-a)                                %s",
506                 (sblock.fs_flags & FS_ACLS)? "enabled" : "disabled");
507         warnx("NFSv4 ACLs: (-N)                                   %s",
508                 (sblock.fs_flags & FS_NFS4ACLS)? "enabled" : "disabled");
509         warnx("MAC multilabel: (-l)                               %s",
510                 (sblock.fs_flags & FS_MULTILABEL)? "enabled" : "disabled");
511         warnx("soft updates: (-n)                                 %s", 
512                 (sblock.fs_flags & FS_DOSOFTDEP)? "enabled" : "disabled");
513         warnx("gjournal: (-J)                                     %s",
514                 (sblock.fs_flags & FS_GJOURNAL)? "enabled" : "disabled");
515         warnx("trim: (-t)                                         %s", 
516                 (sblock.fs_flags & FS_TRIM)? "enabled" : "disabled");
517         warnx("maximum blocks per file in a cylinder group: (-e)  %d",
518               sblock.fs_maxbpg);
519         warnx("average file size: (-f)                            %d",
520               sblock.fs_avgfilesize);
521         warnx("average number of files in a directory: (-s)       %d",
522               sblock.fs_avgfpdir);
523         warnx("minimum percentage of free space: (-m)             %d%%",
524               sblock.fs_minfree);
525         warnx("optimization preference: (-o)                      %s",
526               sblock.fs_optim == FS_OPTSPACE ? "space" : "time");
527         if (sblock.fs_minfree >= MINFREE &&
528             sblock.fs_optim == FS_OPTSPACE)
529                 warnx(OPTWARN, "time", ">=", MINFREE);
530         if (sblock.fs_minfree < MINFREE &&
531             sblock.fs_optim == FS_OPTTIME)
532                 warnx(OPTWARN, "space", "<", MINFREE);
533         warnx("volume label: (-L)                                 %s",
534                 sblock.fs_volname);
535 }