Whamcloud - gitweb
ChangeLog, fsck.c:
[tools/e2fsprogs.git] / misc / tune2fs.c
1 /*
2  * tune2fs.c            - Change the file system parameters on
3  *                        an unmounted second extended file system
4  *
5  * Copyright (C) 1992, 1993, 1994  Remy Card <card@masi.ibp.fr>
6  *                                 Laboratoire MASI, Institut Blaise Pascal
7  *                                 Universite Pierre et Marie Curie (Paris VI)
8  *
9  * Copyright 1995, 1996, 1997 by Theodore Ts'o.
10  *
11  * %Begin-Header%
12  * This file may be redistributed under the terms of the GNU Public
13  * License.
14  * %End-Header%
15  */
16
17 /*
18  * History:
19  * 93/06/01     - Creation
20  * 93/10/31     - Added the -c option to change the maximal mount counts
21  * 93/12/14     - Added -l flag to list contents of superblock
22  *                M.J.E. Mol (marcel@duteca.et.tudelft.nl)
23  *                F.W. ten Wolde (franky@duteca.et.tudelft.nl)
24  * 93/12/29     - Added the -e option to change errors behavior
25  * 94/02/27     - Ported to use the ext2fs library
26  * 94/03/06     - Added the checks interval from Uwe Ohse (uwe@tirka.gun.de)
27  */
28
29 #include <fcntl.h>
30 #include <grp.h>
31 #ifdef HAVE_GETOPT_H
32 #include <getopt.h>
33 #endif
34 #include <pwd.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <time.h>
39 #include <unistd.h>
40 #include <sys/types.h>
41
42 #include <linux/ext2_fs.h>
43
44 #include "ext2fs/ext2fs.h"
45 #include "et/com_err.h"
46 #include "uuid/uuid.h"
47 #include "e2p/e2p.h"
48
49 #include "../version.h"
50
51 const char * program_name = "tune2fs";
52 char * device_name = NULL;
53 char * new_label = NULL;
54 char * new_last_mounted = NULL;
55 char * new_UUID = NULL;
56 int c_flag = 0;
57 int C_flag = 0;
58 int e_flag = 0;
59 int g_flag = 0;
60 int i_flag = 0;
61 int l_flag = 0;
62 int L_flag = 0;
63 int m_flag = 0;
64 int M_flag = 0;
65 int r_flag = 0;
66 int s_flag = -1;
67 int u_flag = 0;
68 int U_flag = 0;
69 int max_mount_count, mount_count;
70 unsigned long interval;
71 unsigned long reserved_ratio = 0;
72 unsigned long reserved_blocks = 0;
73 unsigned short errors;
74 unsigned long resgid = 0;
75 unsigned long resuid = 0;
76
77 #ifndef HAVE_STRCASECMP
78 static int strcasecmp (char *s1, char *s2)
79 {
80         while (*s1 && *s2) {
81                 int ch1 = *s1++, ch2 = *s2++;
82                 if (isupper (ch1))
83                         ch1 = tolower (ch1);
84                 if (isupper (ch2))
85                         ch2 = tolower (ch2);
86                 if (ch1 != ch2)
87                         return ch1 - ch2;
88         }
89         return *s1 ? 1 : *s2 ? -1 : 0;
90 }
91 #endif
92
93 static void usage(void)
94 {
95         fprintf(stderr, "Usage: %s [-c max-mounts-count] [-e errors-behavior] "
96                  "[-g group]\n"
97                  "\t[-i interval[d|m|w]] [-l] [-s] [-m reserved-blocks-percent]\n"
98                  "\t[-r reserved-blocks-count] [-u user] [-C mount-count]\n"
99                  "\t[-L volume-label] [-M last-mounted-dir] [-U UUID] "
100                  "device\n", program_name);
101         exit (1);
102 }
103
104 int main (int argc, char ** argv)
105 {
106         int c;
107         char * tmp;
108         errcode_t retval;
109         ext2_filsys fs;
110         struct ext2fs_sb *sb;
111         struct group * gr;
112         struct passwd * pw;
113         int open_flag = 0;
114
115         fprintf (stderr, "tune2fs %s, %s for EXT2 FS %s, %s\n",
116                  E2FSPROGS_VERSION, E2FSPROGS_DATE,
117                  EXT2FS_VERSION, EXT2FS_DATE);
118         if (argc && *argv)
119                 program_name = *argv;
120         initialize_ext2_error_table();
121         while ((c = getopt (argc, argv, "c:e:g:i:lm:r:s:u:C:L:M:U:")) != EOF)
122                 switch (c)
123                 {
124                         case 'c':
125                                 max_mount_count = strtoul (optarg, &tmp, 0);
126                                 if (*tmp || max_mount_count > 16000) {
127                                         com_err (program_name, 0,
128                                                  "bad mounts count - %s",
129                                                  optarg);
130                                         usage();
131                                 }
132                                 c_flag = 1;
133                                 open_flag = EXT2_FLAG_RW;
134                                 break;
135                         case 'C':
136                                 mount_count = strtoul (optarg, &tmp, 0);
137                                 if (*tmp || mount_count > 16000) {
138                                         com_err (program_name, 0,
139                                                  "bad mounts count - %s",
140                                                  optarg);
141                                         usage();
142                                 }
143                                 C_flag = 1;
144                                 open_flag = EXT2_FLAG_RW;
145                                 break;
146                         case 'e':
147                                 if (strcmp (optarg, "continue") == 0)
148                                         errors = EXT2_ERRORS_CONTINUE;
149                                 else if (strcmp (optarg, "remount-ro") == 0)
150                                         errors = EXT2_ERRORS_RO;
151                                 else if (strcmp (optarg, "panic") == 0)
152                                         errors = EXT2_ERRORS_PANIC;
153                                 else {
154                                         com_err (program_name, 0,
155                                                  "bad error behavior - %s",
156                                                  optarg);
157                                         usage();
158                                 }
159                                 e_flag = 1;
160                                 open_flag = EXT2_FLAG_RW;
161                                 break;
162                         case 'g':
163                                 resgid = strtoul (optarg, &tmp, 0);
164                                 if (*tmp) {
165                                         gr = getgrnam (optarg);
166                                         if (gr == NULL)
167                                                 tmp = optarg;
168                                         else {
169                                                 resgid = gr->gr_gid;
170                                                 *tmp =0;
171                                         }
172                                 }
173                                 if (*tmp) {
174                                         com_err (program_name, 0,
175                                                  "bad gid/group name - %s",
176                                                  optarg);
177                                         usage();
178                                 }
179                                 g_flag = 1;
180                                 open_flag = EXT2_FLAG_RW;
181                                 break;
182                         case 'i':
183                                 interval = strtoul (optarg, &tmp, 0);
184                                 switch (*tmp) {
185                                 case 's':
186                                         tmp++;
187                                         break;
188                                 case '\0':
189                                 case 'd':
190                                 case 'D': /* days */
191                                         interval *= 86400;
192                                         if (*tmp != '\0')
193                                                 tmp++;
194                                         break;
195                                 case 'm':
196                                 case 'M': /* months! */
197                                         interval *= 86400 * 30;
198                                         tmp++;
199                                         break;
200                                 case 'w':
201                                 case 'W': /* weeks */
202                                         interval *= 86400 * 7;
203                                         tmp++;
204                                         break;
205                                 }
206                                 if (*tmp || interval > (365 * 86400)) {
207                                         com_err (program_name, 0,
208                                                  "bad interval - %s", optarg);
209                                         usage();
210                                 }
211                                 i_flag = 1;
212                                 open_flag = EXT2_FLAG_RW;
213                                 break;
214                         case 'l':
215                                 l_flag = 1;
216                                 break;
217                         case 'L':
218                                 new_label = optarg;
219                                 L_flag = 1;
220                                 open_flag = EXT2_FLAG_RW;
221                                 break;
222                         case 'm':
223                                 reserved_ratio = strtoul (optarg, &tmp, 0);
224                                 if (*tmp || reserved_ratio > 50) {
225                                         com_err (program_name, 0,
226                                                  "bad reserved block ratio - %s",
227                                                  optarg);
228                                         usage();
229                                 }
230                                 m_flag = 1;
231                                 open_flag = EXT2_FLAG_RW;
232                                 break;
233                         case 'M':
234                                 new_last_mounted = optarg;
235                                 M_flag = 1;
236                                 open_flag = EXT2_FLAG_RW;
237                                 break;
238                         case 'r':
239                                 reserved_blocks = strtoul (optarg, &tmp, 0);
240                                 if (*tmp) {
241                                         com_err (program_name, 0,
242                                                  "bad reserved blocks count - %s",
243                                                  optarg);
244                                         usage();
245                                 }
246                                 r_flag = 1;
247                                 open_flag = EXT2_FLAG_RW;
248                                 break;
249                         case 's':
250                                 s_flag = atoi(optarg);
251                                 open_flag = EXT2_FLAG_RW;
252                                 break;
253                         case 'u':
254                                 resuid = strtoul (optarg, &tmp, 0);
255                                 if (*tmp) {
256                                         pw = getpwnam (optarg);
257                                         if (pw == NULL)
258                                                 tmp = optarg;
259                                         else {
260                                                 resuid = pw->pw_uid;
261                                                 *tmp = 0;
262                                         }
263                                 }
264                                 if (*tmp) {
265                                         com_err (program_name, 0,
266                                                  "bad uid/user name - %s",
267                                                  optarg);
268                                         usage();
269                                 }
270                                 u_flag = 1;
271                                 open_flag = EXT2_FLAG_RW;
272                                 break;
273                         case 'U':
274                                 new_UUID = optarg;
275                                 U_flag = 1;
276                                 open_flag = EXT2_FLAG_RW;
277                                 break;
278                         default:
279                                 usage();
280                 }
281         if (optind < argc - 1 || optind == argc)
282                 usage();
283         if (!open_flag && !l_flag)
284                 usage();
285         device_name = argv[optind];
286         retval = ext2fs_open (device_name, open_flag, 0, 0,
287                               unix_io_manager, &fs);
288         if (retval) {
289                 com_err (program_name, retval, "while trying to open %s",
290                          device_name);
291                 printf("Couldn't find valid filesystem superblock.\n");
292                 exit(1);
293         }
294         sb = (struct ext2fs_sb *) fs->super;
295
296         if (c_flag) {
297                 fs->super->s_max_mnt_count = max_mount_count;
298                 ext2fs_mark_super_dirty(fs);
299                 printf ("Setting maximal mount count to %d\n",
300                         max_mount_count);
301         }
302         if (C_flag) {
303                 fs->super->s_mnt_count = mount_count;
304                 ext2fs_mark_super_dirty(fs);
305                 printf ("Setting current mount count to %d\n", mount_count);
306         }
307         if (e_flag) {
308                 fs->super->s_errors = errors;
309                 ext2fs_mark_super_dirty(fs);
310                 printf ("Setting error behavior to %d\n", errors);
311         }
312         if (g_flag)
313 #ifdef  EXT2_DEF_RESGID
314         {
315                 fs->super->s_def_resgid = resgid;
316                 ext2fs_mark_super_dirty(fs);
317                 printf ("Setting reserved blocks gid to %lu\n", resgid);
318         }
319 #else
320                 com_err (program_name, 0,
321                          "The -g option is not supported by this version -- "
322                          "Recompile with a newer kernel");
323 #endif
324         if (i_flag) {
325                 fs->super->s_checkinterval = interval;
326                 ext2fs_mark_super_dirty(fs);
327                 printf ("Setting interval between check %lu seconds\n", interval);
328         }
329         if (m_flag) {
330                 fs->super->s_r_blocks_count = (fs->super->s_blocks_count / 100)
331                         * reserved_ratio;
332                 ext2fs_mark_super_dirty(fs);
333                 printf ("Setting reserved blocks percentage to %lu (%u blocks)\n",
334                         reserved_ratio, fs->super->s_r_blocks_count);
335         }
336         if (r_flag) {
337                 if (reserved_blocks >= fs->super->s_blocks_count) {
338                         com_err (program_name, 0,
339                                  "reserved blocks count is too big (%ul)",
340                                  reserved_blocks);
341                         exit (1);
342                 }
343                 fs->super->s_r_blocks_count = reserved_blocks;
344                 ext2fs_mark_super_dirty(fs);
345                 printf ("Setting reserved blocks count to %lu\n",
346                         reserved_blocks);
347         }
348         if (s_flag == 1) {
349 #ifdef EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER
350                 if (sb->s_feature_ro_compat &
351                     EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)
352                         fprintf(stderr, "\nThe filesystem already "
353                                 " has spare superblocks.\n");
354                 else {
355                         sb->s_feature_ro_compat |=
356                                 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
357                         fs->super->s_state &= ~EXT2_VALID_FS;
358                         ext2fs_mark_super_dirty(fs);
359                         printf("\nSparse superblock flag set.  "
360                                "Please run e2fsck on the filesystem.\n");
361                 }
362 #else /* !EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER */
363                 com_err (program_name, 0,
364                          "The -s option is not supported by this version -- "
365                          "Recompile with a newer kernel");
366 #endif /* EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER */
367         }
368         if (s_flag == 0) {
369 #ifdef EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER
370                 if (!(sb->s_feature_ro_compat &
371                       EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER))
372                         fprintf(stderr, "\nThe filesystem already "
373                                 " does not support spare superblocks.\n");
374                 else {
375                         sb->s_feature_ro_compat &=
376                                 ~EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
377                         fs->super->s_state &= ~EXT2_VALID_FS;
378                         fs->flags |= EXT2_FLAG_MASTER_SB_ONLY;
379                         ext2fs_mark_super_dirty(fs);
380                         printf("\nSparse superblock flag cleared.  "
381                                "Please run e2fsck on the filesystem.\n");
382                 }
383 #else /* !EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER */
384                 com_err (program_name, 0,
385                          "The -s option is not supported by this version -- "
386                          "Recompile with a newer kernel");
387 #endif /* EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER */
388         }
389         
390         if (u_flag)
391 #ifdef  EXT2_DEF_RESUID
392         {
393                 fs->super->s_def_resuid = resuid;
394                 ext2fs_mark_super_dirty(fs);
395                 printf ("Setting reserved blocks uid to %lu\n", resuid);
396         }
397 #else
398                 com_err (program_name, 0,
399                          "The -u option is not supported by this version -- "
400                          "Recompile with a newer kernel");
401 #endif
402         if (L_flag) {
403                 if (strlen(new_label) > sizeof(sb->s_volume_name))
404                         fprintf(stderr, "Warning: label too "
405                                 "long, truncating.\n");
406                 memset(sb->s_volume_name, 0, sizeof(sb->s_volume_name));
407                 strncpy(sb->s_volume_name, new_label,
408                         sizeof(sb->s_volume_name));
409                 ext2fs_mark_super_dirty(fs);
410         }
411         if (M_flag) {
412                 memset(sb->s_last_mounted, 0, sizeof(sb->s_last_mounted));
413                 strncpy(sb->s_last_mounted, new_last_mounted,
414                         sizeof(sb->s_last_mounted));
415                 ext2fs_mark_super_dirty(fs);
416         }
417         if (U_flag) {
418                 if (strcasecmp(new_UUID, "null") == 0) {
419                         uuid_clear(sb->s_uuid);
420                 } else if (strcasecmp(new_UUID, "random") == 0) {
421                         uuid_generate(sb->s_uuid);
422                 } else if (uuid_parse(new_UUID, sb->s_uuid)) {
423                         com_err(program_name, 0, "Invalid UUID format\n");
424                         exit(1);
425                 }
426                 ext2fs_mark_super_dirty(fs);
427         }
428
429         if (l_flag)
430                 list_super (fs->super);
431         ext2fs_close (fs);
432         exit (0);
433 }