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