Whamcloud - gitweb
Various portability fixes for Solaris systems.
[tools/e2fsprogs.git] / misc / tune2fs.c
1 /*
2  * tune2fs.c - Change the file system parameters on an ext2 file system
3  *
4  * Copyright (C) 1992, 1993, 1994  Remy Card <card@masi.ibp.fr>
5  *                                 Laboratoire MASI, Institut Blaise Pascal
6  *                                 Universite Pierre et Marie Curie (Paris VI)
7  *
8  * Copyright 1995, 1996, 1997, 1998, 1999, 2000 by Theodore Ts'o.
9  *
10  * %Begin-Header%
11  * This file may be redistributed under the terms of the GNU Public
12  * License.
13  * %End-Header%
14  */
15
16 /*
17  * History:
18  * 93/06/01     - Creation
19  * 93/10/31     - Added the -c option to change the maximal mount counts
20  * 93/12/14     - Added -l flag to list contents of superblock
21  *                M.J.E. Mol (marcel@duteca.et.tudelft.nl)
22  *                F.W. ten Wolde (franky@duteca.et.tudelft.nl)
23  * 93/12/29     - Added the -e option to change errors behavior
24  * 94/02/27     - Ported to use the ext2fs library
25  * 94/03/06     - Added the checks interval from Uwe Ohse (uwe@tirka.gun.de)
26  */
27
28 #ifndef __sun__
29         /* Solaris for a strange reason drops struct 
30            timeval if _XOPEN_SOURCE defined */
31 #define _XOPEN_SOURCE /* for inclusion of strptime() */
32 #endif
33 #define _BSD_SOURCE /* for inclusion of strcasecmp() */
34 #include <fcntl.h>
35 #include <grp.h>
36 #ifdef HAVE_GETOPT_H
37 #include <getopt.h>
38 #else
39 extern char *optarg;
40 extern int optind;
41 #endif
42 #include <pwd.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <time.h>
47 #include <unistd.h>
48 #include <sys/types.h>
49
50 #include "ext2fs/ext2_fs.h"
51 #include "ext2fs/ext2fs.h"
52 #include "et/com_err.h"
53 #include "uuid/uuid.h"
54 #include "e2p/e2p.h"
55 #include "jfs_user.h"
56 #include "util.h"
57 #include "blkid/blkid.h"
58
59 #include "../version.h"
60 #include "nls-enable.h"
61
62 const char * program_name = "tune2fs";
63 char * device_name;
64 char * new_label, *new_last_mounted, *new_UUID;
65 char * io_options;
66 static int c_flag, C_flag, e_flag, f_flag, g_flag, i_flag, l_flag, L_flag;
67 static int m_flag, M_flag, r_flag, s_flag = -1, u_flag, U_flag, T_flag;
68 static time_t last_check_time;
69 static int print_label;
70 static int max_mount_count, mount_count, mount_flags;
71 static unsigned long interval, reserved_ratio, reserved_blocks;
72 static unsigned long resgid, resuid;
73 static unsigned short errors;
74 static int open_flag;
75 static char *features_cmd;
76 static char *mntopts_cmd;
77
78 int journal_size, journal_flags;
79 char *journal_device;
80
81 static const char *please_fsck = N_("Please run e2fsck on the filesystem.\n");
82
83 void do_findfs(int argc, char **argv);
84
85 static void usage(void)
86 {
87         fprintf(stderr,
88                 _("Usage: %s [-c max-mounts-count] [-e errors-behavior] "
89                   "[-g group]\n"
90                   "\t[-i interval[d|m|w]] [-j] [-J journal-options]\n"
91                   "\t[-l] [-s sparse-flag] [-m reserved-blocks-percent]\n"
92                   "\t[-o [^]mount-options[,...]] [-r reserved-blocks-count]\n"
93                   "\t[-u user] [-C mount-count] [-L volume-label] "
94                   "[-M last-mounted-dir]\n"
95                   "\t[-O [^]feature[,...]] [-T last-check-time] [-U UUID]"
96                   " device\n"), program_name);
97         exit (1);
98 }
99
100 static __u32 ok_features[3] = {
101         EXT3_FEATURE_COMPAT_HAS_JOURNAL |
102                 EXT2_FEATURE_COMPAT_DIR_INDEX,  /* Compat */
103         EXT2_FEATURE_INCOMPAT_FILETYPE,         /* Incompat */
104         EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER     /* R/O compat */
105 };
106
107 /*
108  * Remove an external journal from the filesystem
109  */
110 static void remove_journal_device(ext2_filsys fs)
111 {
112         char            *journal_path;
113         ext2_filsys     jfs;
114         char            buf[1024];
115         journal_superblock_t    *jsb;
116         int             i, nr_users;
117         errcode_t       retval;
118         int             commit_remove_journal = 0;
119         io_manager      io_ptr;
120
121         if (f_flag)
122                 commit_remove_journal = 1; /* force removal even if error */
123
124         uuid_unparse(fs->super->s_journal_uuid, buf);
125         journal_path = blkid_get_devname(NULL, "UUID", buf);
126
127         if (!journal_path) {
128                 journal_path =
129                         ext2fs_find_block_device(fs->super->s_journal_dev);
130                 if (!journal_path)
131                         return;
132         }
133
134 #ifdef CONFIG_TESTIO_DEBUG
135         io_ptr = test_io_manager;
136         test_io_backing_manager = unix_io_manager;
137 #else
138         io_ptr = unix_io_manager;
139 #endif
140         retval = ext2fs_open(journal_path, EXT2_FLAG_RW|
141                              EXT2_FLAG_JOURNAL_DEV_OK, 0,
142                              fs->blocksize, io_ptr, &jfs);
143         if (retval) {
144                 com_err(program_name, retval,
145                         _("while trying to open external journal"));
146                 goto no_valid_journal;
147         }
148         if (!(jfs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) {
149                 fprintf(stderr, _("%s is not a journal device.\n"),
150                         journal_path);
151                 goto no_valid_journal;
152         }
153
154         /* Get the journal superblock */
155         if ((retval = io_channel_read_blk(jfs->io, 1, -1024, buf))) {
156                 com_err(program_name, retval,
157                         _("while reading journal superblock"));
158                 goto no_valid_journal;
159         }
160
161         jsb = (journal_superblock_t *) buf;
162         if ((jsb->s_header.h_magic != (unsigned) ntohl(JFS_MAGIC_NUMBER)) ||
163             (jsb->s_header.h_blocktype != (unsigned) ntohl(JFS_SUPERBLOCK_V2))) {
164                 fputs(_("Journal superblock not found!\n"), stderr);
165                 goto no_valid_journal;
166         }
167
168         /* Find the filesystem UUID */
169         nr_users = ntohl(jsb->s_nr_users);
170         for (i=0; i < nr_users; i++) {
171                 if (memcmp(fs->super->s_uuid,
172                            &jsb->s_users[i*16], 16) == 0)
173                         break;
174         }
175         if (i >= nr_users) {
176                 fputs(_("Filesystem's UUID not found on journal device.\n"), 
177                       stderr);
178                 commit_remove_journal = 1;
179                 goto no_valid_journal;
180         }
181         nr_users--;
182         for (i=0; i < nr_users; i++)
183                 memcpy(&jsb->s_users[i*16], &jsb->s_users[(i+1)*16], 16);
184         jsb->s_nr_users = htonl(nr_users);
185
186         /* Write back the journal superblock */
187         if ((retval = io_channel_write_blk(jfs->io, 1, -1024, buf))) {
188                 com_err(program_name, retval,
189                         "while writing journal superblock.");
190                 goto no_valid_journal;
191         }
192
193         commit_remove_journal = 1;
194
195 no_valid_journal:
196         if (commit_remove_journal == 0) {
197                 fputs(_("Journal NOT removed\n"), stderr);
198                 exit(1);
199         }
200         fs->super->s_journal_dev = 0;
201         uuid_clear(fs->super->s_journal_uuid);
202         ext2fs_mark_super_dirty(fs);
203         fputs(_("Journal removed\n"), stdout);
204         free(journal_path);
205 }
206
207 /* Helper function for remove_journal_inode */
208 static int release_blocks_proc(ext2_filsys fs, blk_t *blocknr,
209                                int blockcnt EXT2FS_ATTR((unused)), 
210                                void *private EXT2FS_ATTR((unused)))
211 {
212         blk_t   block;
213         int     group;
214
215         block = *blocknr;
216         ext2fs_unmark_block_bitmap(fs->block_map,block);
217         group = ext2fs_group_of_blk(fs, block);
218         fs->group_desc[group].bg_free_blocks_count++;
219         fs->super->s_free_blocks_count++;
220         return 0;
221 }
222
223 /*
224  * Remove the journal inode from the filesystem
225  */
226 static void remove_journal_inode(ext2_filsys fs)
227 {
228         struct ext2_inode       inode;
229         errcode_t               retval;
230         ino_t                   ino = fs->super->s_journal_inum;
231         
232         retval = ext2fs_read_inode(fs, ino,  &inode);
233         if (retval) {
234                 com_err(program_name, retval,
235                         _("while reading journal inode"));
236                 exit(1);
237         }
238         if (ino == EXT2_JOURNAL_INO) {
239                 retval = ext2fs_read_bitmaps(fs);
240                 if (retval) {
241                         com_err(program_name, retval,
242                                 _("while reading bitmaps"));
243                         exit(1);
244                 }
245                 retval = ext2fs_block_iterate(fs, ino, 0, NULL,
246                                               release_blocks_proc, NULL);
247                 if (retval) {
248                         com_err(program_name, retval,
249                                 _("while clearing journal inode"));
250                         exit(1);
251                 }
252                 memset(&inode, 0, sizeof(inode));
253                 ext2fs_mark_bb_dirty(fs);
254                 fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
255         } else
256                 inode.i_flags &= ~EXT2_IMMUTABLE_FL;
257         retval = ext2fs_write_inode(fs, ino, &inode);
258         if (retval) {
259                 com_err(program_name, retval,
260                         _("while writing journal inode"));
261                 exit(1);
262         }
263         fs->super->s_journal_inum = 0;
264         ext2fs_mark_super_dirty(fs);
265 }
266
267 /*
268  * Update the default mount options
269  */
270 static void update_mntopts(ext2_filsys fs, char *mntopts)
271 {
272         struct ext2_super_block *sb= fs->super;
273
274         if (e2p_edit_mntopts(mntopts, &sb->s_default_mount_opts, ~0)) {
275                 fprintf(stderr, _("Invalid mount option set: %s\n"),
276                         mntopts);
277                 exit(1);
278         }
279         ext2fs_mark_super_dirty(fs);
280 }
281
282 /*
283  * Update the feature set as provided by the user.
284  */
285 static void update_feature_set(ext2_filsys fs, char *features)
286 {
287         int sparse, old_sparse, filetype, old_filetype;
288         int journal, old_journal, dxdir, old_dxdir;
289         struct ext2_super_block *sb= fs->super;
290         __u32   old_compat, old_incompat, old_ro_compat;
291
292         old_compat = sb->s_feature_compat;
293         old_ro_compat = sb->s_feature_ro_compat;
294         old_incompat = sb->s_feature_incompat;
295
296         old_sparse = sb->s_feature_ro_compat &
297                 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
298         old_filetype = sb->s_feature_incompat &
299                 EXT2_FEATURE_INCOMPAT_FILETYPE;
300         old_journal = sb->s_feature_compat &
301                 EXT3_FEATURE_COMPAT_HAS_JOURNAL;
302         old_dxdir = sb->s_feature_compat &
303                 EXT2_FEATURE_COMPAT_DIR_INDEX;
304         if (e2p_edit_feature(features, &sb->s_feature_compat,
305                              ok_features)) {
306                 fprintf(stderr, _("Invalid filesystem option set: %s\n"),
307                         features);
308                 exit(1);
309         }
310         sparse = sb->s_feature_ro_compat &
311                 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
312         filetype = sb->s_feature_incompat &
313                 EXT2_FEATURE_INCOMPAT_FILETYPE;
314         journal = sb->s_feature_compat &
315                 EXT3_FEATURE_COMPAT_HAS_JOURNAL;
316         dxdir = sb->s_feature_compat &
317                 EXT2_FEATURE_COMPAT_DIR_INDEX;
318         if (old_journal && !journal) {
319                 if ((mount_flags & EXT2_MF_MOUNTED) &&
320                     !(mount_flags & EXT2_MF_READONLY)) {
321                         fputs(_("The has_journal flag may only be "
322                                 "cleared when the filesystem is\n"
323                                 "unmounted or mounted "
324                                 "read-only.\n"), stderr);
325                         exit(1);
326                 }
327                 if (sb->s_feature_incompat &
328                     EXT3_FEATURE_INCOMPAT_RECOVER) {
329                         fputs(_("The needs_recovery flag is set.  "
330                                 "Please run e2fsck before clearing\n"
331                                 "the has_journal flag.\n"), stderr);
332                         exit(1);
333                 }
334                 if (sb->s_journal_inum) {
335                         remove_journal_inode(fs);
336                 }
337                 if (sb->s_journal_dev) {
338                         remove_journal_device(fs);
339                 }
340         }
341         if (journal && !old_journal) {
342                 /*
343                  * If adding a journal flag, let the create journal
344                  * code below handle creating setting the flag and
345                  * creating the journal.  We supply a default size if
346                  * necessary.
347                  */
348                 if (!journal_size)
349                         journal_size = -1;
350                 sb->s_feature_compat &= ~EXT3_FEATURE_COMPAT_HAS_JOURNAL;
351         }
352         if (dxdir && !old_dxdir) {
353                 if (!sb->s_def_hash_version)
354                         sb->s_def_hash_version = EXT2_HASH_TEA;
355                 if (uuid_is_null((unsigned char *) sb->s_hash_seed))
356                         uuid_generate((unsigned char *) sb->s_hash_seed);
357         }
358
359         if (sb->s_rev_level == EXT2_GOOD_OLD_REV &&
360             (sb->s_feature_compat || sb->s_feature_ro_compat ||
361              sb->s_feature_incompat))
362                 ext2fs_update_dynamic_rev(fs);
363         if ((sparse != old_sparse) ||
364             (filetype != old_filetype)) {
365                 sb->s_state &= ~EXT2_VALID_FS;
366                 printf("\n%s\n", _(please_fsck));
367         }
368         if ((old_compat != sb->s_feature_compat) ||
369             (old_ro_compat != sb->s_feature_ro_compat) ||
370             (old_incompat != sb->s_feature_incompat))
371                 ext2fs_mark_super_dirty(fs);
372 }
373
374 /*
375  * Add a journal to the filesystem.
376  */
377 static void add_journal(ext2_filsys fs)
378 {
379         unsigned long journal_blocks;
380         errcode_t       retval;
381         ext2_filsys     jfs;
382         io_manager      io_ptr;
383
384         if (fs->super->s_feature_compat &
385             EXT3_FEATURE_COMPAT_HAS_JOURNAL) {
386                 fputs(_("The filesystem already has a journal.\n"), stderr);
387                 goto err;
388         }
389         if (journal_device) {
390                 check_plausibility(journal_device);
391                 check_mount(journal_device, 0, _("journal"));
392 #ifdef CONFIG_TESTIO_DEBUG
393                 io_ptr = test_io_manager;
394                 test_io_backing_manager = unix_io_manager;
395 #else
396                 io_ptr = unix_io_manager;
397 #endif
398                 retval = ext2fs_open(journal_device, EXT2_FLAG_RW|
399                                      EXT2_FLAG_JOURNAL_DEV_OK, 0,
400                                      fs->blocksize, io_ptr, &jfs);
401                 if (retval) {
402                         com_err(program_name, retval,
403                                 _("\n\twhile trying to open journal on %s\n"),
404                                 journal_device);
405                         goto err;
406                 }
407                 printf(_("Creating journal on device %s: "),
408                        journal_device);
409                 fflush(stdout);
410
411                 retval = ext2fs_add_journal_device(fs, jfs);
412                 ext2fs_close(jfs);
413                 if (retval) {
414                         com_err (program_name, retval,
415                                  _("while adding filesystem to journal on %s"),
416                                  journal_device);
417                         goto err;
418                 }
419                 fputs(_("done\n"), stdout);
420         } else if (journal_size) {
421                 fputs(_("Creating journal inode: "), stdout);
422                 fflush(stdout);
423                 journal_blocks = figure_journal_size(journal_size, fs);
424
425                 retval = ext2fs_add_journal_inode(fs, journal_blocks,
426                                                   journal_flags);
427                 if (retval) {
428                         fprintf(stderr, "\n");
429                         com_err(program_name, retval,
430                                 _("\n\twhile trying to create journal file"));
431                         exit(1);
432                 } else
433                         fputs(_("done\n"), stdout);
434                 /*
435                  * If the filesystem wasn't mounted, we need to force
436                  * the block group descriptors out.
437                  */
438                 if ((mount_flags & EXT2_MF_MOUNTED) == 0)
439                         fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
440         }
441         print_check_message(fs);
442         return;
443
444 err:
445         if (journal_device)
446                 free(journal_device);
447         exit(1);
448 }
449
450
451 static void parse_e2label_options(int argc, char ** argv)
452 {
453         if ((argc < 2) || (argc > 3)) {
454                 fputs(_("Usage: e2label device [newlabel]\n"), stderr);
455                 exit(1);
456         }
457         io_options = strchr(argv[1], '?');
458         if (io_options)
459                 *io_options++ = 0;
460         device_name = blkid_get_devname(NULL, argv[1], NULL);
461         if (!device_name) {
462                 com_err("e2label", 0, _("Unable to resolve '%s'"), 
463                         argv[1]);
464                 exit(1);
465         }
466         if (argc == 3) {
467                 open_flag = EXT2_FLAG_RW | EXT2_FLAG_JOURNAL_DEV_OK;
468                 L_flag = 1;
469                 new_label = argv[2];
470         } else 
471                 print_label++;
472 }
473
474 static time_t parse_time(char *str)
475 {
476         struct  tm      ts;
477
478         if (strcmp(str, "now") == 0) {
479                 return (time(0));
480         }
481         memset(&ts, 0, sizeof(ts));
482 #ifdef HAVE_STRPTIME
483         strptime(str, "%Y%m%d%H%M%S", &ts);
484 #else
485         sscanf(str, "%4d%2d%2d%2d%2d%2d", &ts.tm_year, &ts.tm_mon,
486                &ts.tm_mday, &ts.tm_hour, &ts.tm_min, &ts.tm_sec);
487         ts.tm_year -= 1900;
488         ts.tm_mon -= 1;
489         if (ts.tm_year < 0 || ts.tm_mon < 0 || ts.tm_mon > 11 ||
490             ts.tm_mday < 0 || ts.tm_mday > 31 || ts.tm_hour > 23 ||
491             ts.tm_min > 59 || ts.tm_sec > 61)
492                 ts.tm_mday = 0;
493 #endif
494         if (ts.tm_mday == 0) {
495                 com_err(program_name, 0,
496                         _("Couldn't parse date/time specifier: %s"),
497                         str);
498                 usage();
499         }
500         return (mktime(&ts));
501 }
502
503 static void parse_tune2fs_options(int argc, char **argv)
504 {
505         int c;
506         char * tmp;
507         struct group * gr;
508         struct passwd * pw;
509
510         printf("tune2fs %s (%s)\n", E2FSPROGS_VERSION, E2FSPROGS_DATE);
511         while ((c = getopt(argc, argv, "c:e:fg:i:jlm:o:r:s:u:C:J:L:M:O:T:U:")) != EOF)
512                 switch (c)
513                 {
514                         case 'c':
515                                 max_mount_count = strtol (optarg, &tmp, 0);
516                                 if (*tmp || max_mount_count > 16000) {
517                                         com_err (program_name, 0,
518                                                  _("bad mounts count - %s"),
519                                                  optarg);
520                                         usage();
521                                 }
522                                 if (max_mount_count == 0)
523                                         max_mount_count = -1;
524                                 c_flag = 1;
525                                 open_flag = EXT2_FLAG_RW;
526                                 break;
527                         case 'C':
528                                 mount_count = strtoul (optarg, &tmp, 0);
529                                 if (*tmp || mount_count > 16000) {
530                                         com_err (program_name, 0,
531                                                  _("bad mounts count - %s"),
532                                                  optarg);
533                                         usage();
534                                 }
535                                 C_flag = 1;
536                                 open_flag = EXT2_FLAG_RW;
537                                 break;
538                         case 'e':
539                                 if (strcmp (optarg, "continue") == 0)
540                                         errors = EXT2_ERRORS_CONTINUE;
541                                 else if (strcmp (optarg, "remount-ro") == 0)
542                                         errors = EXT2_ERRORS_RO;
543                                 else if (strcmp (optarg, "panic") == 0)
544                                         errors = EXT2_ERRORS_PANIC;
545                                 else {
546                                         com_err (program_name, 0,
547                                                  _("bad error behavior - %s"),
548                                                  optarg);
549                                         usage();
550                                 }
551                                 e_flag = 1;
552                                 open_flag = EXT2_FLAG_RW;
553                                 break;
554                         case 'f': /* Force */
555                                 f_flag = 1;
556                                 break;
557                         case 'g':
558                                 resgid = strtoul (optarg, &tmp, 0);
559                                 if (*tmp) {
560                                         gr = getgrnam (optarg);
561                                         if (gr == NULL)
562                                                 tmp = optarg;
563                                         else {
564                                                 resgid = gr->gr_gid;
565                                                 *tmp =0;
566                                         }
567                                 }
568                                 if (*tmp) {
569                                         com_err (program_name, 0,
570                                                  _("bad gid/group name - %s"),
571                                                  optarg);
572                                         usage();
573                                 }
574                                 g_flag = 1;
575                                 open_flag = EXT2_FLAG_RW;
576                                 break;
577                         case 'i':
578                                 interval = strtoul (optarg, &tmp, 0);
579                                 switch (*tmp) {
580                                 case 's':
581                                         tmp++;
582                                         break;
583                                 case '\0':
584                                 case 'd':
585                                 case 'D': /* days */
586                                         interval *= 86400;
587                                         if (*tmp != '\0')
588                                                 tmp++;
589                                         break;
590                                 case 'm':
591                                 case 'M': /* months! */
592                                         interval *= 86400 * 30;
593                                         tmp++;
594                                         break;
595                                 case 'w':
596                                 case 'W': /* weeks */
597                                         interval *= 86400 * 7;
598                                         tmp++;
599                                         break;
600                                 }
601                                 if (*tmp || interval > (365 * 86400)) {
602                                         com_err (program_name, 0,
603                                                 _("bad interval - %s"), optarg);
604                                         usage();
605                                 }
606                                 i_flag = 1;
607                                 open_flag = EXT2_FLAG_RW;
608                                 break;
609                         case 'j':
610                                 if (!journal_size)
611                                         journal_size = -1;
612                                 open_flag = EXT2_FLAG_RW;
613                                 break;
614                         case 'J':
615                                 parse_journal_opts(optarg);
616                                 open_flag = EXT2_FLAG_RW;
617                                 break;
618                         case 'l':
619                                 l_flag = 1;
620                                 break;
621                         case 'L':
622                                 new_label = optarg;
623                                 L_flag = 1;
624                                 open_flag = EXT2_FLAG_RW |
625                                         EXT2_FLAG_JOURNAL_DEV_OK;
626                                 break;
627                         case 'm':
628                                 reserved_ratio = strtoul (optarg, &tmp, 0);
629                                 if (*tmp || reserved_ratio > 50) {
630                                         com_err (program_name, 0,
631                                                  _("bad reserved block ratio - %s"),
632                                                  optarg);
633                                         usage();
634                                 }
635                                 m_flag = 1;
636                                 open_flag = EXT2_FLAG_RW;
637                                 break;
638                         case 'M':
639                                 new_last_mounted = optarg;
640                                 M_flag = 1;
641                                 open_flag = EXT2_FLAG_RW;
642                                 break;
643                         case 'o':
644                                 if (mntopts_cmd) {
645                                         com_err (program_name, 0,
646                                          _("-o may only be specified once"));
647                                         usage();
648                                 }
649                                 mntopts_cmd = optarg;
650                                 open_flag = EXT2_FLAG_RW;
651                                 break;
652                                 
653                         case 'O':
654                                 if (features_cmd) {
655                                         com_err (program_name, 0,
656                                          _("-O may only be specified once"));
657                                         usage();
658                                 }
659                                 features_cmd = optarg;
660                                 open_flag = EXT2_FLAG_RW;
661                                 break;
662                         case 'r':
663                                 reserved_blocks = strtoul (optarg, &tmp, 0);
664                                 if (*tmp) {
665                                         com_err (program_name, 0,
666                                                  _("bad reserved blocks count - %s"),
667                                                  optarg);
668                                         usage();
669                                 }
670                                 r_flag = 1;
671                                 open_flag = EXT2_FLAG_RW;
672                                 break;
673                         case 's':
674                                 s_flag = atoi(optarg);
675                                 open_flag = EXT2_FLAG_RW;
676                                 break;
677                         case 'T':
678                                 T_flag = 1;
679                                 last_check_time = parse_time(optarg);
680                                 open_flag = EXT2_FLAG_RW;
681                                 break;
682                         case 'u':
683                                 resuid = strtoul (optarg, &tmp, 0);
684                                 if (*tmp) {
685                                         pw = getpwnam (optarg);
686                                         if (pw == NULL)
687                                                 tmp = optarg;
688                                         else {
689                                                 resuid = pw->pw_uid;
690                                                 *tmp = 0;
691                                         }
692                                 }
693                                 if (*tmp) {
694                                         com_err (program_name, 0,
695                                                  _("bad uid/user name - %s"),
696                                                  optarg);
697                                         usage();
698                                 }
699                                 u_flag = 1;
700                                 open_flag = EXT2_FLAG_RW;
701                                 break;
702                         case 'U':
703                                 new_UUID = optarg;
704                                 U_flag = 1;
705                                 open_flag = EXT2_FLAG_RW |
706                                         EXT2_FLAG_JOURNAL_DEV_OK;
707                                 break;
708                         default:
709                                 usage();
710                 }
711         if (optind < argc - 1 || optind == argc)
712                 usage();
713         if (!open_flag && !l_flag)
714                 usage();
715         io_options = strchr(argv[optind], '?');
716         if (io_options)
717                 *io_options++ = 0;
718         device_name = blkid_get_devname(NULL, argv[optind], NULL);
719         if (!device_name) {
720                 com_err("tune2fs", 0, _("Unable to resolve '%s'"), 
721                         argv[optind]);
722                 exit(1);
723         }
724 }
725
726 void do_findfs(int argc, char **argv)
727 {
728         char    *dev;
729
730         if ((argc != 2) ||
731             (strncmp(argv[1], "LABEL=", 6) && strncmp(argv[1], "UUID=", 5))) {
732                 fprintf(stderr, "Usage: findfs LABEL=<label>|UUID=<uuid>\n");
733                 exit(2);
734         }
735         dev = blkid_get_devname(NULL, argv[1], NULL);
736         if (!dev) {
737                 com_err("findfs", 0, _("Unable to resolve '%s'"), 
738                         argv[1]);
739                 exit(1);
740         }
741         puts(dev);
742         exit(0);
743 }
744
745
746 int main (int argc, char ** argv)
747 {
748         errcode_t retval;
749         ext2_filsys fs;
750         struct ext2_super_block *sb;
751         io_manager io_ptr;
752
753 #ifdef ENABLE_NLS
754         setlocale(LC_MESSAGES, "");
755         setlocale(LC_CTYPE, "");
756         bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
757         textdomain(NLS_CAT_NAME);
758 #endif
759         if (argc && *argv)
760                 program_name = *argv;
761         initialize_ext2_error_table();
762
763         if (strcmp(get_progname(argv[0]), "findfs") == 0)
764                 do_findfs(argc, argv);
765         if (strcmp(get_progname(argv[0]), "e2label") == 0)
766                 parse_e2label_options(argc, argv);
767         else
768                 parse_tune2fs_options(argc, argv);
769         
770 #ifdef CONFIG_TESTIO_DEBUG
771         io_ptr = test_io_manager;
772         test_io_backing_manager = unix_io_manager;
773 #else
774         io_ptr = unix_io_manager;
775 #endif
776         retval = ext2fs_open2(device_name, io_options, open_flag, 
777                               0, 0, io_ptr, &fs);
778         if (retval) {
779                 com_err (program_name, retval, _("while trying to open %s"),
780                          device_name);
781                 fprintf(stderr,
782                         _("Couldn't find valid filesystem superblock.\n"));
783                 exit(1);
784         }
785         sb = fs->super;
786         if (print_label) {
787                 /* For e2label emulation */
788                 printf("%.*s\n", (int) sizeof(sb->s_volume_name),
789                        sb->s_volume_name);
790                 exit(0);
791         }
792         retval = ext2fs_check_if_mounted(device_name, &mount_flags);
793         if (retval) {
794                 com_err("ext2fs_check_if_mount", retval,
795                         _("while determining whether %s is mounted."),
796                         device_name);
797                 exit(1);
798         }
799         /* Normally we only need to write out the superblock */
800         fs->flags |= EXT2_FLAG_SUPER_ONLY;
801
802         if (c_flag) {
803                 sb->s_max_mnt_count = max_mount_count;
804                 ext2fs_mark_super_dirty(fs);
805                 printf (_("Setting maximal mount count to %d\n"),
806                         max_mount_count);
807         }
808         if (C_flag) {
809                 sb->s_mnt_count = mount_count;
810                 ext2fs_mark_super_dirty(fs);
811                 printf (_("Setting current mount count to %d\n"), mount_count);
812         }
813         if (e_flag) {
814                 sb->s_errors = errors;
815                 ext2fs_mark_super_dirty(fs);
816                 printf (_("Setting error behavior to %d\n"), errors);
817         }
818         if (g_flag) {
819                 sb->s_def_resgid = resgid;
820                 ext2fs_mark_super_dirty(fs);
821                 printf (_("Setting reserved blocks gid to %lu\n"), resgid);
822         }
823         if (i_flag) {
824                 sb->s_checkinterval = interval;
825                 ext2fs_mark_super_dirty(fs);
826                 printf (_("Setting interval between check %lu seconds\n"), interval);
827         }
828         if (m_flag) {
829                 sb->s_r_blocks_count = (sb->s_blocks_count / 100)
830                         * reserved_ratio;
831                 ext2fs_mark_super_dirty(fs);
832                 printf (_("Setting reserved blocks percentage to %lu (%u blocks)\n"),
833                         reserved_ratio, sb->s_r_blocks_count);
834         }
835         if (r_flag) {
836                 if (reserved_blocks >= sb->s_blocks_count/2) {
837                         com_err (program_name, 0,
838                                  _("reserved blocks count is too big (%lu)"),
839                                  reserved_blocks);
840                         exit (1);
841                 }
842                 sb->s_r_blocks_count = reserved_blocks;
843                 ext2fs_mark_super_dirty(fs);
844                 printf (_("Setting reserved blocks count to %lu\n"),
845                         reserved_blocks);
846         }
847         if (s_flag == 1) {
848                 if (sb->s_feature_ro_compat &
849                     EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)
850                         fputs(_("\nThe filesystem already has sparse "
851                                 "superblocks.\n"), stderr);
852                 else {
853                         sb->s_feature_ro_compat |=
854                                 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
855                         sb->s_state &= ~EXT2_VALID_FS;
856                         ext2fs_mark_super_dirty(fs);
857                         printf(_("\nSparse superblock flag set.  %s"),
858                                _(please_fsck));
859                 }
860         }
861         if (s_flag == 0) {
862                 if (!(sb->s_feature_ro_compat &
863                       EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER))
864                         fputs(_("\nThe filesystem already has sparse "
865                                 "superblocks disabled.\n"), stderr);
866                 else {
867                         sb->s_feature_ro_compat &=
868                                 ~EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
869                         sb->s_state &= ~EXT2_VALID_FS;
870                         fs->flags |= EXT2_FLAG_MASTER_SB_ONLY;
871                         ext2fs_mark_super_dirty(fs);
872                         printf(_("\nSparse superblock flag cleared.  %s"),
873                                _(please_fsck));
874                 }
875         }
876         if (T_flag) {
877                 sb->s_lastcheck = last_check_time;
878                 ext2fs_mark_super_dirty(fs);
879                 printf(_("Setting time filesystem last checked to %s\n"),
880                        ctime(&last_check_time));
881         }
882         if (u_flag) {
883                 sb->s_def_resuid = resuid;
884                 ext2fs_mark_super_dirty(fs);
885                 printf (_("Setting reserved blocks uid to %lu\n"), resuid);
886         }
887         if (L_flag) {
888                 if (strlen(new_label) > sizeof(sb->s_volume_name))
889                         fputs(_("Warning: label too long, truncating.\n"), 
890                               stderr);
891                 memset(sb->s_volume_name, 0, sizeof(sb->s_volume_name));
892                 strncpy(sb->s_volume_name, new_label,
893                         sizeof(sb->s_volume_name));
894                 ext2fs_mark_super_dirty(fs);
895         }
896         if (M_flag) {
897                 memset(sb->s_last_mounted, 0, sizeof(sb->s_last_mounted));
898                 strncpy(sb->s_last_mounted, new_last_mounted,
899                         sizeof(sb->s_last_mounted));
900                 ext2fs_mark_super_dirty(fs);
901         }
902         if (mntopts_cmd)
903                 update_mntopts(fs, mntopts_cmd);
904         if (features_cmd)
905                 update_feature_set(fs, features_cmd);
906         if (journal_size || journal_device)
907                 add_journal(fs);
908         
909         if (U_flag) {
910                 if ((strcasecmp(new_UUID, "null") == 0) ||
911                     (strcasecmp(new_UUID, "clear") == 0)) {
912                         uuid_clear(sb->s_uuid);
913                 } else if (strcasecmp(new_UUID, "time") == 0) {
914                         uuid_generate_time(sb->s_uuid);
915                 } else if (strcasecmp(new_UUID, "random") == 0) {
916                         uuid_generate(sb->s_uuid);
917                 } else if (uuid_parse(new_UUID, sb->s_uuid)) {
918                         com_err(program_name, 0, _("Invalid UUID format\n"));
919                         exit(1);
920                 }
921                 ext2fs_mark_super_dirty(fs);
922         }
923
924         if (l_flag)
925                 list_super (sb);
926         return (ext2fs_close (fs) ? 1 : 0);
927 }