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 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 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 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 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 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 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 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 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