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