xref: /illumos-gate/usr/src/cmd/fs.d/ufs/lockfs/lockfs.c (revision 4de2612967d06c4fdbf524a62556a1e8118a006f)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * lockfs
31  *	user interface to lockfs functionality
32  */
33 #include <sys/types.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <unistd.h>
37 #include <fcntl.h>
38 #include <sys/mntent.h>
39 #include <sys/mnttab.h>
40 #include <errno.h>
41 #include <sys/lockfs.h>
42 #include <sys/filio.h>
43 
44 #define	bzero(s, n)	memset(s, 0, n);
45 
46 /*
47  * command line processing
48  */
49 extern char	*optarg;
50 extern int	optind;
51 extern int	opterr;
52 
53 extern void exit();
54 
55 static void exitusage();
56 static void printstatusline();
57 static void printstatus();
58 static void flushfs();
59 static void lockfs();
60 static void getmntnames();
61 static void getcmdnames();
62 
63 /*
64  * -a = all
65  * -v = verbose
66  */
67 int all		= 0;
68 int verbose	= 0;
69 
70 /*
71  * exitstatus
72  *	0 all ok
73  *	1 internal error
74  *	2 system call error
75  */
76 int exitstatus	= 0;
77 
78 /*
79  * list of filenames
80  */
81 struct filename {
82 	struct filename	*fn_next;
83 	char		*fn_name;
84 };
85 struct filename	*fnanchor	= 0;
86 
87 /*
88  * default request is `file system lock status'
89  * default lock type is `unlock'
90  * -wnduhfe changes them
91  */
92 int request	= _FIOLFSS;
93 u_short	lock	= LOCKFS_ULOCK;
94 
95 /*
96  * default comment is null
97  *	-c changes it
98  */
99 caddr_t comment	= 0;
100 u_long	comlen	= 0;
101 
102 /*
103  * for prettyprint
104  */
105 int firsttime	= 0;
106 
107 /*
108  * no unlocks printed
109  */
110 int no_unlocks_printed	= 0;
111 
112 /*
113  * file system was modified during hlock/wlock/elock
114  */
115 #define	LOCKWARN(FN, S)	\
116 { \
117 	if (verbose) \
118 		printf("WARNING: %s was modified while %s locked\n", FN, S); \
119 	exitstatus = 2; \
120 }
121 
122 /*
123  * forward reference
124  */
125 char	*malloc();
126 
127 void
128 main(argc, argv)
129 	int		argc;
130 	char		**argv;
131 {
132 	int		c;
133 	struct filename	*fnp;
134 
135 	exitstatus = 0;
136 
137 	/*
138 	 * process command line
139 	 */
140 	opterr = 0;
141 	optarg = 0;
142 
143 	while ((c = getopt(argc, argv, "vfwnduheac:")) != -1)
144 		switch (c) {
145 		case 'v':
146 			verbose = 1;
147 			break;
148 		case 'f':
149 			request = _FIOFFS;
150 			break;
151 		case 'w':
152 			lock    = LOCKFS_WLOCK;
153 			request = _FIOLFS;
154 			break;
155 		case 'n':
156 			lock    = LOCKFS_NLOCK;
157 			request = _FIOLFS;
158 			break;
159 		case 'd':
160 			lock    = LOCKFS_DLOCK;
161 			request = _FIOLFS;
162 			break;
163 		case 'h':
164 			lock    = LOCKFS_HLOCK;
165 			request = _FIOLFS;
166 			break;
167 		case 'e':
168 			lock	= LOCKFS_ELOCK;
169 			request = _FIOLFS;
170 			break;
171 		case 'u':
172 			lock    = LOCKFS_ULOCK;
173 			request = _FIOLFS;
174 			break;
175 		case 'a':
176 			all = 1;
177 			break;
178 		case 'c':
179 			comment = optarg;
180 			comlen  = strlen(optarg)+1;
181 			request = _FIOLFS;
182 			break;
183 		default:
184 			exitusage();
185 			break;
186 		}
187 
188 	if (argc == 1) {
189 		no_unlocks_printed = 1;
190 		all = 1;
191 	}
192 
193 	if (all)
194 		/*
195 		 * use /etc/mtab
196 		 */
197 		getmntnames();
198 	else
199 		/*
200 		 * use command line
201 		 */
202 		getcmdnames(argc, argv, optind);
203 
204 	/*
205 	 * for each filename, doit
206 	 */
207 	for (fnp = fnanchor; fnp; fnp = fnp->fn_next) {
208 		switch (request) {
209 		case _FIOLFSS:
210 			printstatus(fnp->fn_name);
211 			break;
212 		case _FIOLFS:
213 			lockfs(fnp->fn_name);
214 			break;
215 		case _FIOFFS:
216 			flushfs(fnp->fn_name);
217 			break;
218 		default:
219 			break;
220 		}
221 	}
222 
223 	/*
224 	 * all done
225 	 */
226 	exit(exitstatus);
227 }
228 /*
229  * exitusage
230  *	bad command line, give hint
231  */
232 void
233 exitusage()
234 {
235 	printf("usage: lockfs [-dfhnuw] [-c string] [-a] [file system ...]\n");
236 	exit(1);
237 }
238 /*
239  * printstatusline
240  * 	prettyprint the status line
241  */
242 void
243 printstatusline(fn, locktype, comment)
244 	char	*fn;
245 	char	*locktype;
246 	char	*comment;
247 {
248 	if (firsttime++ == 0)
249 		printf("%-20s %-10s %s\n", "Filesystem", "Locktype", "Comment");
250 	printf("%-20s %-10s %s\n", fn, locktype, comment);
251 }
252 /*
253  * printstatus
254  *	get and prettyprint file system lock status
255  */
256 void
257 printstatus(fn)
258 	char		*fn;
259 {
260 	int		fd;
261 	int		fsmod	= 0;
262 	char		*locktype;
263 	char		commentbuffer[LOCKFS_MAXCOMMENTLEN+1];
264 	struct lockfs	lf;
265 
266 	fd = open64(fn, O_RDONLY);
267 	if (fd == -1) {
268 		if (errno == EIO)
269 			printstatusline(fn, "EIO", "May be hard locked");
270 		else
271 			perror(fn);
272 		exitstatus = 2;
273 		return;
274 	}
275 
276 	bzero((caddr_t)&lf, sizeof (struct lockfs));
277 
278 	lf.lf_flags   = LOCKFS_MOD;
279 	lf.lf_comlen  = LOCKFS_MAXCOMMENTLEN;
280 	lf.lf_comment = commentbuffer;
281 
282 	if (ioctl(fd, _FIOLFSS, &lf) == -1) {
283 		perror(fn);
284 		close(fd);
285 		exitstatus = 2;
286 		return;
287 	}
288 	switch (lf.lf_lock) {
289 	case LOCKFS_ULOCK:
290 		if (no_unlocks_printed)
291 			goto out;
292 		if (LOCKFS_IS_BUSY(&lf))
293 			locktype = "(unlock)";
294 		else
295 			locktype = "unlock";
296 		break;
297 	case LOCKFS_WLOCK:
298 		if (LOCKFS_IS_BUSY(&lf))
299 			locktype = "(write)";
300 		else {
301 			locktype = "write";
302 			fsmod = LOCKFS_IS_MOD(&lf);
303 		}
304 		break;
305 	case LOCKFS_NLOCK:
306 		if (LOCKFS_IS_BUSY(&lf))
307 			locktype = "(name)";
308 		else
309 			locktype = "name";
310 		break;
311 	case LOCKFS_DLOCK:
312 		locktype = "delete";
313 		if (LOCKFS_IS_BUSY(&lf))
314 			locktype = "(delete)";
315 		else
316 			locktype = "delete";
317 		break;
318 	case LOCKFS_HLOCK:
319 		if (LOCKFS_IS_BUSY(&lf))
320 			locktype = "(hard)";
321 		else {
322 			locktype = "hard";
323 			fsmod = LOCKFS_IS_MOD(&lf);
324 		}
325 		break;
326 	case LOCKFS_ELOCK:
327 		if (LOCKFS_IS_BUSY(&lf))
328 			locktype = "(error)";
329 		else {
330 			locktype = "error";
331 			fsmod = LOCKFS_IS_MOD(&lf);
332 		}
333 		break;
334 	default:
335 		if (LOCKFS_IS_BUSY(&lf))
336 			locktype = "(unknown)";
337 		else
338 			locktype = "unknown";
339 		break;
340 	}
341 	lf.lf_comment[lf.lf_comlen] = '\0';
342 	printstatusline(fn, locktype, lf.lf_comment);
343 	if (fsmod)
344 		LOCKWARN(fn, locktype);
345 out:
346 	close(fd);
347 }
348 /*
349  * flushfs
350  *	push and invalidate at least the data that is *currently* dirty
351  */
352 void
353 flushfs(fn)
354 	char		*fn;
355 {
356 	int		fd;
357 
358 	fd = open64(fn, O_RDONLY);
359 	if (fd == -1) {
360 		perror(fn);
361 		exitstatus = 2;
362 		return;
363 	}
364 
365 	if (ioctl(fd, _FIOFFS, NULL) == -1) {
366 		perror(fn);
367 		close(fd);
368 		exitstatus = 2;
369 		return;
370 	}
371 	close(fd);
372 }
373 /*
374  * lockfs
375  *	lock the file system
376  */
377 void
378 lockfs(fn)
379 	char	*fn;
380 {
381 	int		fd;
382 	struct lockfs	lf;
383 
384 	fd = open64(fn, O_RDONLY);
385 	if (fd == -1) {
386 		perror(fn);
387 		exitstatus = 2;
388 		return;
389 	}
390 
391 	bzero((caddr_t)&lf, sizeof (struct lockfs));
392 
393 	lf.lf_flags = LOCKFS_MOD;
394 	if (ioctl(fd, _FIOLFSS, &lf) == -1) {
395 		perror(fn);
396 		close(fd);
397 		exitstatus = 2;
398 		return;
399 	}
400 
401 	if (!LOCKFS_IS_BUSY(&lf) && LOCKFS_IS_MOD(&lf)) {
402 		if (LOCKFS_IS_HLOCK(&lf))
403 			LOCKWARN(fn, "hard");
404 		if (LOCKFS_IS_ELOCK(&lf))
405 			LOCKWARN(fn, "error");
406 		if (LOCKFS_IS_WLOCK(&lf))
407 			LOCKWARN(fn, "write");
408 	}
409 
410 	lf.lf_lock	= lock;
411 	lf.lf_flags	= 0;
412 	lf.lf_key	= lf.lf_key;
413 	lf.lf_comment	= comment;
414 	lf.lf_comlen	= (comment) ? strlen(comment)+1 : 0;
415 
416 	if (ioctl(fd, _FIOLFS, &lf) == -1) {
417 		perror(fn);
418 		close(fd);
419 		exitstatus = 2;
420 		return;
421 	}
422 	close(fd);
423 }
424 /*
425  * getmntnames
426  *	file names from /etc/mtab
427  */
428 void
429 getmntnames()
430 {
431 	int		fnlen;
432 	struct filename	*fnp;
433 	struct filename	*fnpc;
434 	FILE		*mnttab;
435 	struct mnttab	mnt, *mntp = &mnt;
436 
437 	fnpc = fnanchor;
438 
439 	if ((mnttab = fopen(MNTTAB, "r")) == NULL) {
440 		fprintf(stderr, "Can't open %s\n", MNTTAB);
441 		perror(MNTTAB);
442 		exit(32);
443 	}
444 	while ((getmntent(mnttab, mntp)) == 0) {
445 		if (strcmp(mntp->mnt_fstype, MNTTYPE_UFS) != 0)
446 			continue;
447 		fnlen = strlen(mntp->mnt_mountp) + 1;
448 		fnp = (struct filename *)malloc(sizeof (struct filename));
449 		fnp->fn_name = malloc((u_int)fnlen);
450 		strcpy(fnp->fn_name, mntp->mnt_mountp);
451 		fnp->fn_next = NULL;
452 		if (fnpc)
453 			fnpc->fn_next = fnp;
454 		else
455 			fnanchor = fnp;
456 		fnpc = fnp;
457 	}
458 	fclose(mnttab);
459 }
460 /*
461  * getcmdnames
462  *	file names from command line
463  */
464 void
465 getcmdnames(argc, argv, i)
466 	int	argc;
467 	char	**argv;
468 	int	i;
469 {
470 	struct filename	*fnp;
471 	struct filename	*fnpc;
472 
473 	for (fnpc = fnanchor; i < argc; ++i) {
474 		fnp = (struct filename *)malloc(sizeof (struct filename));
475 		fnp->fn_name = *(argv+i);
476 		fnp->fn_next = NULL;
477 		if (fnpc)
478 			fnpc->fn_next = fnp;
479 		else
480 			fnanchor = fnp;
481 		fnpc = fnp;
482 	}
483 }
484