1    	#include "clusterautoconfig.h"
2    	/**
3    	 * glocktop.c - list/print the top GFS2 glock waiters
4    	 */
5    	#include <stdio.h>
6    	#include <string.h>
7    	#include <stdlib.h>
8    	#include <sys/types.h>
9    	#include <sys/stat.h>
10   	#include <fcntl.h>
11   	#include <unistd.h>
12   	#include <time.h>
13   	#include <limits.h>
14   	#include <sys/wait.h>
15   	#include <sys/mount.h>
16   	#include <dirent.h>
17   	#include <curses.h>
18   	#include <term.h>
19   	#include <string.h>
20   	#include <stdint.h>
21   	#include <inttypes.h>
22   	#include <ctype.h>
23   	#include <errno.h>
24   	#include <libgfs2.h>
25   	
26   	#define MAX_GLOCKS 20
27   	#define MAX_LINES 6000
28   	#define MAX_FILES 512
29   	#define MAX_CALLTRACE_LINES 4
30   	#define TITLE1 "glocktop - GFS2 glock monitor"
31   	#define TITLE2 "Press <ctrl-c> or <escape> to exit"
32   	
33   	#define COLOR_TITLE     1
34   	#define COLOR_NORMAL    2
35   	#define COLOR_INVERSE   3
36   	#define COLOR_SPECIAL   4
37   	#define COLOR_HIGHLIGHT 5
38   	#define COLOR_OFFSETS   6
39   	#define COLOR_CONTENTS  7
40   	#define COLOR_HELD      8
41   	
42   	/*	init_pair(COLOR_TITLE, COLOR_BLACK,  COLOR_CYAN);
43   		init_pair(COLOR_INVERSE, COLOR_BLACK,  COLOR_WHITE);
44   		init_pair(COLOR_NORMAL, COLOR_WHITE,  COLOR_BLACK);
45   		init_pair(COLOR_SPECIAL, COLOR_MAGENTA, COLOR_WHITE);
46   		init_pair(COLOR_HIGHLIGHT, COLOR_WHITE, COLOR_BLUE);
47   		init_pair(COLOR_OFFSETS, COLOR_CYAN,   COLOR_WHITE);
48   		init_pair(COLOR_CONTENTS, COLOR_BLUE, COLOR_WHITE);
49   		init_pair(COLOR_HELD, COLOR_CYAN, COLOR_BLACK);
50   	*/
51   	
52   	#define STR_BLACK "[\033[0;30m]"
53   	#define STR_RED "[\033[0;31m]"
54   	#define STR_GREEN "[\033[0;32m]"
55   	#define STR_YELLOW "[\033[0;33m]"
56   	#define STR_BLUE "[\033[0;34m]"
57   	#define STR_MAGENTA "[\033[0;35m]"
58   	#define STR_CYAN "[\033[0;36m]"
59   	#define STR_WHITE "[\033[0;37m]"
60   	
61   	#define BOLD_WHITE "[\033[1;37m]"
62   	
63   	#define BKG_CYAN "[\033[46m]"
64   	#define BKG_WHITE "[\033[47m]"
65   	#define BKG_BLUE "[\033[44m]"
66   	
67   	#define REFRESH_TIME    30
68   	#define COLORS_TITLE    \
69   		do {						   \
70   			if (termlines)				   \
71   				attrset(COLOR_PAIR(COLOR_TITLE));  \
72   			else 					   \
73   				printf(BKG_CYAN);		   \
74   		} while (0)
75   	#define COLORS_NORMAL_BOLD    \
76   		do {						   \
77   			if (termlines) {			   \
78   				attrset(COLOR_PAIR(COLOR_NORMAL)); \
79   				attron(A_BOLD);			   \
80   			} else {				   \
81   				printf(BOLD_WHITE);		   \
82   			}					   \
83   		} while (0)
84   	#define COLORS_NORMAL    \
85   		do {						   \
86   			if (termlines) {			   \
87   				attrset(COLOR_PAIR(COLOR_NORMAL)); \
88   			} else {				   \
89   				printf(STR_WHITE);		   \
90   			}					   \
91   		} while (0)
92   	#define COLORS_INVERSE_BOLD   \
93   		do {						    \
94   			if (termlines) {			    \
95   				attrset(COLOR_PAIR(COLOR_INVERSE)); \
96   				attron(A_BOLD);			    \
97   			} else {				    \
98   				printf(BKG_WHITE);		    \
99   			}					    \
100  		} while (0)
101  	#define COLORS_INVERSE   \
102  		do {						    \
103  			if (termlines) {			    \
104  				attrset(COLOR_PAIR(COLOR_INVERSE)); \
105  			} else {				    \
106  				printf(BKG_WHITE);		    \
107  			}					    \
108  		} while (0)
109  	#define COLORS_HELD   \
110  		do {						    \
111  			if (termlines) {			    \
112  				attrset(COLOR_PAIR(COLOR_HELD));    \
113  			} else {				    \
114  				printf(STR_CYAN);		    \
115  			}					    \
116  		} while (0)
117  	#define COLORS_HIGHLIGHT   \
118  		do {						    \
119  			if (termlines) {			    \
120  				attrset(COLOR_PAIR(COLOR_HIGHLIGHT));	\
121  			} else {				    \
122  				printf(BKG_BLUE);		    \
123  			}					    \
124  		} while (0)
125  	#define DLM_DIRTBL "/sys/kernel/config/dlm/cluster/dirtbl_size"
126  	#define DLM_RSBTBL "/sys/kernel/config/dlm/cluster/rsbtbl_size"
127  	#define DLM_LKBTBL "/sys/kernel/config/dlm/cluster/lkbtbl_size"
128  	
129  	#define GFS2_MAX_META_HEIGHT	10
130  	
131  	#define DETAILS  0x00000001
132  	#define FRIENDLY 0x00000002
133  	
134  	enum summary_types {
135  		all = 0,
136  		locked = 1,
137  		held_ex = 2,
138  		held_sh = 3,
139  		held_df = 4,
140  		has_waiter = 5,
141  		tot_waiters = 6,
142  		stypes = 7,
143  	};
144  	
145  	static char *debugfs;
146  	static int termcols = 80, termlines = 30, done = 0;
147  	static unsigned glocks = 0;
148  	static const char *termtype;
149  	static WINDOW *wind;
150  	static int bufsize = 4 * 1024 * 1024;
151  	static char *glock[MAX_GLOCKS];
152  	static int iterations = 0, show_reservations = 0, iters_done = 0;
153  	struct mount_point {
154  		struct mount_point *next;
155  		char *device;
156  		char *dir;
157  		int fd;
158  		struct lgfs2_sbd sb;
159  	};
160  	static struct mount_point *mounts;
161  	static char dlmwlines[MAX_LINES][96]; /* waiters lines */
162  	static char dlmglines[MAX_LINES][97]; /* granted lines */
163  	static char contended_filenames[MAX_FILES][PATH_MAX];
164  	static uint64_t contended_blocks[MAX_FILES];
165  	static int contended_count = 0;
166  	static int line = 0;
167  	static const char *prog_name;
168  	static char dlm_dirtbl_size[32], dlm_rsbtbl_size[32], dlm_lkbtbl_size[32];
169  	static int bsize = 0;
170  	static char print_dlm_grants = 1;
171  	static char *gbuf = NULL; /* glocks buffer */
172  	static char *gpos = NULL;
173  	static char *gnextpos = NULL;
174  	static int gmaxpos = 0;
175  	static char *dbuf = NULL; /* dlm locks buffer */
176  	static char *dpos = NULL;
177  	static char *dnextpos = NULL;
178  	static int dmaxpos = 0;
179  	static char hostname[256];
180  	
181  	/*
182  	 * init_colors
183  	 */
184  	static void init_colors(void)
185  	{
186  		init_pair(COLOR_TITLE, COLOR_BLACK,  COLOR_CYAN);
187  		init_pair(COLOR_INVERSE, COLOR_BLACK,  COLOR_WHITE);
188  		init_pair(COLOR_NORMAL, COLOR_WHITE,  COLOR_BLACK);
189  		init_pair(COLOR_SPECIAL, COLOR_MAGENTA, COLOR_WHITE);
190  		init_pair(COLOR_HIGHLIGHT, COLOR_WHITE, COLOR_BLUE);
191  		init_pair(COLOR_OFFSETS, COLOR_CYAN,   COLOR_WHITE);
192  		init_pair(COLOR_CONTENTS, COLOR_BLUE, COLOR_WHITE);
193  		init_pair(COLOR_HELD, COLOR_CYAN, COLOR_BLACK);
194  	}
195  	
196  	/*
197  	 * UpdateSize - screen size changed, so update it
198  	 */
199  	static void UpdateSize(int sig)
200  	{
201  		static char term_buffer[2048];
202  		int rc;
203  	
204  		if (termlines) {
205  			termlines = 30;
206  			termtype = getenv("TERM");
207  			if (termtype == NULL)
208  				return;
209  			rc=tgetent(term_buffer,termtype);
210  			if (rc >= 0) {
211  				termlines = tgetnum((char *)"li");
212  				if (termlines < 10)
213  					termlines = 30;
214  				termcols = tgetnum((char *)"co");
215  				if (termcols < 80)
216  					termcols = 80;
217  			} else
218  				perror("Error: tgetent failed.");
219  			termlines--; /* last line is number of lines -1 */
220  		}
221  		signal(SIGWINCH, UpdateSize);
222  	}
223  	
224  	static int read_superblock(int fd, struct lgfs2_sbd *sdp)
225  	{
226  		ssize_t r;
227  		char *buf;
228  	
229  		ioctl(fd, BLKFLSBUF, 0);
230  		buf = calloc(1, GFS2_BASIC_BLOCK);
231  		if (buf == NULL) {
232  			perror("Failed to read superblock");
233  			return -1;
234  		}
235  		r = pread(fd, buf, GFS2_BASIC_BLOCK, GFS2_BASIC_BLOCK * GFS2_SB_ADDR);
236  		if (r != GFS2_BASIC_BLOCK) {
237  			perror("Failed to read superblock");
238  			free(buf);
239  			return -1;
240  		}
241  		lgfs2_sb_in(sdp, buf);
242  		free(buf);
243  	
244  		bsize = sdp->sd_bsize;
245  		if (!bsize)
246  			bsize = 4096;
247  		return 0;
248  	}
249  	
250  	static void free_mounts(void)
251  	{
252  		struct mount_point *mntp = mounts;
253  	
254  		while (mntp != NULL) {
255  			struct mount_point *nextp = mntp->next;
256  	
257  			close(mntp->fd);
258  			free(mntp);
259  			mntp = nextp;
260  		}
261  		mounts = NULL;
262  	}
263  	
264  	static int parse_mounts(void)
265  	{
266  		struct mount_point **mntp = &mounts;
267  		struct mntent *mnt;
268  		FILE *fp;
269  	
270  		fp = setmntent("/proc/mounts", "r");
271  		if (fp == NULL) {
272  			perror("/proc/mounts");
273  			return 1;
274  		}
275  		while ((mnt = getmntent(fp)) != NULL) {
276  			size_t devlen = strlen(mnt->mnt_fsname);
277  			size_t dirlen = strlen(mnt->mnt_dir);
278  			struct mount_point *newmnt;
279  	
280  			if (strcmp(mnt->mnt_type, "debugfs") == 0) {
281  				if (debugfs == NULL)
282  					debugfs = strdup(mnt->mnt_dir);
283  				continue;
284  			}
285  			if (strcmp(mnt->mnt_type, "gfs2") != 0)
286  				continue;
287  	
288  			newmnt = calloc(1, sizeof(*newmnt) + devlen + 1 + dirlen + 1);
289  			if (newmnt == NULL) {
290  				perror("Failed to gather mount points");
291  				return 1;
292  			}
293  			newmnt->device = (char *)(newmnt + 1);
294  			newmnt->dir = newmnt->device + devlen + 1;
295  			strcpy(newmnt->device, mnt->mnt_fsname);
296  			strcpy(newmnt->dir, mnt->mnt_dir);
297  			newmnt->fd = open(newmnt->device, O_RDONLY);
298  	
299  			if (newmnt->fd < 0) {
300  				fprintf(stderr, "Failed to open gfs2 filesystem '%s': %s\n",
301  				        newmnt->device, strerror(errno));
302  				free(newmnt);
303  				continue;
304  			}
305  			if (read_superblock(newmnt->fd, &newmnt->sb) != 0) {
306  				free(newmnt);
307  				continue;
308  			}
309  			*mntp = newmnt;
310  			mntp = &newmnt->next;
311  		}
312  		endmntent(fp);
313  		if (debugfs == NULL) {
314  			debugfs = strdup("/sys/kernel/debug");
315  			if (!debugfs || mount("debugfs", "/sys/kernel/debug", "debugfs", 0, NULL)) {
316  				perror("debugfs not mounted and an attempt to mount it failed");
317  				free(debugfs);
318  				free_mounts();
319  				return 1;
320  			}
321  		}
322  		return 0;
323  	}
324  	
325  	/*
326  	 * display_title_lines
327  	 */
328  	static void display_title_lines(void)
329  	{
330  		if (termlines) {
331  			clear(); /* don't use Erase */
332  			COLORS_TITLE;
333  			attron(A_BOLD);
334  			move(0, 0);
335  			printw("%-80s", TITLE1);
336  			move(termlines, 0);
337  			printw("%-79s", TITLE2);
338  			COLORS_NORMAL_BOLD;
339  			move(1, 0);
340  		} else {
341  			printf("\n");
342  		}
343  		line = 1;
344  	}
345  	
346  	/*
347  	 * bobgets - get a string
348  	 * returns: 1 if user exited by hitting enter
349  	 *          0 if user exited by hitting escape
350  	 */
351  	static int bobgets(char string[], int x, int y, int sz, int *ch)
352  	{
353  		int finished,runningy,rc;
354  	
355  		if (!termlines)
356  			return 0;
357  		move(x,y);
358  		finished=FALSE;
359  		COLORS_INVERSE_BOLD;
360  		move(x,y);
361  		addstr(string);
362  		move(x,y);
363  		curs_set(2);
364  		refresh();
365  		runningy=y;
366  		rc=0;
367  		while (!finished) {
368  			*ch = getch();
369  	
370  			if(*ch < 0x0100 && isprint(*ch)) {
371  				char *p=string+strlen(string); // end of the string
372  	
373  				*(p+1)='\0';
374  				string[runningy-y]=*ch;
375  				runningy++;
376  				move(x,y);
377  				addstr(string);
378  				if (runningy-y >= sz) {
379  					rc=1;
380  					*ch = KEY_RIGHT;
381  					finished = TRUE;
382  				}
383  			}
384  			else {
385  				// special character, is it one we recognize?
386  				switch(*ch)
387  				{
388  				case(KEY_ENTER):
389  				case('\n'):
390  				case('\r'):
391  					rc=1;
392  					finished=TRUE;
393  					string[runningy-y] = '\0';
394  					break;
395  				case(KEY_CANCEL):
396  				case(0x01B):
397  					rc=0;
398  					finished=TRUE;
399  					break;
400  				case(KEY_DC):
401  				case(0x07F):
402  					if (runningy>=y) {
403  						char *p;
404  						p = &string[runningy - y];
405  						while (*p) {
406  							*p = *(p + 1);
407  							p++;
408  						}
409  						*p = '\0';
410  						runningy--;
411  						// remove the character from the string
412  						move(x,y);
413  						addstr(string);
414  						COLORS_NORMAL_BOLD;
415  						addstr(" ");
416  						COLORS_INVERSE_BOLD;
417  						runningy++;
418  					}
419  					break;
420  				case(KEY_BACKSPACE):
421  					if (runningy>y) {
422  						char *p;
423  	
424  						p = &string[runningy - y - 1];
425  						while (*p) {
426  							*p = *(p + 1);
427  							p++;
428  						}
429  						*p='\0';
430  						runningy--;
431  						// remove the character from the string
432  						move(x,y);
433  						addstr(string);
434  						COLORS_NORMAL_BOLD;
435  						addstr(" ");
436  						COLORS_INVERSE_BOLD;
437  					}
438  					break;
439  				default:
440  					move(0,70);
441  					printw("%08x", *ch);
442  					// ignore all other characters
443  					break;
444  				} // end switch on non-printable character
445  			} // end non-printable character
446  			move(line, runningy);
447  			refresh();
448  		} // while !finished
449  		if (sz>0)
450  			string[sz]='\0';
451  		COLORS_NORMAL_BOLD;
452  		return rc;
453  	}/* bobgets */
454  	
455  	static char *bufgets(int fd, char *bigbuf, char **nextpos, char **pos,
456  			     int *maxpos)
457  	{
(1) Event path: Condition "*nextpos == NULL", taking true branch.
458  		if (*nextpos == NULL) {
(2) Event tainted_data_argument: Calling function "read" taints parameter "*bigbuf". [Note: The source code implementation of the function has been overridden by a builtin model.]
Also see events: [parm_assign][return_tainted_data]
459  			*maxpos = read(fd, bigbuf, bufsize - 1);
460  			bigbuf[bufsize - 1] = '\0';
(3) Event path: Condition "*maxpos == 0", taking false branch.
461  			if (*maxpos == 0)
462  				return NULL;
(4) Event parm_assign: Assigning: "*pos" = "bigbuf", which taints "**pos".
Also see events: [tainted_data_argument][return_tainted_data]
463  			*pos = bigbuf;
(5) Event path: Falling through to end of if statement.
464  		} else
465  			*pos = *nextpos;
466  	
467  		*nextpos = memchr(*pos, '\n', (bigbuf + *maxpos) - *pos);
(6) Event path: Condition "*nextpos", taking true branch.
(7) Event path: Condition "**nextpos == 10", taking true branch.
(8) Event path: Condition "*nextpos < bigbuf + (bufsize - 1)", taking true branch.
(10) Event path: Condition "*nextpos", taking true branch.
(11) Event path: Condition "**nextpos == 10", taking true branch.
(12) Event path: Condition "*nextpos < bigbuf + (bufsize - 1)", taking false branch.
468  		while (*nextpos && (**nextpos == '\n' || **nextpos == '\r') &&
469  		       *nextpos < bigbuf + (bufsize - 1)) {
470  			**nextpos = '\0';
471  			(*nextpos)++;
(9) Event path: Jumping back to the beginning of the loop.
472  		}
(13) Event path: Condition "*nextpos >= bigbuf + *maxpos", taking true branch.
473  		if (*nextpos >= bigbuf + *maxpos)
474  			*nextpos = NULL;
(14) Event return_tainted_data: Returning tainted data "*pos".
Also see events: [tainted_data_argument][parm_assign]
475  		return *pos;
476  	}
477  	
478  	static char *glock_number(const char *str)
479  	{
480  		const char *glockid;
481  		char *p;
482  		static char id[32];
483  	
484  		glockid = strchr(str, '/');
485  		if (glockid == NULL)
486  			return NULL;
487  		glockid++;
488  		strncpy(id, glockid, sizeof(id));
489  		id[31] = '\0';
490  		p = strchr(id, ' ');
491  		if (p)
492  			*p = '\0';
493  		return id;
494  	}
495  	
496  	static int this_glock_requested(const char *str)
497  	{
498  		const char *glockid;
499  		int i;
500  	
501  		if (!glocks)
502  			return 0;
503  	
504  		glockid = glock_number(str);
505  		if (glockid == NULL)
506  			return 0;
507  		for (i = 0; i < glocks; i++)
508  			if (!strcmp(glockid, glock[i]))
509  				return 1;
510  		return 0;
511  	}
512  	
513  	static int is_iopen(const char *str)
514  	{
515  		const char *p;
516  	
517  		p = strchr(str, '/');
518  		if (p == NULL)
519  			return 0;
520  		p--;
521  		if (*p == '5')
522  			return 1;
523  		return 0;
524  	}
525  	
526  	static int this_lkb_requested(const char *str)
527  	{
528  		int i;
529  	
530  		if (!glocks)
531  			return 1;
532  	
533  		for (i = 0; i < glocks; i++) {
534  			if (strstr(str, glock[i]))
535  				return 1;
536  		}
537  		return 0;
538  	}
539  	
540  	static void eol(int col) /* end of line */
541  	{
542  		if (termlines) {
543  			line++;
544  			move(line, col);
545  		} else {
546  			printf("\n");
547  			for (; col > 0; col--)
548  				printf(" ");
549  		}
550  	}
551  	
552  	__attribute__((format(printf,2,4)))
553  	static void print_it(const char *label, const char *fmt, const char *fmt2, ...)
554  	{
555  		va_list args;
556  		char tmp_string[128];
557  	
558  		if (!termlines || line < termlines) {
559  			va_start(args, fmt2);
560  			vsnprintf(tmp_string, 127, fmt, args);
561  			tmp_string[127] = '\0';
562  	
563  			if (termlines) {
564  				printw("%s", tmp_string);
565  				refresh();
566  			} else {
567  				printf("%s", tmp_string);
568  				fflush(stdout);
569  			}
570  		}
571  		va_end(args);
572  	}
573  	
574  	static void display_filename(int fd, uint64_t block, uint64_t *dirarray, int subdepth)
575  	{
576  		struct mount_point *mp;
577  		int i, subs;
578  		char blk[32];
579  		DIR *dir = NULL;
580  		struct dirent *dent;
581  	
582  		for (mp = mounts; mp != NULL; mp = mp->next) {
583  			if (fd == mp->fd)
584  				break;
585  		}
586  		if (mp == NULL)
587  			return;
588  		for (i = 0; i < contended_count; i++) {
589  			if (contended_blocks[i] == block) {
590  				break;
591  			}
592  		}
593  		sprintf(blk, "%"PRIu64, block);
594  		if (i >= contended_count) {
595  			memset(contended_filenames[i], 0, PATH_MAX);
596  			strcat(contended_filenames[i], mp->dir);
597  			for (subs = subdepth - 2; subs >= 0; subs--) {
598  				dir = opendir(contended_filenames[i]);
599  				while ((dent = readdir(dir))) {
600  					if (dent->d_ino == dirarray[subs]) {
601  						strcat(contended_filenames[i], "/");
602  						strcat(contended_filenames[i],
603  						       dent->d_name);
604  						break;
605  					}
606  				}
607  				closedir(dir);
608  			}
609  		}
610  	
611  		print_it(NULL, "%s", NULL, contended_filenames[i]);
612  		eol(0);
613  	}
614  	
615  	static const char *show_inode(const char *id, int fd, uint64_t block)
616  	{
617  		struct lgfs2_inode *ip;
618  		const char *inode_type = NULL;
619  		struct lgfs2_sbd sbd = { .device_fd = fd, .sd_bsize = bsize };
620  	
621  		ip = lgfs2_inode_read(&sbd, block);
622  		if (S_ISDIR(ip->i_mode)) {
623  			struct lgfs2_inode *parent;
624  			uint64_t dirarray[256];
625  			int subdepth = 0;
626  	
627  			inode_type = "directory ";
628  			dirarray[0] = block;
629  			subdepth++;
630  			/* Backtrack the directory to its source */
631  			while (1) {
632  				parent = lgfs2_lookupi(ip, "..", 2);
633  				if (parent == NULL)
634  					break;
635  				/* Stop at the root inode */
636  				if (ip->i_num.in_addr == parent->i_num.in_addr) {
637  					lgfs2_inode_put(&parent);
638  					break;
639  				}
640  				lgfs2_inode_put(&ip);
641  				/* coverity[use_after_free:SUPPRESS] */
642  				ip = parent;
643  				dirarray[subdepth++] = parent->i_num.in_addr;
644  			}
645  			display_filename(fd, block, dirarray, subdepth);
646  		} else if (S_ISREG(ip->i_mode)) {
647  			inode_type = "file ";
648  		} else if (S_ISLNK(ip->i_mode)) {
649  			inode_type = "link ";
650  		} else if (S_ISCHR(ip->i_mode)) {
651  			inode_type = "char device ";
652  		} else if (S_ISBLK(ip->i_mode)) {
653  			inode_type = "block device ";
654  		} else if (S_ISFIFO(ip->i_mode)) {
655  			inode_type = "fifo ";
656  		} else if (S_ISSOCK(ip->i_mode)) {
657  			inode_type = "socket ";
658  		} else
659  			inode_type = "file? ";
660  		lgfs2_inode_put(&ip);
661  		return inode_type;
662  	}
663  	
664  	static const char *show_details(const char *id, const char *fsname, int btype,
665  					int trace_dir_path)
666  	{
667  		uint64_t block = 0;
668  		const char *blk_type = NULL;
669  		struct mount_point *mp;
670  		FILE *dlmf;
671  	
672  		/* Figure out which mount point corresponds to this debugfs id */
673  		for (mp = mounts; mp != NULL; mp = mp->next) {
674  			char *p;
675  	
676  			p = strchr(mp->sb.sd_locktable, ':');
677  			if (!p)
678  				continue;
679  			p++;
680  			if (!strcmp(p, fsname))
681  				break;
682  		}
683  		if (mp == NULL)
684  			return "unknown";
685  		memset(dlm_dirtbl_size, 0, sizeof(dlm_dirtbl_size));
686  		memset(dlm_rsbtbl_size, 0, sizeof(dlm_rsbtbl_size));
687  		memset(dlm_lkbtbl_size, 0, sizeof(dlm_lkbtbl_size));
688  		if (!strcmp(mp->sb.sd_lockproto, "lock_dlm")) {
689  			char *sp;
690  			char *p;
691  	
692  			dlmf = fopen(DLM_DIRTBL, "rt");
693  			if (dlmf) {
694  				sp = fgets(dlm_dirtbl_size, sizeof(dlm_dirtbl_size), dlmf);
695  				if (sp == NULL)
696  					goto out_err;
697  				p = strchr(dlm_dirtbl_size, '\n');
698  				if (p)
699  					*p = '\0';
700  				fclose(dlmf);
701  			} else {
702  				strcpy(dlm_dirtbl_size, " ");
703  			}
704  			dlmf = fopen(DLM_RSBTBL, "rt");
705  			if (dlmf) {
706  				sp = fgets(dlm_rsbtbl_size, sizeof(dlm_rsbtbl_size), dlmf);
707  				if (sp == NULL)
708  					goto out_err;
709  				p = strchr(dlm_rsbtbl_size, '\n');
710  				if (p)
711  					*p = '\0';
712  				fclose(dlmf);
713  			} else {
714  				strcpy(dlm_rsbtbl_size, " ");
715  			}
716  			dlmf = fopen(DLM_LKBTBL, "rt");
717  			if (dlmf) {
718  				sp = fgets(dlm_lkbtbl_size, sizeof(dlm_lkbtbl_size), dlmf);
719  				if (sp == NULL)
720  					goto out_err;
721  				p = strchr(dlm_lkbtbl_size, '\n');
722  				if (p)
723  					*p = '\0';
724  				fclose(dlmf);
725  			} else {
726  				strcpy(dlm_lkbtbl_size, " ");
727  			}
728  		} else {
729  			strcpy(dlm_dirtbl_size, "nolock");
730  			strcpy(dlm_lkbtbl_size, "nolock");
731  			strcpy(dlm_lkbtbl_size, "nolock");
732  		}
733  	
734  		/* Read the inode in so we can see its type. */
735  		sscanf(id, "%"PRIx64, &block);
736  		if (block) {
737  			if (btype == 2)
738  				if (trace_dir_path)
739  					blk_type = show_inode(id, mp->fd, block);
740  				else
741  					blk_type = "";
742  			else
743  				blk_type = "";
744  		}
745  		return blk_type;
746  	out_err:
747  		fclose(dlmf);
748  		return "error";
749  	}
750  	
751  	static int is_dlm_waiting(int dlmwaiters, int locktype, char *id)
752  	{
753  		int i;
754  		int dlmid, wait_type, nodeid, type;
755  		char locknum[32];
756  	
757  		for (i = 0; i < dlmwaiters && i < 100; i++) {
758  			sscanf(dlmwlines[i], "%x %d %d        %d         %s",
759  			       &dlmid, &wait_type, &nodeid, &type, locknum);
760  			if ((type == locktype) && (!strcmp(locknum, id)))
761  				return 1;
762  		}
763  		return 0;
764  	}
765  	
766  	static const char *friendly_state(const char *glock_line, const char *search)
767  	{
768  		const char *p;
769  	
770  		p = strstr(glock_line, search);
771  	
772  		if (p == NULL)
773  			return "Dazed";
774  	
775  		p += 2;
776  		if (*p == 'E')
777  			return "Exclusive";
778  		else if (*p == 'S')
779  			return "Shared";
780  		else if (*p == 'U')
781  			return "Unlocked";
782  		else if (*p == 'D')
783  			return "Deferred";
784  		else
785  			return "Confused";
786  	}
787  	
788  	static const char *friendly_gflags(const char *glock_line)
789  	{
790  		static char flagout[PATH_MAX];
791  		const char *p;
792  	
793  		memset(flagout, 0, sizeof(flagout));
794  	
795  		p = strstr(glock_line, "f:");
796  		if (!p)
797  			return " ";
798  		p += 2;
799  		strcpy(flagout, "[");
800  		while (*p != ' ') {
801  			switch (*p) {
802  			case 'l':
803  				/*strcat(flagout, "Locked");*/
804  				break;
805  			case 'D':
806  				strcat(flagout, "Demoting");
807  				break;
808  			case 'd':
809  				strcat(flagout, "Demote pending");
810  				break;
811  			case 'p':
812  				strcat(flagout, "Demote in progress");
813  				break;
814  			case 'y':
815  				strcat(flagout, "Dirty");
816  				break;
817  			case 'f':
818  				strcat(flagout, "Flush");
819  				break;
820  			case 'i':
821  				strcat(flagout, "Invalidating");
822  				break;
823  			case 'r':
824  				strcat(flagout, "Reply pending");
825  				break;
826  			case 'I':
827  				/*strcat(flagout, "Initial");*/
828  				break;
829  			case 'F':
830  				strcat(flagout, "Frozen");
831  				break;
832  			case 'q':
833  				strcat(flagout, "Queued");
834  				break;
835  			case 'L':
836  				strcat(flagout, "LRU");
837  				break;
838  			case 'o':
839  				/*strcat(flagout, "Object present");*/
840  				break;
841  			case 'b':
842  				strcat(flagout, "Blocking");
843  				break;
844  			default:
845  				strcat(flagout, "Unknown");
846  				break;
847  			}
848  			if ((strlen(flagout)) > 1 && (!strchr(" lIo", *(p + 1))))
849  				strcat(flagout, ", ");
850  			p++;
851  		}
852  		strcat(flagout, "]");
853  		return flagout;
854  	}
855  	
856  	static const char *friendly_glock(const char *glock_line, char prefix)
857  	{
858  		static char gline[PATH_MAX];
859  	
860  		if (prefix == 'W')
861  			sprintf(gline, "Is:%s, Want:%s   %s",
862  				friendly_state(glock_line, "s:"),
863  				friendly_state(glock_line, "t:"),
864  				friendly_gflags(glock_line));
865  		else
866  			sprintf(gline, "Held:%s   %s",
867  				friendly_state(glock_line, "s:"),
868  				friendly_gflags(glock_line));
869  		return gline;
870  	}
871  	
872  	static const char *dlm_grtype(int grmode)
873  	{
874  		const char *dlm_types[8] = {"NL", "CR", "CW", "PR", "PW", "EX",
875  					    "NA", "NA"};
876  	
877  		if (grmode < 0)
878  			return "-1";
879  		return dlm_types[grmode & 0x07];
880  	}
881  	
882  	static const char *dlm_status(int status)
883  	{
884  		const char *dlm_statuses[4] = {"Unknown", "Waiting", "Granted",
885  					       "Converting"};
886  		if (status < 0)
887  			return "unknown";
888  		return dlm_statuses[status & 0x03];
889  	}
890  	
891  	static const char *dlm_nodeid(int lkbnodeid)
892  	{
893  		static char nodeid[16];
894  	
895  		if (lkbnodeid == 0)
896  			return "this node";
897  		sprintf(nodeid, "node %d", lkbnodeid);
898  		return nodeid;
899  	}
900  	
901  	static const char *getprocname(int ownpid)
902  	{
903  		char fn[1024];
904  		static char str[80];
905  		const char *procname;
906  		FILE *fp;
907  	
908  		sprintf(fn, "/proc/%d/status", ownpid);
909  		fp = fopen(fn, "r");
910  		if (fp == NULL)
911  			return "ended";
912  	
913  		if (fgets(str, 80, fp) != NULL) {
914  			char *p;
915  	
916  			p = strchr(str + 6, '\n');
917  			if (p)
918  				*p = '\0';
919  			procname = str + 6;
920  		} else
921  			procname = "unknown";
922  	
923  		fclose(fp);
924  		return procname;
925  	}
926  	
927  	static void show_dlm_grants(int locktype, const char *g_line, int dlmgrants,
928  				    int summary)
929  	{
930  		int i;
931  		char dlm_resid[75];
932  		unsigned int lkb_id, lkbnodeid, remid, ownpid, exflags, flags, status;
933  		unsigned int grmode, rqmode, nodeid, length;
934  		uint64_t xid, us;
935  		char trgt_res_name[64], res_name[64];
936  		const char *p1, *p2;
937  		const char *procname;
938  	
939  		p1 = strchr(g_line, '/');
940  		if (!p1)
941  			return;
942  		p1++;
943  		p2 = strchr(p1, ' ');
944  		if (!p2)
945  			return;
946  		memset(trgt_res_name, 0, sizeof(trgt_res_name));
947  		memcpy(trgt_res_name, p1, p2 - p1);
948  		sprintf(dlm_resid, "%8d%16s", locktype, trgt_res_name);
949  		for (i = 0; i < dlmgrants; i++) {
950  	/*
951  	lkb_id  n   remid  pid x e f s g rq u n ln res_name 1234567890123456
952  	1100003 1 2ae0006 8954 0 0 0 2 5 -1 0 1 24 "       2           102ab"
953  	2a20001 1 30d0001 8934 0 0 0 2 3 -1 0 1 24 "       5           102ab"
954  	  b0001 2  860001 8868 0 0 10000 2 3 -1 0 0 24 "       1               2"
955  	2450001 2 1be0002 8962 0 0 10000 1 -1 5 12214 0 24 "       2           102ab"
956  	*/
957  			p1 = strchr(dlmglines[i], '\"');
958  			if (!p1)
959  				continue;
960  			p1++;
961  			if (strncmp(dlm_resid, p1, 24))
962  				continue;
963  	
964  			sscanf(dlmglines[i], "%x %d %x %u %"SCNu64" %x %x %d %d %d %"SCNu64" "
965  			       "%u %d \"%24s\"\n",
966  			       &lkb_id, &lkbnodeid, &remid, &ownpid, &xid, &exflags,
967  			       &flags, &status, &grmode, &rqmode, &us, &nodeid,
968  			       &length, res_name);
969  			if (status == 1) { /* Waiting */
970  				if (!lkbnodeid)
971  					procname = getprocname(ownpid);
972  				else
973  					procname = "";
974  				if (summary)
975  					print_it(NULL, " (", NULL);
976  				else
977  					print_it(NULL, "  D: ", NULL);
978  				print_it(NULL, "%s for %s, pid %d %s", NULL,
979  					 dlm_status(status), dlm_nodeid(lkbnodeid),
980  					 ownpid, procname);
981  				if (summary)
982  					print_it(NULL, ")", NULL);
983  			} else if (grmode == 0) {
984  				continue; /* ignore "D: Granted NL on node X" */
985  			} else {
986  				procname = getprocname(ownpid);
987  				if (summary)
988  					print_it(NULL, " (", NULL);
989  				else
990  					print_it(NULL, "  D: ", NULL);
991  				print_it(NULL, "%s %s on %s to pid %d %s", NULL,
992  					 dlm_status(status), dlm_grtype(grmode),
993  					 dlm_nodeid(lkbnodeid), ownpid, procname);
994  				if (summary)
995  					print_it(NULL, ")", NULL);
996  			}
997  			if (!summary)
998  				eol(0);
999  		}
1000 	}
1001 	
1002 	static void print_call_trace(char *hline)
1003 	{
1004 		char *p, *pid, tmp[32], stackfn[64], str[96];
1005 		FILE *fp;
1006 		int i;
1007 	
1008 		p = strchr(hline, 'p');
1009 		if (!p)
1010 			return;
1011 		pid = p + 2;
1012 		p = strchr(pid, ' ');
1013 		if (!p)
1014 			return;
1015 		memset(tmp, 0, sizeof(tmp));
1016 		memcpy(tmp, pid, p - pid);
1017 		sprintf(stackfn, "/proc/%s/stack", tmp);
1018 		fp = fopen(stackfn, "rt");
1019 		if (fp == NULL)
1020 			return;
1021 		for (i = 0; i < MAX_CALLTRACE_LINES; i++) {
1022 			if (fgets(str, sizeof(str) - 1, fp) == NULL)
1023 				break;
1024 			if (strstr(str, "gfs2_glock_")) { /* skip lines we don't
1025 							      care about*/
1026 				i--;
1027 				continue;
1028 			}
1029 			p = strchr(str, '\n');
1030 			if (p)
1031 				*p = '\0';
1032 			p = strchr(str, ']');
1033 			if (p)
1034 				p += 2;
1035 			else
1036 				p = str;
1037 			print_it(NULL, "  C:              %s ", NULL, p);
1038 			eol(0);
1039 		}
1040 		fclose(fp);
1041 	}
1042 	
1043 	static int is_ex(const char *hline)
1044 	{
1045 		if (strncmp(hline, " H: s:EX ", 9) == 0)
1046 			return 1;
1047 		return 0;
1048 	}
1049 	
1050 	static int has_holder_flag(const char *hline, char flag)
1051 	{
1052 		const char *p;
1053 	
1054 		p = strchr(hline, 'f');
1055 		if (p == NULL)
1056 			return 0;
1057 		p++;
1058 		if (*p != ':')
1059 			return 0;
1060 		p++;
1061 		while (*p != '\0') {
1062 			if (*p == ' ')
1063 				return 0;
1064 			if (*p == flag)
1065 				return 1;
1066 			p++;
1067 		}
1068 		return 0;
1069 	}
1070 	
1071 	static int is_holder(const char *hline)
1072 	{
1073 		return has_holder_flag(hline, 'H');
1074 	}
1075 	
1076 	static int is_waiter(const char *hline)
1077 	{
1078 		return has_holder_flag(hline, 'W');
1079 	}
1080 	
1081 	static int get_lock_type(const char *str)
1082 	{
1083 		const char *p;
1084 	
(1) Event identity_transfer: Passing "str" as argument 1 to function "strchr", which returns an offset off that argument.
(2) Event tainted_data_transitive: Calling function "strchr" with tainted argument "str" results in tainted data.
(3) Event var_assign: Assigning: "p" = "strchr(str, 47)", which taints "p".
Also see events: [return_tainted_data]
1085 		p = strchr(str, '/');
(4) Event path: Condition "p", taking true branch.
(5) Event return_tainted_data: Returning tainted data "p ? *(p - 1) - 48 : 0".
Also see events: [identity_transfer][tainted_data_transitive][var_assign]
1086 		return (p ? (*(p - 1)) - '0' : 0);
1087 	}
1088 	
1089 	static long long get_demote_time(char *str)
1090 	{
1091 		char *p;
1092 		char tmp[80];
1093 	
1094 		p = strchr(str, '/');
1095 		if (p == NULL)
1096 			return 0;
1097 		p++;
1098 		p = strchr(p, '/');
1099 		if (p == NULL)
1100 			return 0;
1101 		p++;
1102 		strncpy(tmp, p, 79);
1103 		tmp[79] = '\0';
1104 		p = strchr(tmp, ' ');
1105 		if (p == NULL)
1106 			return 0;
1107 		*p = '\0';
1108 		return atoll(tmp);
1109 	}
1110 	
1111 	static const char *pid_string(char *str)
1112 	{
1113 		char *p;
1114 		static char pidstr[80];
1115 	
1116 		memset(pidstr, 0, sizeof(pidstr));
1117 		p = strchr(str, 'p');
1118 		if (p) {
1119 			strncpy(pidstr, p + 2, sizeof(pidstr));
1120 			pidstr[79] = '\0';
1121 			p = strchr(pidstr, ']');
1122 			if (p) {
1123 				p++;
1124 				*p = '\0';
1125 			}
1126 		}
1127 		return pidstr;
1128 	}
1129 	
1130 	/* If this glock is relevant, return 0, else the reason it's irrelevant */
1131 	static int irrelevant(const char *holder, const char *glockstr)
1132 	{
1133 		int lock_type = get_lock_type(glockstr);
1134 	
1135 		/* Exclude shared and locks */
1136 		if (!is_ex(holder))
1137 			return 1;
1138 		/* Exclude locks held at mount time: statfs*/
1139 		if (strstr(holder, "init_per_node"))
1140 			return 2;
1141 		if (strstr(holder, "init_journal"))
1142 			return 3;
1143 		if (strstr(holder, "init_inodes"))
1144 			return 4;
1145 		if (strstr(holder, "fill_super"))
1146 			return 5;
1147 		if (lock_type == 9) /* Exclude journal locks */
1148 			return 6;
1149 		return 0;
1150 	}
1151 	
1152 	static const char *reason(int why)
1153 	{
1154 		const char *reasons[] = {"(N/A:------)",  /* 0 */
1155 					 "(N/A:Not EX)",  /* 1 */
1156 					 "(N/A:System)",  /* 2 */
1157 					 "(N/A:journl)",  /* 3 */
1158 					 "(N/A:System)",  /* 4 */
1159 					 "(N/A:System)",  /* 5 */
1160 					 "(N/A:Journl)"}; /* 6 */
1161 	
1162 		return reasons[why];
1163 	}
1164 	
1165 	static void print_friendly_prefix(char one_glocks_lines[MAX_LINES][97])
1166 	{
1167 		int why = irrelevant(one_glocks_lines[1], one_glocks_lines[0]);
1168 	
1169 		if (why)
1170 			print_it(NULL, "  U: %s ", NULL, reason(why));
1171 		else
1172 			print_it(NULL, "  U: ", NULL);
1173 	}
1174 	
1175 	static void show_glock(char one_glocks_lines[MAX_LINES][97], int gline,
1176 			       const char *fsname, int dlmwaiters, int dlmgrants,
1177 			       int trace_dir_path, int prev_had_waiter, int flags,
1178 			       int summary)
1179 	{
1180 		int i, locktype = 0;
1181 		char id[33], *p;
1182 		char extras[80], prefix = '\0';
1183 		long long demote_time = 0;
1184 		const char *ltype[] = {"N/A", "non-disk", "inode", "rgrp", "meta",
1185 				       "i_open", "flock", "posix lock", "quota",
1186 				       "journal"};
1187 	
1188 		if (termlines) {
1189 			if (irrelevant(one_glocks_lines[1], one_glocks_lines[0]))
1190 				COLORS_HELD;
1191 			else
1192 				COLORS_NORMAL;
1193 		}
1194 		if (!gline)
1195 			return;
1196 	
1197 		memset(extras, 0, sizeof(extras));
1198 		p = strchr(one_glocks_lines[0], '/');
1199 		memset(id, 0, sizeof(id));
1200 	
1201 		if (p) {
1202 			locktype = get_lock_type(one_glocks_lines[0]);
1203 			demote_time = get_demote_time(one_glocks_lines[0]);
1204 			p++;
1205 			strncpy(id, p, sizeof(id) - 1);
1206 			id[sizeof(id) - 1] = '\0';
1207 			p = strchr(id, ' ');
1208 			if (p)
1209 				*p = '\0';
1210 	
1211 			if (locktype != 2) {
1212 				strncpy(extras, ltype[locktype], 79);
1213 				extras[79] = '\0';
1214 			} else {
1215 				const char *i_type = show_details(id, fsname, 2,
1216 								  trace_dir_path);
1217 				sprintf(extras, "%sinode", i_type);
1218 			}
1219 		}
1220 		if (flags & DETAILS) {
1221 			print_it(NULL, " %s ", NULL, one_glocks_lines[0]);
1222 			print_it(NULL, "(%s)", NULL, extras);
1223 			if (demote_time)
1224 				print_it(NULL, " ** demote time is greater than 0 **",
1225 					 NULL);
1226 			eol(0);
1227 			if (dlmgrants)
1228 				show_dlm_grants(locktype, one_glocks_lines[0],
1229 						dlmgrants, 0);
1230 		}
1231 		if (flags & FRIENDLY) {
1232 			print_friendly_prefix(one_glocks_lines);
1233 			for (i = 1; i < gline; i++) {
1234 				if (one_glocks_lines[i][0] == ' ' &&
1235 				    one_glocks_lines[i][1] == 'H' &&
1236 				    prefix != 'W')
1237 					prefix = (is_holder(one_glocks_lines[i]) ?
1238 						  'H' : 'W');
1239 			}
1240 			print_it(NULL, " %c %-10.10s %-9.9s %s", NULL, prefix,
1241 				 extras, id, friendly_glock(one_glocks_lines[0],
1242 							    prefix));
1243 			eol(0);
1244 		}
1245 		for (i = 1; i < gline; i++) {
1246 			if (!show_reservations &&
1247 			    one_glocks_lines[i][0] == ' ' &&
1248 			    one_glocks_lines[i][2] == 'B' &&
1249 			    one_glocks_lines[i][3] == ':')
1250 				continue;
1251 	
1252 			if (flags & DETAILS) {
1253 				print_it(NULL, " %-80.80s", NULL, one_glocks_lines[i]);
1254 				eol(0);
1255 				continue;
1256 			}
1257 			if ((flags & FRIENDLY) &&
1258 			    one_glocks_lines[i][1] == 'H')
1259 				print_friendly_prefix(one_glocks_lines);
1260 	
1261 			if (one_glocks_lines[i][0] == ' ' &&
1262 			    one_glocks_lines[i][1] == 'H') {
1263 				print_it(NULL, " %c ---> %s pid %s ", NULL,
1264 					 prefix, (is_holder(one_glocks_lines[i]) ?
1265 						  "held by" : "waiting"),
1266 					 pid_string(one_glocks_lines[i]));
1267 				if (demote_time)
1268 					print_it(NULL, "** demote time is non-"
1269 						 "zero ** ", NULL);
1270 				if (is_dlm_waiting(dlmwaiters, locktype, id)) {
1271 					print_it(NULL, "***** DLM is in a "
1272 						 "comm wait for this lock "
1273 						 "***** ", NULL);
1274 				}
1275 				show_dlm_grants(locktype, one_glocks_lines[0],
1276 						dlmgrants, 1);
1277 				eol(0);
1278 				print_call_trace(one_glocks_lines[i]);
1279 			}
1280 		}
1281 	}
1282 	
1283 	static int parse_dlm_waiters(FILE *dlm, const char *fsname)
1284 	{
1285 		int dlml = 0;
1286 	
1287 		memset(dlmwlines, 0, sizeof(dlmwlines));
1288 		while (fgets(dlmwlines[dlml], 80, dlm))
1289 			dlml++;
1290 	
1291 		return dlml;
1292 	}
1293 	
1294 	static int parse_dlm_grants(int dlmfd, const char *fsname)
1295 	{
1296 		int dlml = 0;
1297 		char *dlmline;
1298 	
1299 		memset(dlmglines, 0, sizeof(dlmglines));
1300 		dnextpos = NULL;
1301 		while ((dlmline = bufgets(dlmfd, dbuf, &dnextpos, &dpos, &dmaxpos))) {
1302 			if (!this_lkb_requested(dlmline))
1303 				continue;
1304 			strncpy(dlmglines[dlml], dlmline, 96);
1305 			dlmglines[dlml][96] = '\0';
1306 			dlml++;
1307 			if (dlml >= MAX_LINES)
1308 				break;
1309 		}
1310 		return dlml;
1311 	}
1312 	
1313 	static void print_summary(int total_glocks[11][stypes], int dlmwaiters)
1314 	{
1315 		int i;
1316 		int total_unlocked = 0;
1317 		const struct {
1318 			const char *name;
1319 			const int width;
1320 		} column[] = {
1321 			{ "unknown", 7 }, { "nondisk", 7}, { "inode", 8 }, { "rgrp", 7 },
1322 			{ "meta", 4 }, { "iopen", 7 }, { "flock", 7 }, { "p", 1 },
1323 			{ "quota", 5 }, { "jrnl", 4 }, { "Total", 8 }
1324 		};
1325 		const int ncols = sizeof(column) / sizeof(column[0]);
1326 	
1327 		/* Print column headers */
1328 		print_it(NULL, "S     glocks ", NULL);
1329 		for (i = 1; i < ncols; i++)
1330 			if (i != 7 && i != 4) /* Ignore plock and meta */
1331 				print_it(NULL, "%*s ", NULL, column[i].width, column[i].name);
1332 		eol(0);
1333 		print_it(NULL, "S  --------- ", NULL);
1334 		for (i = 1; i < ncols; i++)
1335 			if (i != 7 && i != 4) /* Ignore plock and meta */
1336 				print_it(NULL, "%*s ", NULL, column[i].width, "--------");
1337 		eol(0);
1338 	
1339 		/* Print rows */
1340 		print_it(NULL, "S  Unlocked: ", NULL);
1341 		for (i = 1; i < (ncols - 1); i++) {
1342 			if (i != 7 && i != 4) /* Ignore plock and meta */
1343 				print_it(NULL, "%*d ", NULL, column[i].width,
1344 					 total_glocks[i][all] - total_glocks[i][locked]);
1345 			total_unlocked += total_glocks[i][all] -
1346 				total_glocks[i][locked];
1347 		}
1348 		print_it(NULL, "%*d ", NULL, column[i].width, total_unlocked);
1349 		eol(0);
1350 		print_it(NULL, "S    Locked: ", NULL);
1351 		for (i = 1; i < ncols; i++) {
1352 			if (i != 7 && i != 4) /* Ignore plock and meta */
1353 				print_it(NULL, "%*d ", NULL, column[i].width,
1354 					 total_glocks[i][locked]);
1355 			total_glocks[10][locked] += total_glocks[i][locked];
1356 		}
1357 		eol(0);
1358 		print_it(NULL, "S     Total: ", NULL);
1359 		for (i = 1; i < ncols; i++) {
1360 			if (i != 7 && i != 4) /* Ignore plock and meta */
1361 				print_it(NULL, "%*d ", NULL, column[i].width,
1362 					 total_glocks[i][all]);
1363 			total_glocks[10][all] += total_glocks[i][all];
1364 		}
1365 		eol(0);
1366 		print_it(NULL, "S", NULL);
1367 		eol(0);
1368 		print_it(NULL, "S   Held EX: ", NULL);
1369 		for (i = 1; i < ncols; i++) {
1370 			if (i != 7 && i != 4) /* Ignore plock and meta */
1371 				print_it(NULL, "%*d ", NULL, column[i].width,
1372 					 total_glocks[i][held_ex]);
1373 			total_glocks[10][held_ex] += total_glocks[i][held_ex];
1374 		}
1375 		eol(0);
1376 		print_it(NULL, "S   Held SH: ", NULL);
1377 		for (i = 1; i < ncols; i++) {
1378 			if (i != 7 && i != 4) /* Ignore plock and meta */
1379 				print_it(NULL, "%*d ", NULL, column[i].width,
1380 					 total_glocks[i][held_sh]);
1381 			total_glocks[10][held_sh] += total_glocks[i][held_sh];
1382 		}
1383 		eol(0);
1384 		print_it(NULL, "S   Held DF: ", NULL);
1385 		for (i = 1; i < ncols; i++) {
1386 			if (i != 7 && i != 4) /* Ignore plock and meta */
1387 				print_it(NULL, "%*d ", NULL, column[i].width,
1388 					 total_glocks[i][held_df]);
1389 			total_glocks[10][held_df] += total_glocks[i][held_df];
1390 		}
1391 		eol(0);
1392 		print_it(NULL, "S G Waiting: ", NULL);
1393 		for (i = 1; i < ncols; i++) {
1394 			if (i != 7 && i != 4) /* Ignore plock and meta */
1395 				print_it(NULL, "%*d ", NULL, column[i].width,
1396 					 total_glocks[i][has_waiter]);
1397 			total_glocks[10][has_waiter] += total_glocks[i][has_waiter];
1398 		}
1399 		eol(0);
1400 		print_it(NULL, "S P Waiting: ", NULL);
1401 		for (i = 1; i < ncols; i++) {
1402 			if (i != 7 && i != 4) /* Ignore plock and meta */
1403 				print_it(NULL, "%*d ", NULL, column[i].width,
1404 					 total_glocks[i][tot_waiters]);
1405 			total_glocks[10][tot_waiters] += total_glocks[i][tot_waiters];
1406 		}
1407 		eol(0);
1408 		print_it(NULL, "S  DLM wait: %7d", NULL, dlmwaiters);
1409 		eol(0);
1410 		eol(0);
1411 	}
1412 	
1413 	/* flags = DETAILS || FRIENDLY or both */
1414 	static void glock_details(int fd, const char *fsname, int dlmwaiters,
1415 				  int dlmgrants, int trace_dir_path, int show_held,
1416 				  int summary)
1417 	{
1418 		char *ln, *p;
1419 		char one_glocks_lines[MAX_LINES][97];
1420 		int gline = 0;
1421 		int show_prev_glock = 0, prev_had_waiter = 0;
1422 		int total_glocks[11][stypes], locktype = 0;
1423 		int holders_this_glock_ex = 0;
1424 		int holders_this_glock_sh = 0;
1425 		int holders_this_glock_df = 0;
1426 		int waiters_this_glock = 0;
1427 	
1428 		memset(total_glocks, 0, sizeof(total_glocks));
1429 		gnextpos = NULL;
(1) Event tainted_return_value: Function "bufgets" returns tainted data. [details]
(2) Event var_assign: Assigning: "ln" = "bufgets(fd, gbuf, &gnextpos, &gpos, &gmaxpos)", which taints "ln".
(3) Event path: Condition "ln = bufgets(fd, gbuf, &gnextpos, &gpos, &gmaxpos)", taking true branch.
Also see events: [tainted_data_transitive][var_assign][tainted_data][remediation]
1430 		while ((ln = bufgets(fd, gbuf, &gnextpos, &gpos, &gmaxpos))) {
(4) Event path: Condition "ln[0] == ' '", taking true branch.
(5) Event path: Condition "ln[1] == ' '", taking true branch.
(6) Event path: Condition "ln[2] == ' '", taking false branch.
1431 			if (ln[0] == ' ' && ln[1] == ' ' && ln[2] == ' ')
1432 				continue;
(7) Event path: Condition "ln[0] == 'G'", taking true branch.
1433 			if (ln[0] == 'G') {
1434 				/* Summary stuff------------------------------------ */
(8) Event path: Condition "waiters_this_glock", taking false branch.
1435 				if (waiters_this_glock) {
1436 					total_glocks[locktype][tot_waiters] +=
1437 						waiters_this_glock;
1438 					total_glocks[locktype][has_waiter]++;
1439 				}
(9) Event path: Condition "holders_this_glock_ex", taking false branch.
1440 				if (holders_this_glock_ex)
1441 					total_glocks[locktype][held_ex]++;
(10) Event path: Condition "holders_this_glock_sh", taking false branch.
1442 				if (holders_this_glock_sh)
1443 					total_glocks[locktype][held_sh]++;
(11) Event path: Condition "holders_this_glock_df", taking false branch.
1444 				if (holders_this_glock_df)
1445 					total_glocks[locktype][held_df]++;
(12) Event tainted_data_transitive: Call to function "get_lock_type" with tainted argument "*ln" returns tainted data. [details]
(13) Event var_assign: Assigning: "locktype" = "get_lock_type(ln)", which taints "locktype".
Also see events: [tainted_return_value][var_assign][tainted_data][remediation]
1446 				locktype = get_lock_type(ln);
1447 				p = ln + 6;
(14) Event path: Condition "*p != 'U'", taking false branch.
(15) Event path: Condition "p[1] != 'N'", taking false branch.
1448 				if (*p != 'U' || *(p + 1) != 'N')
1449 					total_glocks[locktype][locked]++;
CID (unavailable; MK=3f4fec61aeccf1b1d9ae83151fa012f3) (#2 of 4): Untrusted array index write (TAINTED_SCALAR):
(16) Event tainted_data: Using tainted variable "locktype" as an index into an array "total_glocks".
(17) Event remediation: Ensure that tainted values are properly sanitized, by checking that their values are within a permissible range.
Also see events: [tainted_return_value][var_assign][tainted_data_transitive][var_assign]
1450 				total_glocks[locktype][all]++;
1451 				holders_this_glock_ex = 0;
1452 				holders_this_glock_sh = 0;
1453 				holders_this_glock_df = 0;
1454 				waiters_this_glock = 0;
1455 				/* Detail stuff------------------------------------- */
1456 				if (show_prev_glock) {
1457 					show_glock(one_glocks_lines, gline, fsname,
1458 						   dlmwaiters, dlmgrants,
1459 						   trace_dir_path, prev_had_waiter,
1460 						   DETAILS, summary);
1461 					show_glock(one_glocks_lines, gline, fsname,
1462 						   dlmwaiters, dlmgrants,
1463 						   trace_dir_path, prev_had_waiter,
1464 						   FRIENDLY, summary);
1465 					memset(one_glocks_lines, 0,
1466 					       sizeof(one_glocks_lines));
1467 					show_prev_glock = 0;
1468 				}
1469 				prev_had_waiter = 0;
1470 				gline = 0;
1471 				if (this_glock_requested(ln))
1472 					show_prev_glock = 1;
1473 			} else if (ln[0] == ' ' && ln[1] == 'H') {
1474 				char *flag = strchr(ln, 'f');
1475 				char *mode = strchr(ln, 's');
1476 	
1477 				/* Summary stuff------------------------------------ */
1478 				while (flag) {
1479 					flag++;
1480 					switch (*flag) {
1481 					case ':':
1482 						break;
1483 					case 'W':
1484 						waiters_this_glock++;
1485 						flag = NULL;
1486 						break;
1487 					case 'H':
1488 						flag = NULL;
1489 						if (mode == NULL)
1490 							holders_this_glock_df++;
1491 						else if (*(mode + 1) == ':' &&
1492 							 *(mode + 2) == 'E' &&
1493 							 *(mode + 3) == 'X')
1494 							holders_this_glock_ex++;
1495 						else if (*(mode + 1) == ':' &&
1496 							 *(mode + 2) == 'S' &&
1497 							 *(mode + 3) == 'H')
1498 							holders_this_glock_sh++;
1499 						else
1500 							holders_this_glock_df++;
1501 						break;
1502 					case ' ':
1503 						flag = NULL;
1504 						break;
1505 					default:
1506 						break;
1507 					};
1508 				}
1509 				/* Detail stuff------------------------------------- */
1510 				if (!glocks) {
1511 					int haswaiter = is_waiter(ln);
1512 	
1513 					if (haswaiter) {
1514 						show_prev_glock = 1;
1515 						prev_had_waiter = 1;
1516 					} else if (show_held && is_holder(ln) &&
1517 						   !is_iopen(one_glocks_lines[0])) {
1518 						show_prev_glock = 1;
1519 					} else if (!irrelevant(ln, one_glocks_lines[0])) {
1520 						show_prev_glock = 1;
1521 					}
1522 				}
1523 			}
1524 			/* Detail stuff--------------------------------------------- */
1525 			strncpy(one_glocks_lines[gline], ln, 96);
1526 			one_glocks_lines[gline][96] = '\0';
1527 			gline++;
1528 			if (gline >= MAX_LINES)
1529 				break;
1530 			if (termlines && line >= termlines)
1531 				break;
1532 		}
1533 		/* Detail stuff----------------------------------------------------- */
1534 		if (show_prev_glock && gline < MAX_LINES &&
1535 		    (!termlines || line < termlines)) {
1536 			show_glock(one_glocks_lines, gline, fsname, dlmwaiters,
1537 				   dlmgrants, trace_dir_path, prev_had_waiter,
1538 				   DETAILS, summary);
1539 			show_glock(one_glocks_lines, gline, fsname, dlmwaiters,
1540 				   dlmgrants, trace_dir_path, prev_had_waiter,
1541 				   FRIENDLY, summary);
1542 		}
1543 		if (!summary || ((iters_done % summary) != 0))
1544 			return;
1545 	
1546 		print_summary(total_glocks, dlmwaiters);
1547 	}
1548 	
1549 	static void show_help(int help)
1550 	{
1551 		if (help == 1) {
1552 			COLORS_NORMAL;
1553 			eol(0);
1554 			print_it(NULL, "  Glock flags:                 ", NULL);
1555 			eol(0);
1556 			print_it(NULL, "    l - Locked                 ", NULL);
1557 			print_it(NULL, "    r - Reply pending          ", NULL);
1558 			eol(0);
1559 			print_it(NULL, "    d - Demote pending         ", NULL);
1560 			print_it(NULL, "    I - Initial                ", NULL);
1561 			eol(0);
1562 			print_it(NULL, "    D - Demote requested       ", NULL);
1563 			print_it(NULL, "    F - Frozen                 ", NULL);
1564 			eol(0);
1565 			print_it(NULL, "    p - Demote in progress     ", NULL);
1566 			print_it(NULL, "    q - Queued holder          ", NULL);
1567 			eol(0);
1568 			print_it(NULL, "    y - Dirty data             ", NULL);
1569 			print_it(NULL, "    L - LRU                    ", NULL);
1570 			eol(0);
1571 			print_it(NULL, "    f - Flush                  ", NULL);
1572 			print_it(NULL, "    o - Object present         ", NULL);
1573 			eol(0);
1574 			print_it(NULL, "    i - Invalidating           ", NULL);
1575 			print_it(NULL, "    b - Blocking request       ", NULL);
1576 			eol(0);
1577 		} else if (help == 2) {
1578 			COLORS_NORMAL;
1579 			eol(0);
1580 			print_it(NULL, "  Holder flags:                ", NULL);
1581 			eol(0);
1582 			print_it(NULL, "    t - Try (non-blocking)     ", NULL);
1583 			print_it(NULL, "    E - Exact lock             ", NULL);
1584 			eol(0);
1585 			print_it(NULL, "    T - Try with callback      ", NULL);
1586 			print_it(NULL, "    c - No Cache lock          ", NULL);
1587 			eol(0);
1588 			print_it(NULL, "    e - No exp                 ", NULL);
1589 			print_it(NULL, "    H - Held (locked)          ", NULL);
1590 			eol(0);
1591 			print_it(NULL, "    A - Any lock               ", NULL);
1592 			print_it(NULL, "    W - Waiting for lock       ", NULL);
1593 			eol(0);
1594 			print_it(NULL, "    p - Priority lock          ", NULL);
1595 			print_it(NULL, "    a - Asynchronous lock      ", NULL);
1596 			eol(0);
1597 			print_it(NULL, "    F - First                  ", NULL);
1598 			eol(0);
1599 		}
1600 	}
1601 	
1602 	/* flags = DETAILS || FRIENDLY or both */
1603 	static void parse_glocks_file(int fd, const char *fsname, int dlmwaiters,
1604 				      int dlmgrants, int trace_dir_path,
1605 				      int show_held, int help, int summary)
1606 	{
1607 		char fstitle[96], *fsdlm;
1608 		char ctimestr[64];
1609 		time_t t;
1610 		int i;
1611 	
1612 		tzset();
1613 		t = time(NULL);
1614 		strftime(ctimestr, 64, "%a %b %d %T %Y", localtime(&t));
1615 		ctimestr[63] = '\0';
1616 		memset(fstitle, 0, sizeof(fstitle));
1617 		fsdlm = calloc(1, 105 + dlmwaiters);
1618 		if (!fsdlm) {
1619 			printf("Failed to allocate fsdlm\n");
1620 			exit(-1);
1621 		}
1622 	
1623 		sprintf(fstitle, "@ %.22s       %s ", fsname, ctimestr);
1624 		if (dlmwaiters) {
1625 			sprintf(fsdlm, "dlm: %s/%s/%s [", dlm_dirtbl_size,
1626 				dlm_rsbtbl_size, dlm_lkbtbl_size);
1627 			for (i = 0; i < dlmwaiters; i++)
1628 				strcat(fsdlm, "*");
1629 			for (; i < 10; i++)
1630 				strcat(fsdlm, " ");
1631 			strcat(fsdlm, "]");
1632 		}
1633 		attron(A_BOLD);
1634 		print_it(NULL, "%s @%s %s", NULL, fstitle, hostname, fsdlm);
1635 		free(fsdlm);
1636 		eol(0);
1637 		attroff(A_BOLD);
1638 		glock_details(fd, fsname, dlmwaiters, dlmgrants, trace_dir_path,
1639 			      show_held, summary);
1640 	
1641 		show_help(help);
1642 		if (termlines)
1643 			refresh();
1644 	}
1645 	
1646 	static void usage(void)
1647 	{
1648 		printf("Usage:\n");
1649 		printf("glocktop [-i] [-d <delay sec>] [-n <iter>] [-sX] [-c] [-D] [-H] [-r] [-t]\n");
1650 		printf("\n");
1651 		printf("-i : Runs glocktop in interactive mode.\n");
1652 		printf("-d : delay between refreshes, in seconds (default: %d).\n", REFRESH_TIME);
1653 		printf("-n : stop after <iter> refreshes.\n");
1654 		printf("-H : don't show Held glocks, even if not waited on, excluding "
1655 		       "iopen\n");
1656 		printf("-r : show reservations when rgrp glocks are displayed\n");
1657 		printf("-s : show glock summary information every X iterations\n");
1658 		printf("-t : trace directory glocks back\n");
1659 		printf("-D : don't show DLM lock status\n");
1660 		printf("\n");
1661 		fflush(stdout);
1662 		exit(0);
1663 	}
1664 	
1665 	int main(int argc, char **argv)
1666 	{
1667 		int fd;
1668 		DIR *dir = NULL;
1669 		char *fn;
1670 		struct dirent *dent;
1671 		int retval;
1672 		int refresh_time = REFRESH_TIME;
1673 		fd_set readfds;
1674 		char string[96];
1675 		int ch, dlmwaiters = 0, dlmgrants = 0;
1676 		int cont = TRUE, optchar;
1677 		int trace_dir_path = 0;
1678 		int show_held = 1, help = 0;
1679 		int interactive = 0;
1680 		int summary = 10;
1681 		int nfds = STDIN_FILENO + 1;
1682 	
1683 		prog_name = argv[0];
1684 		memset(glock, 0, sizeof(glock));
1685 		memset(contended_filenames, 0, sizeof(contended_filenames));
1686 		memset(contended_blocks, 0, sizeof(contended_blocks));
1687 		UpdateSize(0);
1688 		/* decode command line arguments */
1689 		while (cont) {
1690 			optchar = getopt(argc, argv, "-d:Dn:rs:thHi");
1691 	
1692 			switch (optchar) {
1693 			case 'd':
1694 				refresh_time = atoi(optarg);
1695 				if (refresh_time < 1) {
1696 					fprintf(stderr, "Error: delay %d too small; "
1697 						"must be at least 1\n", refresh_time);
1698 					exit(-1);
1699 				}
1700 				break;
1701 			case 'D':
1702 				print_dlm_grants = 0;
1703 				break;
1704 			case 'n':
1705 				iterations = atoi(optarg);
1706 				break;
1707 			case 'r':
1708 				show_reservations = 1;
1709 				break;
1710 			case 's':
1711 				summary = atoi(optarg);
1712 				break;
1713 			case 't':
1714 				trace_dir_path = 1;
1715 				break;
1716 			case 'h':
1717 				usage();
1718 				break;
1719 			case 'H':
1720 				show_held = 0; /* held, but not iopen held */
1721 				break;
1722 			case 'i':
1723 				interactive = 1;
1724 				break;
1725 			case EOF:
1726 				cont = FALSE;
1727 				break;
1728 			case 1:
1729 				if  (optarg && glocks < MAX_GLOCKS)
1730 					glock[glocks++] = optarg;
1731 				break;
1732 	
1733 			default:
1734 				fprintf(stderr, "unknown option: %c\n", optchar);
1735 				exit(-1);
1736 			};
1737 		}
1738 	
1739 		if (interactive) {
1740 			printf("Initializing. Please wait...");
1741 			fflush(stdout);
1742 		}
1743 		if (gethostname(hostname, sizeof(hostname))) {
1744 			fprintf(stderr, "Error: unable to determine host name.\n");
1745 			exit(-1);
1746 		}
1747 		if (parse_mounts())
1748 			exit(-1);
1749 	
1750 		if (interactive && (wind = initscr()) == NULL) {
1751 			fprintf(stderr, "Error: unable to initialize screen.\n");
1752 			exit(-1);
1753 		}
1754 	
1755 		if (interactive) {
1756 			/* Do our initial screen stuff: */
1757 			signal(SIGWINCH, UpdateSize); /* handle term resize signal */
1758 			UpdateSize(0); /* update screen size based on term settings */
1759 			clear(); /* don't use Erase */
1760 			start_color();
1761 			noecho();
1762 			keypad(stdscr, TRUE);
1763 			raw();
1764 			curs_set(0);
1765 			init_colors();
1766 		} else {
1767 			termlines = 0;
1768 		}
1769 		while (!gbuf) {
1770 			gbuf = malloc(bufsize);
1771 			if (gbuf) {
1772 				/*printf("bufsize=%dK\n", bufsize / 1024);*/
1773 				break;
1774 			}
1775 			bufsize /= 2;
1776 		}
1777 		while (!dbuf) {
1778 			dbuf = malloc(bufsize);
1779 			if (dbuf) {
1780 				/*printf("bufsize=%dK\n", bufsize / 1024);*/
1781 				break;
1782 			}
1783 			bufsize /= 2;
1784 		}
1785 	
1786 		while (!done) {
1787 			struct timeval tv;
1788 	
1789 			if (asprintf(&fn, "%s/gfs2/", debugfs) == -1) {
1790 				perror(argv[0]);
1791 				exit(-1);
1792 			}
1793 			dir = opendir(fn);
1794 			free(fn);
1795 	
1796 			if (!dir) {
1797 				if (interactive) {
1798 					refresh();
1799 					endwin();
1800 				}
1801 				fprintf(stderr, "Unable to open gfs2 debugfs directory.\n");
1802 				fprintf(stderr, "Check if debugfs and gfs2 are mounted.\n");
1803 				exit(-1);
1804 			}
1805 			display_title_lines();
1806 			while ((dent = readdir(dir))) {
1807 				const char *fsname;
1808 				char *dlm_fn;
1809 				FILE *dlmf;
1810 				int dlmfd;
1811 	
1812 				if (!strcmp(dent->d_name, "."))
1813 					continue;
1814 				if (!strcmp(dent->d_name, ".."))
1815 					continue;
1816 	
1817 				fsname = strchr(dent->d_name, ':');
1818 				if (fsname)
1819 					fsname++;
1820 				else
1821 					fsname = dent->d_name;
1822 	
1823 				if (asprintf(&dlm_fn, "%s/dlm/%s_waiters", debugfs, fsname) == -1) {
1824 					perror("Failed to construct dlm waiters debugfs path");
1825 					exit(-1);
1826 				}
1827 				dlmf = fopen(dlm_fn, "rt");
1828 				if (dlmf) {
1829 					dlmwaiters = parse_dlm_waiters(dlmf, fsname);
1830 					fclose(dlmf);
1831 				}
1832 				free(dlm_fn);
1833 	
1834 				if (print_dlm_grants) {
1835 					if (asprintf(&dlm_fn, "%s/dlm/%s_locks", debugfs, fsname) == -1) {
1836 						perror("Failed to construct dlm locks debugfs path");
1837 						exit(-1);
1838 					}
1839 					dlmfd = open(dlm_fn, O_RDONLY);
1840 					if (dlmfd > 0) {
1841 						dlmgrants = parse_dlm_grants(dlmfd,
1842 									     fsname);
1843 						close(dlmfd);
1844 					}
1845 					free(dlm_fn);
1846 				}
1847 	
1848 				if (asprintf(&fn, "%s/gfs2/%s/glocks", debugfs, dent->d_name) == -1) {
1849 					perror(argv[0]);
1850 					exit(-1);
1851 				}
1852 				fd = open(fn, O_RDONLY);
1853 				if (fd < 0) {
1854 					if (interactive) {
1855 						refresh();
1856 						endwin();
1857 					}
1858 					perror(fn);
1859 					free(fn);
1860 					exit(-1);
1861 				}
1862 				free(fn);
1863 				parse_glocks_file(fd, fsname, dlmwaiters, dlmgrants,
1864 						  trace_dir_path, show_held, help,
1865 						  summary);
1866 				close(fd);
1867 			}
1868 			closedir(dir);
1869 			tv.tv_sec = refresh_time;
1870 			tv.tv_usec = 0;
1871 			FD_ZERO(&readfds);
1872 			if (nfds != 0)
1873 				FD_SET(STDIN_FILENO, &readfds);
1874 			retval = select(nfds, &readfds, NULL, NULL, &tv);
1875 			if (retval) {
1876 				if (interactive)
1877 					ch = getch();
1878 				else
1879 					ch = getchar();
1880 				switch (ch) {
1881 				case 0x1b: /* mount wheel? */
1882 				case 0x03:
1883 				case 'q':
1884 					done = 1;
1885 					break;
1886 				case 'h':
1887 					help = (help + 1) % 3;
1888 					break;
1889 				case 's':
1890 					if (!interactive)
1891 						break;
1892 					move(1, 0);
1893 					printw("Change delay from %d to: ",
1894 					       refresh_time);
1895 					if (bobgets(string, 1, 25, 5, &ch) == 1)
1896 						refresh_time = atoi(string);
1897 					if (refresh_time < 1)
1898 						refresh_time = 1;
1899 					break;
1900 				/* When we get EOF on stdin, remove it from the fd_set
1901 				   to avoid shorting out the select() */
1902 				case EOF:
1903 					nfds = 0;
1904 					break;
1905 				}
1906 			}
1907 			iters_done++;
1908 			if (iterations && iters_done >= iterations)
1909 				break;
1910 		}
1911 		free_mounts();
1912 		free(gbuf);
1913 		free(dbuf);
1914 		free(debugfs);
1915 		if (interactive) {
1916 			refresh();
1917 			endwin();
1918 		}
1919 		exit(0);
1920 	}
1921