1    	#include "clusterautoconfig.h"
2    	
3    	#include <unistd.h>
4    	#include <stdio.h>
5    	#include <stdint.h>
6    	#include <stdlib.h>
7    	#include <libgen.h>
8    	#include <string.h>
9    	#include <stdarg.h>
10   	#include <ctype.h>
11   	#include <signal.h>
12   	#include <libintl.h>
13   	#include <locale.h>
14   	#include <sys/time.h>
15   	#define _(String) gettext(String)
16   	#include <syslog.h>
17   	
18   	#include <logging.h>
19   	#include "copyright.cf"
20   	#include "libgfs2.h"
21   	#include "fsck.h"
22   	#include "link.h"
23   	#include "osi_list.h"
24   	#include "metawalk.h"
25   	#include "util.h"
26   	
27   	struct lgfs2_inode *lf_dip = NULL; /* Lost and found directory inode */
28   	int lf_was_created = 0;
29   	uint64_t last_fs_block, last_reported_block = -1;
30   	int64_t last_reported_fblock = -1000000;
31   	int skip_this_pass = 0, fsck_abort = 0;
32   	int errors_found = 0, errors_corrected = 0;
33   	uint64_t last_data_block;
34   	uint64_t first_data_block;
35   	int dups_found = 0, dups_found_first = 0;
36   	int sb_fixed = 0;
37   	int print_level = MSG_NOTICE;
38   	
39   	static const char *pass_name = "";
40   	
41   	static void usage(char *name)
42   	{
43   		printf("Usage: %s [-afhnpqvVy] <device> \n", basename(name));
44   	}
45   	
46   	static void version(void)
47   	{
48   		printf("fsck.gfs2 " VERSION "\n");
49   		printf(REDHAT_COPYRIGHT "\n");
50   	}
51   	
52   	static int read_cmdline(int argc, char **argv, struct fsck_options *gopts)
53   	{
54   		int c;
55   	
56   		while ((c = getopt(argc, argv, "afhnpqvyV")) != -1) {
57   			switch(c) {
58   	
59   			case 'a':
60   			case 'p':
61   				if (gopts->yes || gopts->no) {
62   					fprintf(stderr, _("Options -p/-a, -y and -n may not be used together\n"));
63   					return FSCK_USAGE;
64   				}
65   				gopts->preen = 1;
66   				gopts->yes = 1;
67   				break;
68   			case 'f':
69   				gopts->force = 1;
70   				break;
71   			case 'h':
72   				usage(argv[0]);
73   				exit(FSCK_OK);
74   				break;
75   			case 'n':
76   				if (gopts->yes || gopts->preen) {
77   					fprintf(stderr, _("Options -p/-a, -y and -n may not be used together\n"));
78   					return FSCK_USAGE;
79   				}
80   				gopts->no = 1;
81   				break;
82   			case 'q':
83   				decrease_verbosity();
84   				break;
85   			case 'v':
86   				increase_verbosity();
87   				break;
88   			case 'V':
89   				version();
90   				exit(FSCK_OK);
91   				break;
92   			case 'y':
93   				if (gopts->no || gopts->preen) {
94   					fprintf(stderr, _("Options -p/-a, -y and -n may not be used together\n"));
95   					return FSCK_USAGE;
96   				}
97   				gopts->yes = 1;
98   				break;
99   			case ':':
100  			case '?':
101  				fprintf(stderr, _("Please use '-h' for help.\n"));
102  				return FSCK_USAGE;
103  			default:
104  				fprintf(stderr, _("Invalid option %c\n"), c);
105  				return FSCK_USAGE;
106  	
107  			}
108  		}
109  		if (argc > optind) {
110  			gopts->device = (argv[optind]);
111  			if (!gopts->device) {
112  				fprintf(stderr, _("Please use '-h' for help.\n"));
113  				return FSCK_USAGE;
114  			}
115  		} else {
116  			fprintf(stderr, _("No device specified (Please use '-h' for help)\n"));
117  			return FSCK_USAGE;
118  		}
119  		return 0;
120  	}
121  	
122  	static void interrupt(int sig)
123  	{
124  		char response;
125  		char progress[1024];
126  	
127  		if (!last_reported_block || last_reported_block == last_fs_block)
128  			snprintf(progress, sizeof(progress), _("progress unknown.\n"));
129  		else
130  			snprintf(progress, sizeof(progress),
131  			        _("processing block %"PRIu64" out of %"PRIu64"\n"),
132  			        last_reported_block, last_fs_block);
133  	
134  		response = generic_interrupt("fsck.gfs2", pass_name, progress,
135  					     _("Do you want to abort fsck.gfs2, skip " \
136  					     "the rest of this pass or continue " \
137  					     "(a/s/c)?"), "asc");
138  		if (tolower(response) == 's') {
139  			skip_this_pass = 1;
140  			return;
141  		}
142  		else if (tolower(response) == 'a') {
143  			fsck_abort = 1;
144  			return;
145  		}
146  	}
147  	
148  	static int check_statfs(struct fsck_cx *cx)
149  	{
150  		struct osi_node *n, *next = NULL;
151  		struct lgfs2_rgrp_tree *rgd;
152  		struct gfs2_statfs_change sc;
153  		struct lgfs2_sbd *sdp = cx->sdp;
154  		uint64_t sc_total;
155  		uint64_t sc_free;
156  		uint64_t sc_dinodes;
157  		int count;
158  	
159  		/* Read the current statfs values */
160  		count = lgfs2_readi(sdp->md.statfs, &sc, 0, sdp->md.statfs->i_size);
161  		if (count != sizeof(struct gfs2_statfs_change)) {
162  			log_err(_("Failed to read statfs values (%d of %"PRIu64" read)\n"),
163  			        count, sdp->md.statfs->i_size);
164  			return FSCK_ERROR;
165  		}
166  		sc_total = be64_to_cpu(sc.sc_total);
167  		sc_free = be64_to_cpu(sc.sc_free);
168  		sc_dinodes = be64_to_cpu(sc.sc_dinodes);
169  	
170  		/* Calculate the real values from the rgrp information */
171  		sdp->blks_total = 0;
172  		sdp->blks_alloced = 0;
173  		sdp->dinodes_alloced = 0;
174  	
175  		for (n = osi_first(&sdp->rgtree); n; n = next) {
176  			next = osi_next(n);
177  			rgd = (struct lgfs2_rgrp_tree *)n;
178  			sdp->blks_total += rgd->rt_data;
179  			sdp->blks_alloced += (rgd->rt_data - rgd->rt_free);
180  			sdp->dinodes_alloced += rgd->rt_dinodes;
181  		}
182  	
183  		/* See if they match */
184  		if (sc_total == sdp->blks_total &&
185  		    sc_free == (sdp->blks_total - sdp->blks_alloced) &&
186  		    sc_dinodes == sdp->dinodes_alloced) {
187  			log_info( _("The statfs file is accurate.\n"));
188  			return 0;
189  		}
190  		log_err( _("The statfs file is wrong:\n\n"));
191  		log_err( _("Current statfs values:\n"));
192  		log_err( _("blocks:  %"PRId64" (0x%"PRIx64")\n"), sc_total, sc_total);
193  		log_err( _("free:    %"PRId64" (0x%"PRIx64")\n"), sc_free, sc_free);
194  		log_err( _("dinodes: %"PRId64" (0x%"PRIx64")\n\n"), sc_dinodes, sc_dinodes);
195  		log_err( _("Calculated statfs values:\n"));
196  		log_err( _("blocks:  %"PRIu64" (0x%"PRIx64")\n"),
197  		        sdp->blks_total, sdp->blks_total);
198  		log_err( _("free:    %"PRIu64" (0x%"PRIx64")\n"),
199  		        (sdp->blks_total - sdp->blks_alloced),
200  		        (sdp->blks_total - sdp->blks_alloced));
201  		log_err( _("dinodes: %"PRIu64" (0x%"PRIx64")\n"),
202  		        sdp->dinodes_alloced, sdp->dinodes_alloced);
203  	
204  		errors_found++;
205  		if (!query(cx, _("Okay to fix the master statfs file? (y/n)"))) {
206  			log_err( _("The statfs file was not fixed.\n"));
207  			return 0;
208  		}
209  	
210  		lgfs2_init_statfs(sdp, NULL);
211  		log_err( _("The statfs file was fixed.\n"));
212  		errors_corrected++;
213  		return 0;
214  	}
215  	
216  	static const struct fsck_pass passes[] = {
217  		{ .name = "pass1",  .f = pass1 },
218  		{ .name = "pass1b", .f = pass1b },
219  		{ .name = "pass2",  .f = pass2 },
220  		{ .name = "pass3",  .f = pass3 },
221  		{ .name = "pass4",  .f = pass4 },
222  		{ .name = "check_statfs", .f = check_statfs },
223  		{ .name = NULL, }
224  	};
225  	
226  	static int fsck_pass(const struct fsck_pass *p, struct fsck_cx *cx)
227  	{
228  		int ret;
229  		struct timeval timer;
230  	
231  		if (fsck_abort)
232  			return FSCK_CANCELED;
233  		pass_name = p->name;
234  	
235  		log_notice( _("Starting %s\n"), p->name);
236  		gettimeofday(&timer, NULL);
237  	
238  		ret = p->f(cx);
239  		if (ret)
240  			exit(ret);
241  		if (skip_this_pass || fsck_abort) {
242  			skip_this_pass = 0;
243  			log_notice( _("%s interrupted   \n"), p->name);
244  			return FSCK_CANCELED;
245  		}
246  	
247  		print_pass_duration(p->name, &timer);
248  		return 0;
249  	}
250  	
251  	/*
252  	 * on_exit() is non-standard but useful for reporting the exit status if it's
253  	 * available.
254  	 */
255  	#ifdef HAVE_ON_EXIT
256  	static void exitlog(int status, void *unused)
257  	{
258  		syslog(LOG_INFO, "exit: %d", status);
259  	}
260  	#else
261  	static void exitlog(void)
262  	{
263  		syslog(LOG_INFO, "exit.");
264  	}
265  	#endif
266  	
267  	static void startlog(int argc, char **argv)
268  	{
269  		int i;
270  		char *cmd, *p;
271  		size_t len;
272  	
273  		for (len = i = 0; i < argc; i++)
274  			len += strlen(argv[i]);
275  		len += argc; /* Add spaces and '\0' */
276  	
277  		cmd = malloc(len);
278  		if (cmd == NULL) {
279  			perror(argv[0]);
280  			exit(FSCK_ERROR);
281  		}
282  		p = cmd;
283  		for (i = 0; i < argc; i++, p++) {
284  			p = stpcpy(p, argv[i]);
285  			*p = ' ';
286  		}
287  		*(--p) = '\0';
288  		syslog(LOG_INFO, "started: %s", cmd);
289  		free(cmd);
290  	}
291  	
292  	#ifndef UNITTESTS
293  	int main(int argc, char **argv)
294  	{
295  		struct fsck_options opts = {0};
296  		struct lgfs2_sbd sb;
297  		struct fsck_cx cx = {
298  			.sdp = &sb,
299  			.opts = &opts,
300  		};
301  		int j;
302  		int i;
303  		int error = 0;
304  		int all_clean = 0;
305  		struct sigaction act = { .sa_handler = interrupt, };
306  	
307  		setlocale(LC_ALL, "");
308  		textdomain("gfs2-utils");
309  	
310  		openlog("fsck.gfs2", LOG_CONS|LOG_PID, LOG_USER);
311  		startlog(argc - 1, &argv[1]);
312  	#ifdef HAVE_ON_EXIT
313  		on_exit(exitlog, NULL);
314  	#else
315  		atexit(exitlog);
316  	#endif
317  	
318  		memset(&sb, 0, sizeof(sb));
319  	
(1) Event cond_false: Condition "error = read_cmdline(argc, argv, &opts)", taking false branch.
320  		if ((error = read_cmdline(argc, argv, &opts)))
(2) Event if_end: End of if statement.
321  			exit(error);
322  		setbuf(stdout, NULL);
(3) Event cond_true: Condition "print_level >= 5", taking true branch.
323  		log_notice( _("Initializing fsck\n"));
(4) Event cond_false: Condition "error = initialize(&cx, &all_clean)", taking false branch.
324  		if ((error = initialize(&cx, &all_clean)))
(5) Event if_end: End of if statement.
325  			exit(error);
326  	
(6) Event cond_false: Condition "!opts.force", taking false branch.
327  		if (!opts.force && all_clean && opts.preen) {
328  			log_err( _("%s: clean.\n"), opts.device);
329  			destroy(&cx);
330  			exit(FSCK_OK);
(7) Event if_end: End of if statement.
331  		}
332  	
333  		sigaction(SIGINT, &act, NULL);
334  	
(8) Event cond_true: Condition "passes[i].name", taking true branch.
(10) Event loop_begin: Jumped back to beginning of loop.
(11) Event cond_true: Condition "passes[i].name", taking true branch.
(13) Event loop_begin: Jumped back to beginning of loop.
(14) Event cond_true: Condition "passes[i].name", taking true branch.
(16) Event loop_begin: Jumped back to beginning of loop.
(17) Event cond_false: Condition "passes[i].name", taking false branch.
335  		for (i = 0; passes[i].name; i++)
(9) Event loop: Jumping back to the beginning of the loop.
(12) Event loop: Jumping back to the beginning of the loop.
(15) Event loop: Jumping back to the beginning of the loop.
(18) Event loop_end: Reached end of loop.
336  			error = fsck_pass(passes + i, &cx);
337  	
338  		/* Free up our system inodes */
339  		lgfs2_inode_put(&sb.md.inum);
340  		lgfs2_inode_put(&sb.md.statfs);
(19) Event cond_true: Condition "j < sb.md.journals", taking true branch.
(21) Event loop_begin: Jumped back to beginning of loop.
(22) Event cond_true: Condition "j < sb.md.journals", taking true branch.
(24) Event loop_begin: Jumped back to beginning of loop.
(25) Event cond_false: Condition "j < sb.md.journals", taking false branch.
341  		for (j = 0; j < sb.md.journals; j++)
(20) Event loop: Jumping back to the beginning of the loop.
(23) Event loop: Jumping back to the beginning of the loop.
(26) Event loop_end: Reached end of loop.
342  			lgfs2_inode_put(&sb.md.journal[j]);
343  		free(sb.md.journal);
344  		sb.md.journal = NULL;
345  		lgfs2_inode_put(&sb.md.jiinode);
346  		lgfs2_inode_put(&sb.md.riinode);
(27) Event null_field: Reading field "qinode", which is expected to possibly be "NULL" in "sb.md.qinode" (checked 5 out of 6 times).
(33) Event dereference: Passing "&sb.md.qinode" to "lgfs2_inode_put", which dereferences null "sb.md.qinode". [details]
Also see events: [example_checked][example_checked][example_checked][example_checked][example_checked]
347  		lgfs2_inode_put(&sb.md.qinode);
348  		lgfs2_inode_put(&sb.md.pinode);
349  		lgfs2_inode_put(&sb.md.rooti);
350  		lgfs2_inode_put(&sb.master_dir);
351  		if (lf_dip)
352  			lgfs2_inode_put(&lf_dip);
353  	
354  		if (!opts.no && errors_corrected)
355  			log_notice( _("Writing changes to disk\n"));
356  		fsync(sb.device_fd);
357  		link1_destroy(&nlink1map);
358  		link1_destroy(&clink1map);
359  		destroy(&cx);
360  		if (sb_fixed)
361  			log_warn(_("Superblock was reset. Use tunegfs2 to manually "
362  			           "set lock table before mounting.\n"));
363  		log_notice( _("fsck.gfs2 complete\n"));
364  	
365  		if (!error) {
366  			if (!errors_found)
367  				error = FSCK_OK;
368  			else if (errors_found == errors_corrected)
369  				error = FSCK_NONDESTRUCT;
370  			else
371  				error = FSCK_UNCORRECTED;
372  		}
373  		exit(error);
374  	}
375  	#endif /* UNITTESTS */
376