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
main(int argc,char * argv[])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
exitusage()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
printstatusline(char * fn,char * locktype,char * comment)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
printstatus(char * fn)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
flushfs(char * fn)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
lockfs(char * fn)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
getmntnames()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
getcmdnames(int argc,char ** argv,int i)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