Whamcloud - gitweb
196a6fe724caad934120723bc2f9c88550575f09
[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 #else
34 extern char *optarg;
35 extern int optind;
36 #endif
37 #include <pwd.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <time.h>
42 #include <unistd.h>
43 #include <sys/types.h>
44
45 #include <linux/ext2_fs.h>
46
47 #include "ext2fs/ext2fs.h"
48 #include "et/com_err.h"
49 #include "uuid/uuid.h"
50 #include "e2p/e2p.h"
51
52 #include "../version.h"
53 #include "nls-enable.h"
54
55 const char * program_name = "tune2fs";
56 char * device_name = NULL;
57 char * new_label = NULL;
58 char * new_last_mounted = NULL;
59 char * new_UUID = NULL;
60 int c_flag = 0;
61 int C_flag = 0;
62 int e_flag = 0;
63 int g_flag = 0;
64 int i_flag = 0;
65 int l_flag = 0;
66 int L_flag = 0;
67 int m_flag = 0;
68 int M_flag = 0;
69 int r_flag = 0;
70 int s_flag = -1;
71 int u_flag = 0;
72 int U_flag = 0;
73 int max_mount_count, mount_count;
74 unsigned long interval;
75 unsigned long reserved_ratio = 0;
76 unsigned long reserved_blocks = 0;
77 unsigned short errors;
78 unsigned long resgid = 0;
79 unsigned long resuid = 0;
80
81 #ifndef HAVE_STRCASECMP
82 static int strcasecmp (char *s1, char *s2)
83 {
84         while (*s1 && *s2) {
85                 int ch1 = *s1++, ch2 = *s2++;
86                 if (isupper (ch1))
87                         ch1 = tolower (ch1);
88                 if (isupper (ch2))
89                         ch2 = tolower (ch2);
90                 if (ch1 != ch2)
91                         return ch1 - ch2;
92         }
93         return *s1 ? 1 : *s2 ? -1 : 0;
94 }
95 #endif
96
97 static void usage(void)
98 {
99         fprintf(stderr, _("Usage: %s [-c max-mounts-count] [-e errors-behavior] "
100                  "[-g group]\n"
101                  "\t[-i interval[d|m|w]] [-l] [-s sparse-flag] "
102                 "[-m reserved-blocks-percent]\n"
103                  "\t[-r reserved-blocks-count] [-u user] [-C mount-count]\n"
104                  "\t[-L volume-label] [-M last-mounted-dir] [-U UUID]\n"
105                  "\t[-O [^]feature[,...]] device\n"), program_name);
106         exit (1);
107 }
108
109 static __u32 ok_features[3] = {
110         0,                                      /* Compat */
111         EXT2_FEATURE_INCOMPAT_FILETYPE,         /* Incompat */
112         EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER     /* R/O compat */
113 };
114
115 static const char *please_fsck = N_("Please run e2fsck on the filesystem.\n");
116
117 int main (int argc, char ** argv)
118 {
119         int c;
120         char * tmp;
121         errcode_t retval;
122         ext2_filsys fs;
123         struct ext2fs_sb *sb;
124         struct group * gr;
125         struct passwd * pw;
126         int open_flag = 0;
127         char *features_cmd = 0;
128
129 #ifdef ENABLE_NLS
130         setlocale(LC_MESSAGES, "");
131         bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
132         textdomain(NLS_CAT_NAME);
133 #endif
134         fprintf (stderr, _("tune2fs %s, %s for EXT2 FS %s, %s\n"),
135                  E2FSPROGS_VERSION, E2FSPROGS_DATE,
136                  EXT2FS_VERSION, EXT2FS_DATE);
137         if (argc && *argv)
138                 program_name = *argv;
139         initialize_ext2_error_table();
140         while ((c = getopt (argc, argv, "c:e:g:i:lm:r:s:u:C:L:M:O:U:")) != EOF)
141                 switch (c)
142                 {
143                         case 'c':
144                                 max_mount_count = strtol (optarg, &tmp, 0);
145                                 if (*tmp || max_mount_count > 16000) {
146                                         com_err (program_name, 0,
147                                                  _("bad mounts count - %s"),
148                                                  optarg);
149                                         usage();
150                                 }
151                                 c_flag = 1;
152                                 open_flag = EXT2_FLAG_RW;
153                                 break;
154                         case 'C':
155                                 mount_count = strtoul (optarg, &tmp, 0);
156                                 if (*tmp || mount_count > 16000) {
157                                         com_err (program_name, 0,
158                                                  _("bad mounts count - %s"),
159                                                  optarg);
160                                         usage();
161                                 }
162                                 C_flag = 1;
163                                 open_flag = EXT2_FLAG_RW;
164                                 break;
165                         case 'e':
166                                 if (strcmp (optarg, "continue") == 0)
167                                         errors = EXT2_ERRORS_CONTINUE;
168                                 else if (strcmp (optarg, "remount-ro") == 0)
169                                         errors = EXT2_ERRORS_RO;
170                                 else if (strcmp (optarg, "panic") == 0)
171                                         errors = EXT2_ERRORS_PANIC;
172                                 else {
173                                         com_err (program_name, 0,
174                                                  _("bad error behavior - %s"),
175                                                  optarg);
176                                         usage();
177                                 }
178                                 e_flag = 1;
179                                 open_flag = EXT2_FLAG_RW;
180                                 break;
181                         case 'g':
182                                 resgid = strtoul (optarg, &tmp, 0);
183                                 if (*tmp) {
184                                         gr = getgrnam (optarg);
185                                         if (gr == NULL)
186                                                 tmp = optarg;
187                                         else {
188                                                 resgid = gr->gr_gid;
189                                                 *tmp =0;
190                                         }
191                                 }
192                                 if (*tmp) {
193                                         com_err (program_name, 0,
194                                                  _("bad gid/group name - %s"),
195                                                  optarg);
196                                         usage();
197                                 }
198                                 g_flag = 1;
199                                 open_flag = EXT2_FLAG_RW;
200                                 break;
201                         case 'i':
202                                 interval = strtoul (optarg, &tmp, 0);
203                                 switch (*tmp) {
204                                 case 's':
205                                         tmp++;
206                                         break;
207                                 case '\0':
208                                 case 'd':
209                                 case 'D': /* days */
210                                         interval *= 86400;
211                                         if (*tmp != '\0')
212                                                 tmp++;
213                                         break;
214                                 case 'm':
215                                 case 'M': /* months! */
216                                         interval *= 86400 * 30;
217                                         tmp++;
218                                         break;
219                                 case 'w':
220                                 case 'W': /* weeks */
221                                         interval *= 86400 * 7;
222                                         tmp++;
223                                         break;
224                                 }
225                                 if (*tmp || interval > (365 * 86400)) {
226                                         com_err (program_name, 0,
227                                                 _("bad interval - %s"), optarg);
228                                         usage();
229                                 }
230                                 i_flag = 1;
231                                 open_flag = EXT2_FLAG_RW;
232                                 break;
233                         case 'l':
234                                 l_flag = 1;
235                                 break;
236                         case 'L':
237                                 new_label = optarg;
238                                 L_flag = 1;
239                                 open_flag = EXT2_FLAG_RW;
240                                 break;
241                         case 'm':
242                                 reserved_ratio = strtoul (optarg, &tmp, 0);
243                                 if (*tmp || reserved_ratio > 50) {
244                                         com_err (program_name, 0,
245                                                  _("bad reserved block ratio - %s"),
246                                                  optarg);
247                                         usage();
248                                 }
249                                 m_flag = 1;
250                                 open_flag = EXT2_FLAG_RW;
251                                 break;
252                         case 'M':
253                                 new_last_mounted = optarg;
254                                 M_flag = 1;
255                                 open_flag = EXT2_FLAG_RW;
256                                 break;
257                         case 'O':
258                                 features_cmd = optarg;
259                                 open_flag = EXT2_FLAG_RW;
260                                 break;
261                         case 'r':
262                                 reserved_blocks = strtoul (optarg, &tmp, 0);
263                                 if (*tmp) {
264                                         com_err (program_name, 0,
265                                                  _("bad reserved blocks count - %s"),
266                                                  optarg);
267                                         usage();
268                                 }
269                                 r_flag = 1;
270                                 open_flag = EXT2_FLAG_RW;
271                                 break;
272                         case 's':
273                                 s_flag = atoi(optarg);
274                                 open_flag = EXT2_FLAG_RW;
275                                 break;
276                         case 'u':
277                                 resuid = strtoul (optarg, &tmp, 0);
278                                 if (*tmp) {
279                                         pw = getpwnam (optarg);
280                                         if (pw == NULL)
281                                                 tmp = optarg;
282                                         else {
283                                                 resuid = pw->pw_uid;
284                                                 *tmp = 0;
285                                         }
286                                 }
287                                 if (*tmp) {
288                                         com_err (program_name, 0,
289                                                  _("bad uid/user name - %s"),
290                                                  optarg);
291                                         usage();
292                                 }
293                                 u_flag = 1;
294                                 open_flag = EXT2_FLAG_RW;
295                                 break;
296                         case 'U':
297                                 new_UUID = optarg;
298                                 U_flag = 1;
299                                 open_flag = EXT2_FLAG_RW;
300                                 break;
301                         default:
302                                 usage();
303                 }
304         if (optind < argc - 1 || optind == argc)
305                 usage();
306         if (!open_flag && !l_flag)
307                 usage();
308         device_name = argv[optind];
309         retval = ext2fs_open (device_name, open_flag, 0, 0,
310                               unix_io_manager, &fs);
311         if (retval) {
312                 com_err (program_name, retval, _("while trying to open %s"),
313                          device_name);
314                 printf(_("Couldn't find valid filesystem superblock.\n"));
315                 exit(1);
316         }
317         sb = (struct ext2fs_sb *) fs->super;
318
319         if (c_flag) {
320                 fs->super->s_max_mnt_count = max_mount_count;
321                 ext2fs_mark_super_dirty(fs);
322                 printf (_("Setting maximal mount count to %d\n"),
323                         max_mount_count);
324         }
325         if (C_flag) {
326                 fs->super->s_mnt_count = mount_count;
327                 ext2fs_mark_super_dirty(fs);
328                 printf (_("Setting current mount count to %d\n"), mount_count);
329         }
330         if (e_flag) {
331                 fs->super->s_errors = errors;
332                 ext2fs_mark_super_dirty(fs);
333                 printf (_("Setting error behavior to %d\n"), errors);
334         }
335         if (g_flag)
336 #ifdef  EXT2_DEF_RESGID
337         {
338                 fs->super->s_def_resgid = resgid;
339                 ext2fs_mark_super_dirty(fs);
340                 printf (_("Setting reserved blocks gid to %lu\n"), resgid);
341         }
342 #else
343                 com_err (program_name, 0,
344                          _("The -g option is not supported by this version -- "
345                          "Recompile with a newer kernel"));
346 #endif
347         if (i_flag) {
348                 fs->super->s_checkinterval = interval;
349                 ext2fs_mark_super_dirty(fs);
350                 printf (_("Setting interval between check %lu seconds\n"), interval);
351         }
352         if (m_flag) {
353                 fs->super->s_r_blocks_count = (fs->super->s_blocks_count / 100)
354                         * reserved_ratio;
355                 ext2fs_mark_super_dirty(fs);
356                 printf (_("Setting reserved blocks percentage to %lu (%u blocks)\n"),
357                         reserved_ratio, fs->super->s_r_blocks_count);
358         }
359         if (r_flag) {
360                 if (reserved_blocks >= fs->super->s_blocks_count) {
361                         com_err (program_name, 0,
362                                  _("reserved blocks count is too big (%ul)"),
363                                  reserved_blocks);
364                         exit (1);
365                 }
366                 fs->super->s_r_blocks_count = reserved_blocks;
367                 ext2fs_mark_super_dirty(fs);
368                 printf (_("Setting reserved blocks count to %lu\n"),
369                         reserved_blocks);
370         }
371         if (s_flag == 1) {
372 #ifdef EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER
373                 if (sb->s_feature_ro_compat &
374                     EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)
375                         fprintf(stderr, _("\nThe filesystem already"
376                                 " has sparse superblocks.\n"));
377                 else {
378                         sb->s_feature_ro_compat |=
379                                 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
380                         fs->super->s_state &= ~EXT2_VALID_FS;
381                         ext2fs_mark_super_dirty(fs);
382                         printf(_("\nSparse superblock flag set.  %s"),
383                                _(please_fsck));
384                 }
385 #else /* !EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER */
386                 com_err (program_name, 0,
387                          _("The -s option is not supported by this version -- "
388                          "Recompile with a newer kernel"));
389 #endif /* EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER */
390         }
391         if (s_flag == 0) {
392 #ifdef EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER
393                 if (!(sb->s_feature_ro_compat &
394                       EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER))
395                         fprintf(stderr, _("\nThe filesystem already"
396                                 " has sparse superblocks disabled.\n"));
397                 else {
398                         sb->s_feature_ro_compat &=
399                                 ~EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
400                         fs->super->s_state &= ~EXT2_VALID_FS;
401                         fs->flags |= EXT2_FLAG_MASTER_SB_ONLY;
402                         ext2fs_mark_super_dirty(fs);
403                         printf(_("\nSparse superblock flag cleared.  %s"),
404                                _(please_fsck));
405                 }
406 #else /* !EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER */
407                 com_err (program_name, 0,
408                          _("The -s option is not supported by this version -- "
409                          "Recompile with a newer kernel"));
410 #endif /* EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER */
411         }
412         
413         if (u_flag)
414 #ifdef  EXT2_DEF_RESUID
415         {
416                 fs->super->s_def_resuid = resuid;
417                 ext2fs_mark_super_dirty(fs);
418                 printf (_("Setting reserved blocks uid to %lu\n"), resuid);
419         }
420 #else
421                 com_err (program_name, 0,
422                          _("The -u option is not supported by this version -- "
423                          "Recompile with a newer kernel"));
424 #endif
425         if (L_flag) {
426                 if (strlen(new_label) > sizeof(sb->s_volume_name))
427                         fprintf(stderr, _("Warning: label too "
428                                 "long, truncating.\n"));
429                 memset(sb->s_volume_name, 0, sizeof(sb->s_volume_name));
430                 strncpy(sb->s_volume_name, new_label,
431                         sizeof(sb->s_volume_name));
432                 ext2fs_mark_super_dirty(fs);
433         }
434         if (M_flag) {
435                 memset(sb->s_last_mounted, 0, sizeof(sb->s_last_mounted));
436                 strncpy(sb->s_last_mounted, new_last_mounted,
437                         sizeof(sb->s_last_mounted));
438                 ext2fs_mark_super_dirty(fs);
439         }
440         if (features_cmd) {
441                 int sparse, old_sparse, filetype, old_filetype;
442
443                 old_sparse = sb->s_feature_ro_compat &
444                         EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
445                 old_filetype = sb->s_feature_incompat &
446                         EXT2_FEATURE_INCOMPAT_FILETYPE;
447                 if (e2p_edit_feature(features_cmd,
448                                      &sb->s_feature_compat,
449                                      ok_features)) {
450                         fprintf(stderr, _("Invalid filesystem option set: %s\n"),
451                                 features_cmd);
452                         exit(1);
453                 }
454                 sparse = sb->s_feature_ro_compat &
455                         EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
456                 filetype = sb->s_feature_incompat &
457                         EXT2_FEATURE_INCOMPAT_FILETYPE;
458                 if ((sparse != old_sparse) ||
459                     (filetype != old_filetype)) {
460                         fs->super->s_state &= ~EXT2_VALID_FS;
461                         printf("\n%s\n", _(please_fsck));
462                 }
463                 ext2fs_mark_super_dirty(fs);
464         }
465         if (U_flag) {
466                 if (strcasecmp(new_UUID, "null") == 0) {
467                         uuid_clear(sb->s_uuid);
468                 } else if (strcasecmp(new_UUID, "random") == 0) {
469                         uuid_generate(sb->s_uuid);
470                 } else if (uuid_parse(new_UUID, sb->s_uuid)) {
471                         com_err(program_name, 0, _("Invalid UUID format\n"));
472                         exit(1);
473                 }
474                 ext2fs_mark_super_dirty(fs);
475         }
476
477         if (l_flag)
478                 list_super (fs->super);
479         ext2fs_close (fs);
480         exit (0);
481 }