util.c revision 3f65f1acaa1f32740fdbc03affe3dc95f9668bad
1/*
2 * util.c --- miscellaneous utilities
3 *
4 * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12#include <stdlib.h>
13#include <unistd.h>
14#include <string.h>
15#include <ctype.h>
16
17#ifdef HAVE_CONIO_H
18#undef HAVE_TERMIOS_H
19#include <conio.h>
20#define read_a_char()	getch()
21#else
22#ifdef HAVE_TERMIOS_H
23#include <termios.h>
24#endif
25#include <stdio.h>
26#define read_a_char()	getchar()
27#endif
28
29#ifdef HAVE_MALLOC_H
30#include <malloc.h>
31#endif
32
33#include "e2fsck.h"
34
35#include <sys/time.h>
36#include <sys/resource.h>
37
38void fatal_error(e2fsck_t ctx, const char *msg)
39{
40	if (msg)
41		fprintf (stderr, "e2fsck: %s\n", msg);
42	if (ctx->fs && ctx->fs->io)
43		io_channel_flush(ctx->fs->io);
44	ctx->flags |= E2F_FLAG_ABORT;
45	if (ctx->flags & E2F_FLAG_SETJMP_OK)
46		longjmp(ctx->abort_loc, 1);
47	exit(FSCK_ERROR);
48}
49
50void *e2fsck_allocate_memory(e2fsck_t ctx, unsigned int size,
51			     const char *description)
52{
53	void *ret;
54	char buf[256];
55
56#ifdef DEBUG_ALLOCATE_MEMORY
57	printf("Allocating %d bytes for %s...\n", size, description);
58#endif
59	ret = malloc(size);
60	if (!ret) {
61		sprintf(buf, "Can't allocate %s\n", description);
62		fatal_error(ctx, buf);
63	}
64	memset(ret, 0, size);
65	return ret;
66}
67
68int ask_yn(const char * string, int def)
69{
70	int		c;
71	const char	*defstr;
72	char		*short_yes = _("yY");
73	char		*short_no = _("nN");
74
75#ifdef HAVE_TERMIOS_H
76	struct termios	termios, tmp;
77
78	tcgetattr (0, &termios);
79	tmp = termios;
80	tmp.c_lflag &= ~(ICANON | ECHO);
81	tmp.c_cc[VMIN] = 1;
82	tmp.c_cc[VTIME] = 0;
83	tcsetattr (0, TCSANOW, &tmp);
84#endif
85
86	if (def == 1)
87		defstr = _("<y>");
88	else if (def == 0)
89		defstr = _("<n>");
90	else
91		defstr = _(" (y/n)");
92	printf("%s%s? ", string, defstr);
93	while (1) {
94		fflush (stdout);
95		if ((c = read_a_char()) == EOF)
96			break;
97		if (strchr(short_yes, (char) c)) {
98			def = 1;
99			break;
100		}
101		else if (strchr(short_no, (char) c)) {
102			def = 0;
103			break;
104		}
105		else if ((c == ' ' || c == '\n') && (def != -1))
106			break;
107	}
108	if (def)
109		printf ("yes\n\n");
110	else
111		printf ("no\n\n");
112#ifdef HAVE_TERMIOS_H
113	tcsetattr (0, TCSANOW, &termios);
114#endif
115	return def;
116}
117
118int ask (e2fsck_t ctx, const char * string, int def)
119{
120	if (ctx->options & E2F_OPT_NO) {
121		printf (_("%s? no\n\n"), string);
122		return 0;
123	}
124	if (ctx->options & E2F_OPT_YES) {
125		printf (_("%s? yes\n\n"), string);
126		return 1;
127	}
128	if (ctx->options & E2F_OPT_PREEN) {
129		printf ("%s? %s\n\n", string, def ? _("yes") : _("no"));
130		return def;
131	}
132	return ask_yn(string, def);
133}
134
135void e2fsck_read_bitmaps(e2fsck_t ctx)
136{
137	ext2_filsys fs = ctx->fs;
138	errcode_t	retval;
139
140	if (ctx->invalid_bitmaps) {
141		com_err(ctx->program_name, 0,
142		    _("e2fsck_read_bitmaps: illegal bitmap block(s) for %s"),
143			ctx->device_name);
144		fatal_error(ctx, 0);
145	}
146
147	ehandler_operation(_("reading inode and block bitmaps"));
148	retval = ext2fs_read_bitmaps(fs);
149	ehandler_operation(0);
150	if (retval) {
151		com_err(ctx->program_name, retval,
152			_("while retrying to read bitmaps for %s"),
153			ctx->device_name);
154		fatal_error(ctx, 0);
155	}
156}
157
158void e2fsck_write_bitmaps(e2fsck_t ctx)
159{
160	ext2_filsys fs = ctx->fs;
161	errcode_t	retval;
162
163	if (ext2fs_test_bb_dirty(fs)) {
164		ehandler_operation(_("writing block bitmaps"));
165		retval = ext2fs_write_block_bitmap(fs);
166		ehandler_operation(0);
167		if (retval) {
168			com_err(ctx->program_name, retval,
169			    _("while retrying to write block bitmaps for %s"),
170				ctx->device_name);
171			fatal_error(ctx, 0);
172		}
173	}
174
175	if (ext2fs_test_ib_dirty(fs)) {
176		ehandler_operation(_("writing inode bitmaps"));
177		retval = ext2fs_write_inode_bitmap(fs);
178		ehandler_operation(0);
179		if (retval) {
180			com_err(ctx->program_name, retval,
181			    _("while retrying to write inode bitmaps for %s"),
182				ctx->device_name);
183			fatal_error(ctx, 0);
184		}
185	}
186}
187
188void preenhalt(e2fsck_t ctx)
189{
190	ext2_filsys fs = ctx->fs;
191
192	if (!(ctx->options & E2F_OPT_PREEN))
193		return;
194	fprintf(stderr, _("\n\n%s: UNEXPECTED INCONSISTENCY; "
195		"RUN fsck MANUALLY.\n\t(i.e., without -a or -p options)\n"),
196	       ctx->device_name);
197	if (fs != NULL) {
198		fs->super->s_state |= EXT2_ERROR_FS;
199		ext2fs_mark_super_dirty(fs);
200		ext2fs_close(fs);
201	}
202	exit(FSCK_UNCORRECTED);
203}
204
205#ifdef RESOURCE_TRACK
206void init_resource_track(struct resource_track *track)
207{
208#ifdef HAVE_GETRUSAGE
209	struct rusage r;
210#endif
211
212	track->brk_start = sbrk(0);
213	gettimeofday(&track->time_start, 0);
214#ifdef HAVE_GETRUSAGE
215#ifdef solaris
216	memcpy(&r, 0, sizeof(struct rusage));
217#endif
218	getrusage(RUSAGE_SELF, &r);
219	track->user_start = r.ru_utime;
220	track->system_start = r.ru_stime;
221#else
222	track->user_start.tv_sec = track->user_start.tv_usec = 0;
223	track->system_start.tv_sec = track->system_start.tv_usec = 0;
224#endif
225}
226
227#ifdef __GNUC__
228#define _INLINE_ __inline__
229#else
230#define _INLINE_
231#endif
232
233static _INLINE_ float timeval_subtract(struct timeval *tv1,
234				       struct timeval *tv2)
235{
236	return ((tv1->tv_sec - tv2->tv_sec) +
237		((float) (tv1->tv_usec - tv2->tv_usec)) / 1000000);
238}
239
240void print_resource_track(const char *desc, struct resource_track *track)
241{
242#ifdef HAVE_GETRUSAGE
243	struct rusage r;
244#endif
245#ifdef HAVE_MALLINFO
246	struct mallinfo	malloc_info;
247#endif
248	struct timeval time_end;
249
250	gettimeofday(&time_end, 0);
251
252	if (desc)
253		printf("%s: ", desc);
254
255#ifdef HAVE_MALLINFO
256#define kbytes(x)	(((x) + 1023) / 1024)
257
258	malloc_info = mallinfo();
259	printf(_("Memory used: %dk/%dk (%dk/%dk), "),
260	       kbytes(malloc_info.arena), kbytes(malloc_info.hblkhd),
261	       kbytes(malloc_info.uordblks), kbytes(malloc_info.fordblks));
262#else
263	printf(_("Memory used: %d, "),
264	       (int) (((char *) sbrk(0)) - ((char *) track->brk_start)));
265#endif
266#ifdef HAVE_GETRUSAGE
267	getrusage(RUSAGE_SELF, &r);
268
269	printf(_("time: %5.2f/%5.2f/%5.2f\n"),
270	       timeval_subtract(&time_end, &track->time_start),
271	       timeval_subtract(&r.ru_utime, &track->user_start),
272	       timeval_subtract(&r.ru_stime, &track->system_start));
273#else
274	printf(_("elapsed time: %6.3f\n"),
275	       timeval_subtract(&time_end, &track->time_start));
276#endif
277}
278#endif /* RESOURCE_TRACK */
279
280void e2fsck_read_inode(e2fsck_t ctx, unsigned long ino,
281			      struct ext2_inode * inode, const char *proc)
282{
283	int retval;
284
285	retval = ext2fs_read_inode(ctx->fs, ino, inode);
286	if (retval) {
287		com_err("ext2fs_read_inode", retval,
288			_("while reading inode %ld in %s"), ino, proc);
289		fatal_error(ctx, 0);
290	}
291}
292
293extern void e2fsck_write_inode(e2fsck_t ctx, unsigned long ino,
294			       struct ext2_inode * inode, const char *proc)
295{
296	int retval;
297
298	retval = ext2fs_write_inode(ctx->fs, ino, inode);
299	if (retval) {
300		com_err("ext2fs_write_inode", retval,
301			_("while writing inode %ld in %s"), ino, proc);
302		fatal_error(ctx, 0);
303	}
304}
305
306#ifdef MTRACE
307void mtrace_print(char *mesg)
308{
309	FILE	*malloc_get_mallstream();
310	FILE	*f = malloc_get_mallstream();
311
312	if (f)
313		fprintf(f, "============= %s\n", mesg);
314}
315#endif
316
317blk_t get_backup_sb(ext2_filsys fs)
318{
319	if (!fs || !fs->super)
320		return 8193;
321	return fs->super->s_blocks_per_group + fs->super->s_first_data_block;
322}
323
324/*
325 * Given a mode, return the ext2 file type
326 */
327int ext2_file_type(unsigned int mode)
328{
329	if (LINUX_S_ISREG(mode))
330		return EXT2_FT_REG_FILE;
331
332	if (LINUX_S_ISDIR(mode))
333		return EXT2_FT_DIR;
334
335	if (LINUX_S_ISCHR(mode))
336		return EXT2_FT_CHRDEV;
337
338	if (LINUX_S_ISBLK(mode))
339		return EXT2_FT_BLKDEV;
340
341	if (LINUX_S_ISLNK(mode))
342		return EXT2_FT_SYMLINK;
343
344	if (LINUX_S_ISFIFO(mode))
345		return EXT2_FT_FIFO;
346
347	if (LINUX_S_ISSOCK(mode))
348		return EXT2_FT_SOCK;
349
350	return 0;
351}
352