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