]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sbin/tunefs/tunefs.c
Create a new 32-bit fs_flags word in the superblock. Add code to move
[FreeBSD/FreeBSD.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  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by the University of
16  *      California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33
34 #ifndef lint
35 static const char copyright[] =
36 "@(#) Copyright (c) 1983, 1993\n\
37         The Regents of the University of California.  All rights reserved.\n";
38 #endif /* not lint */
39
40 #ifndef lint
41 #if 0
42 static char sccsid[] = "@(#)tunefs.c    8.2 (Berkeley) 4/19/94";
43 #endif
44 static const char rcsid[] =
45   "$FreeBSD$";
46 #endif /* not lint */
47
48 /*
49  * tunefs: change layout parameters to an existing file system.
50  */
51 #include <sys/param.h>
52 #include <sys/mount.h>
53 #include <sys/disklabel.h>
54 #include <sys/stat.h>
55
56 #include <ufs/ufs/ufsmount.h>
57 #include <ufs/ufs/dinode.h>
58 #include <ufs/ffs/fs.h>
59
60 #include <err.h>
61 #include <fcntl.h>
62 #include <fstab.h>
63 #include <paths.h>
64 #include <stdio.h>
65 #include <stdlib.h>
66 #include <string.h>
67 #include <unistd.h>
68
69 /* the optimization warning string template */
70 #define OPTWARN "should optimize for %s with minfree %s %d%%"
71
72 union {
73         struct  fs sb;
74         char pad[MAXBSIZE];
75 } sbun;
76 #define sblock sbun.sb
77
78 int fi;
79 long dev_bsize = 1;
80
81 void bwrite(ufs2_daddr_t, const char *, int);
82 int bread(ufs2_daddr_t, char *, int);
83 void getsb(struct fs *, const char *);
84 void putsb(struct fs *, const char *, int);
85 void usage(void);
86 void printfs(void);
87
88 int
89 main(argc, argv)
90         int argc;
91         char *argv[];
92 {
93         char *special;
94         const char *name;
95         struct stat st;
96         int Aflag = 0, active = 0, aflag = 0;
97         int eflag = 0, fflag = 0, lflag = 0, mflag = 0;
98         int nflag = 0, oflag = 0, pflag = 0, sflag = 0;
99         int evalue = 0, fvalue = 0;
100         int mvalue = 0, ovalue = 0, svalue = 0;
101         char *avalue = NULL, *lvalue = NULL, *nvalue = NULL; 
102         struct fstab *fs;
103         const char *chg[2];
104         char device[MAXPATHLEN];
105         struct ufs_args args;
106         struct statfs stfs;
107         int found_arg, ch;
108
109         if (argc < 3)
110                 usage();
111         found_arg = 0; /* at least one arg is required */
112         while ((ch = getopt(argc, argv, "Aa:e:f:l:m:n:o:ps:")) != -1)
113           switch (ch) {
114           case 'A':
115                 found_arg = 1;
116                 Aflag++;
117                 break;
118           case 'a':
119                 found_arg = 1;
120                 name = "ACLs";
121                 avalue = optarg;
122                 if (strcmp(avalue, "enable") && strcmp(avalue, "disable")) {
123                         errx(10, "bad %s (options are %s)", name,
124                             "`enable' or `disable'");
125                 }
126                 aflag = 1;
127                 break;
128           case 'e':
129                 found_arg = 1;
130                 name = "maximum blocks per file in a cylinder group";
131                 evalue = atoi(optarg);
132                 if (evalue < 1)
133                         errx(10, "%s must be >= 1 (was %s)", name, optarg);
134                 eflag = 1;
135                 break;
136           case 'f':
137                 found_arg = 1;
138                 name = "average file size";
139                 fvalue = atoi(optarg);
140                 if (fvalue < 1)
141                         errx(10, "%s must be >= 1 (was %s)", name, optarg);
142                 fflag = 1;
143                 break;
144           case 'l':
145                 found_arg = 1;
146                 name = "multilabel MAC file system";
147                 lvalue = optarg;
148                 if (strcmp(lvalue, "enable") && strcmp(lvalue, "disable")) {
149                         errx(10, "bad %s (options are %s)", name,
150                             "`enable' or `disable'");
151                 }
152                 lflag = 1;
153                 break;
154           case 'm':
155                 found_arg = 1;
156                 name = "minimum percentage of free space";
157                 mvalue = atoi(optarg);
158                 if (mvalue < 0 || mvalue > 99)
159                         errx(10, "bad %s (%s)", name, optarg);
160                 mflag = 1;
161                 break;
162           case 'n':
163                 found_arg = 1;
164                 name = "soft updates";
165                 nvalue = optarg;
166                 if (strcmp(nvalue, "enable") && strcmp(nvalue, "disable")) {
167                         errx(10, "bad %s (options are %s)",
168                             name, "`enable' or `disable'");
169                 }
170                 nflag = 1;
171                 break;
172           case 'o':
173                 found_arg = 1;
174                 name = "optimization preference";
175                 chg[FS_OPTSPACE] = "space";
176                 chg[FS_OPTTIME] = "time";
177                 if (strcmp(optarg, chg[FS_OPTSPACE]) == 0)
178                         ovalue = FS_OPTSPACE;
179                 else if (strcmp(optarg, chg[FS_OPTTIME]) == 0)
180                         ovalue = FS_OPTTIME;
181                 else
182                         errx(10, "bad %s (options are `space' or `time')",
183                                             name);
184                 oflag = 1;
185                 break;
186           case 'p':
187                 found_arg = 1;
188                 pflag = 1;
189                 break;
190           case 's':
191                 found_arg = 1;
192                 name = "expected number of files per directory";
193                 svalue = atoi(optarg);
194                 if (svalue < 1)
195                         errx(10, "%s must be >= 1 (was %s)", name, optarg);
196                 sflag = 1;
197                 break;
198           default:
199                 usage();
200           }
201         argc -= optind;
202         argv += optind;
203
204         if (found_arg == 0 || argc != 1)
205           usage();
206
207         special = argv[0];
208         fs = getfsfile(special);
209         if (fs) {
210                 if (statfs(special, &stfs) == 0 &&
211                     strcmp(special, stfs.f_mntonname) == 0) {
212                         active = 1;
213                 }
214                 special = fs->fs_spec;
215         }
216 again:
217         if (stat(special, &st) < 0) {
218                 if (*special != '/') {
219                         if (*special == 'r')
220                                 special++;
221                         (void)snprintf(device, sizeof(device), "%s%s",
222                                        _PATH_DEV, special);
223                         special = device;
224                         goto again;
225                 }
226                 err(1, "%s", special);
227         }
228         if (fs == NULL && (st.st_mode & S_IFMT) == S_IFDIR)
229                 errx(10, "%s: unknown file system", special);
230         getsb(&sblock, special);
231
232         if (pflag) {
233                 printfs();
234                 exit(0);
235         }
236         if (aflag) {
237                 name = "ACLs";
238                 if (strcmp(avalue, "enable") == 0) {
239                         if (sblock.fs_flags & FS_ACLS) {
240                                 warnx("%s remains unchanged as enabled", name);
241                         } else {
242                                 sblock.fs_flags |= FS_ACLS;
243                                 warnx("%s set", name);
244                         }
245                 } else if (strcmp(avalue, "disable") == 0) {
246                         if ((~sblock.fs_flags & FS_ACLS) ==
247                             FS_ACLS) {
248                                 warnx("%s remains unchanged as disabled",
249                                     name);
250                         } else {
251                                 sblock.fs_flags &= ~FS_ACLS;
252                                 warnx("%s cleared", name);
253                         }
254                 }
255         }
256         if (eflag) {
257                 name = "maximum blocks per file in a cylinder group";
258                 if (sblock.fs_maxbpg == evalue) {
259                         warnx("%s remains unchanged as %d", name, evalue);
260                 }
261                 else {
262                         warnx("%s changes from %d to %d",
263                                         name, sblock.fs_maxbpg, evalue);
264                         sblock.fs_maxbpg = evalue;
265                 }
266         }
267         if (fflag) {
268                 name = "average file size";
269                 if (sblock.fs_avgfilesize == fvalue) {
270                         warnx("%s remains unchanged as %d", name, fvalue);
271                 }
272                 else {
273                         warnx("%s changes from %d to %d",
274                                         name, sblock.fs_avgfilesize, fvalue);
275                         sblock.fs_avgfilesize = fvalue;
276                 }
277         }
278         if (lflag) {
279                 name = "multilabel";
280                 if (strcmp(lvalue, "enable") == 0) {
281                         if (sblock.fs_flags & FS_MULTILABEL) {
282                                 warnx("%s remains unchanged as enabled", name);
283                         } else {
284                                 sblock.fs_flags |= FS_MULTILABEL;
285                                 warnx("%s set", name);
286                         }
287                 } else if (strcmp(lvalue, "disable") == 0) {
288                         if ((~sblock.fs_flags & FS_MULTILABEL) ==
289                             FS_MULTILABEL) {
290                                 warnx("%s remains unchanged as disabled",
291                                     name);
292                         } else {
293                                 sblock.fs_flags &= ~FS_MULTILABEL;
294                                 warnx("%s cleared", name);
295                         }
296                 }
297         }
298         if (mflag) {
299                 name = "minimum percentage of free space";
300                 if (sblock.fs_minfree == mvalue) {
301                         warnx("%s remains unchanged as %d%%", name, mvalue);
302                 }
303                 else {
304                         warnx("%s changes from %d%% to %d%%",
305                                     name, sblock.fs_minfree, mvalue);
306                         sblock.fs_minfree = mvalue;
307                         if (mvalue >= MINFREE && sblock.fs_optim == FS_OPTSPACE)
308                                 warnx(OPTWARN, "time", ">=", MINFREE);
309                         if (mvalue < MINFREE && sblock.fs_optim == FS_OPTTIME)
310                                 warnx(OPTWARN, "space", "<", MINFREE);
311                 }
312         }
313         if (nflag) {
314                 name = "soft updates";
315                 if (strcmp(nvalue, "enable") == 0) {
316                         if (sblock.fs_flags & FS_DOSOFTDEP) {
317                                 warnx("%s remains unchanged as enabled", name);
318                         } else if (sblock.fs_clean == 0) {
319                                 warnx("%s cannot be enabled until fsck is run",
320                                     name);
321                         } else {
322                                 sblock.fs_flags |= FS_DOSOFTDEP;
323                                 warnx("%s set", name);
324                         }
325                 } else if (strcmp(nvalue, "disable") == 0) {
326                         if ((~sblock.fs_flags & FS_DOSOFTDEP) == FS_DOSOFTDEP) {
327                                 warnx("%s remains unchanged as disabled", name);
328                         } else {
329                                 sblock.fs_flags &= ~FS_DOSOFTDEP;
330                                 warnx("%s cleared", name);
331                         }
332                 }
333         }
334         if (oflag) {
335                 name = "optimization preference";
336                 chg[FS_OPTSPACE] = "space";
337                 chg[FS_OPTTIME] = "time";
338                 if (sblock.fs_optim == ovalue) {
339                         warnx("%s remains unchanged as %s", name, chg[ovalue]);
340                 }
341                 else {
342                         warnx("%s changes from %s to %s",
343                                     name, chg[sblock.fs_optim], chg[ovalue]);
344                         sblock.fs_optim = ovalue;
345                         if (sblock.fs_minfree >= MINFREE &&
346                                         ovalue == FS_OPTSPACE)
347                                 warnx(OPTWARN, "time", ">=", MINFREE);
348                         if (sblock.fs_minfree < MINFREE &&
349                                         ovalue == FS_OPTTIME)
350                                 warnx(OPTWARN, "space", "<", MINFREE);
351                 }
352         }
353         if (sflag) {
354                 name = "expected number of files per directory";
355                 if (sblock.fs_avgfpdir == svalue) {
356                         warnx("%s remains unchanged as %d", name, svalue);
357                 }
358                 else {
359                         warnx("%s changes from %d to %d",
360                                         name, sblock.fs_avgfpdir, svalue);
361                         sblock.fs_avgfpdir = svalue;
362                 }
363         }
364
365         putsb(&sblock, special, Aflag);
366         if (active) {
367                 bzero(&args, sizeof(args));
368                 if (mount("ufs", fs->fs_file,
369                     stfs.f_flags | MNT_UPDATE | MNT_RELOAD, &args) < 0)
370                         err(9, "%s: reload", special);
371                 warnx("file system reloaded");
372         }
373         exit(0);
374 }
375
376 void
377 usage()
378 {
379         fprintf(stderr, "%s\n%s\n%s\n",
380 "usage: tunefs [-A] [-a enable | disable] [-e maxbpg] [-f avgfilesize]",
381 "              [-l enable | disable] [-m minfree] [-n enable | disable]",
382 "              [-o space | time] [-p] [-s avgfpdir] special | filesystem");
383         exit(2);
384 }
385
386 /*
387  * Possible superblock locations ordered from most to least likely.
388  */
389 static int sblock_try[] = SBLOCKSEARCH;
390 static ufs2_daddr_t sblockloc;
391
392 void
393 getsb(fs, file)
394         struct fs *fs;
395         const char *file;
396 {
397         int i;
398
399         fi = open(file, O_RDONLY);
400         if (fi < 0)
401                 err(3, "cannot open %s", file);
402         for (i = 0; sblock_try[i] != -1; i++) {
403                 if (bread(sblock_try[i], (char *)fs, SBLOCKSIZE))
404                         err(4, "%s: bad super block", file);
405                 if ((fs->fs_magic == FS_UFS1_MAGIC ||
406                      (fs->fs_magic == FS_UFS2_MAGIC &&
407                       fs->fs_sblockloc == sblock_try[i])) &&
408                     fs->fs_bsize <= MAXBSIZE &&
409                     fs->fs_bsize >= sizeof(struct fs))
410                         break;
411         }
412         if (sblock_try[i] == -1)
413                 err(5, "Cannot find file system superblock");
414         dev_bsize = fs->fs_fsize / fsbtodb(fs, 1);
415         sblockloc = sblock_try[i] / dev_bsize;
416 }
417
418 void
419 putsb(fs, file, all)
420         struct fs *fs;
421         const char *file;
422         int all;
423 {
424         int i;
425
426         /*
427          * Re-open the device read-write. Use the read-only file
428          * descriptor as an interlock to prevent the device from
429          * being mounted while we are switching mode.
430          */
431         i = fi;
432         fi = open(file, O_RDWR);
433         close(i);
434         if (fi < 0)
435                 err(3, "cannot open %s", file);
436         bwrite(sblockloc, (const char *)fs, SBLOCKSIZE);
437         if (all)
438                 for (i = 0; i < fs->fs_ncg; i++)
439                         bwrite(fsbtodb(fs, cgsblock(fs, i)),
440                             (const char *)fs, SBLOCKSIZE);
441         close(fi);
442 }
443
444 void
445 printfs()
446 {
447         warnx("ACLs: (-a)                                         %s",
448                 (sblock.fs_flags & FS_ACLS)? "enabled" : "disabled");
449         warnx("MAC multilabel: (-l)                               %s",
450                 (sblock.fs_flags & FS_MULTILABEL)? "enabled" : "disabled");
451         warnx("soft updates:  (-n)                                %s", 
452                 (sblock.fs_flags & FS_DOSOFTDEP)? "enabled" : "disabled");
453         warnx("maximum blocks per file in a cylinder group: (-e)  %d",
454               sblock.fs_maxbpg);
455         warnx("average file size: (-f)                            %d",
456               sblock.fs_avgfilesize);
457         warnx("average number of files in a directory: (-s)       %d",
458               sblock.fs_avgfpdir);
459         warnx("minimum percentage of free space: (-m)             %d%%",
460               sblock.fs_minfree);
461         warnx("optimization preference: (-o)                      %s",
462               sblock.fs_optim == FS_OPTSPACE ? "space" : "time");
463         if (sblock.fs_minfree >= MINFREE &&
464             sblock.fs_optim == FS_OPTSPACE)
465                 warnx(OPTWARN, "time", ">=", MINFREE);
466         if (sblock.fs_minfree < MINFREE &&
467             sblock.fs_optim == FS_OPTTIME)
468                 warnx(OPTWARN, "space", "<", MINFREE);
469 }
470
471 void
472 bwrite(blk, buf, size)
473         ufs2_daddr_t blk;
474         const char *buf;
475         int size;
476 {
477
478         if (lseek(fi, (off_t)blk * dev_bsize, SEEK_SET) < 0)
479                 err(6, "FS SEEK");
480         if (write(fi, buf, size) != size)
481                 err(7, "FS WRITE");
482 }
483
484 int
485 bread(bno, buf, cnt)
486         ufs2_daddr_t bno;
487         char *buf;
488         int cnt;
489 {
490         int i;
491
492         if (lseek(fi, (off_t)bno * dev_bsize, SEEK_SET) < 0)
493                 return(1);
494         if ((i = read(fi, buf, cnt)) != cnt) {
495                 for(i=0; i<sblock.fs_bsize; i++)
496                         buf[i] = 0;
497                 return (1);
498         }
499         return (0);
500 }