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