Print this page
6136 sysmacros.h unnecessarily polutes the namespace
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/fuser/fuser.c
+++ new/usr/src/cmd/fuser/fuser.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License, Version 1.0 only
6 6 * (the "License"). You may not use this file except in compliance
7 7 * with the License.
8 8 *
9 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 10 * or http://www.opensolaris.org/os/licensing.
11 11 * See the License for the specific language governing permissions
12 12 * and limitations under the License.
13 13 *
14 14 * When distributing Covered Code, include this CDDL HEADER in each
15 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 16 * If applicable, add the following below this CDDL HEADER, with the
↓ open down ↓ |
16 lines elided |
↑ open up ↑ |
17 17 * fields enclosed by brackets "[]" replaced with your own identifying
18 18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 19 *
20 20 * CDDL HEADER END
21 21 */
22 22 /*
23 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 */
26 26
27 -#pragma ident "%Z%%M% %I% %E% SMI"
28 -
29 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
30 28 /* All Rights Reserved */
31 29
32 30
33 31 #include <errno.h>
34 32 #include <fcntl.h>
35 33 #include <kstat.h>
36 34 #include <libdevinfo.h>
37 35 #include <locale.h>
38 36 #include <pwd.h>
39 37 #include <signal.h>
40 38 #include <stdio.h>
↓ open down ↓ |
2 lines elided |
↑ open up ↑ |
41 39 #include <stdlib.h>
42 40 #include <string.h>
43 41 #include <unistd.h>
44 42 #include <sys/mnttab.h>
45 43 #include <sys/modctl.h>
46 44 #include <sys/stat.h>
47 45 #include <sys/sysmacros.h>
48 46 #include <sys/types.h>
49 47 #include <sys/utssys.h>
50 48 #include <sys/var.h>
49 +#include <sys/mkdev.h>
51 50
52 51 /*
53 52 * Command line options for fuser command. Mutually exclusive.
54 53 */
55 54 #define OPT_FILE_ONLY 0x0001 /* -f */
56 55 #define OPT_CONTAINED 0x0002 /* -c */
57 56
58 57 /*
59 58 * Command line option modifiers for fuser command.
60 59 */
61 60 #define OPT_SIGNAL 0x0100 /* -k, -s */
62 61 #define OPT_USERID 0x0200 /* -u */
63 62 #define OPT_NBMANDLIST 0x0400 /* -n */
64 63 #define OPT_DEVINFO 0x0800 /* -d */
65 64
66 65 #define NELEM(a) (sizeof (a) / sizeof ((a)[0]))
67 66
68 67 /*
69 68 * System call prototype
70 69 */
71 70 extern int utssys(void *buf, int arg, int type, void *outbp);
72 71
73 72 /*
74 73 * Option flavors or types of options fuser command takes. Exclusive
75 74 * options (EXCL_OPT) are mutually exclusive key options, while
76 75 * modifier options (MOD_OPT) add to the key option. Examples are -f
77 76 * for EXCL_OPT and -u for MOD_OPT.
78 77 */
79 78 typedef enum {EXCL_OPT, MOD_OPT} opt_flavor_t;
80 79
81 80 struct co_tab {
82 81 int c_flag;
83 82 char c_char;
84 83 };
85 84
86 85 static struct co_tab code_tab[] = {
87 86 {F_CDIR, 'c'}, /* current directory */
88 87 {F_RDIR, 'r'}, /* root directory (via chroot) */
89 88 {F_TEXT, 't'}, /* textfile */
90 89 {F_OPEN, 'o'}, /* open (creat, etc.) file */
91 90 {F_MAP, 'm'}, /* mapped file */
92 91 {F_TTY, 'y'}, /* controlling tty */
93 92 {F_TRACE, 'a'}, /* trace file */
94 93 {F_NBM, 'n'} /* nbmand lock/share reservation on file */
95 94 };
96 95
97 96 /*
98 97 * Return a pointer to the mount point matching the given special name, if
99 98 * possible, otherwise, exit with 1 if mnttab corruption is detected, else
100 99 * return NULL.
101 100 *
102 101 * NOTE: the underlying storage for mget and mref is defined static by
103 102 * libos. Repeated calls to getmntany() overwrite it; to save mnttab
104 103 * structures would require copying the member strings elsewhere.
105 104 */
106 105 static char *
107 106 spec_to_mount(char *specname)
108 107 {
109 108 struct mnttab mref, mget;
110 109 struct stat st;
111 110 FILE *frp;
112 111 int ret;
113 112
114 113 /* get mount-point */
115 114 if ((frp = fopen(MNTTAB, "r")) == NULL)
116 115 return (NULL);
117 116
118 117 mntnull(&mref);
119 118 mref.mnt_special = specname;
120 119 ret = getmntany(frp, &mget, &mref);
121 120 (void) fclose(frp);
122 121
123 122 if (ret == 0) {
124 123 if ((stat(specname, &st) == 0) && S_ISBLK(st.st_mode))
125 124 return (mget.mnt_mountp);
126 125 } else if (ret > 0) {
127 126 (void) fprintf(stderr, gettext("mnttab is corrupted\n"));
128 127 exit(1);
129 128 }
130 129 return (NULL);
131 130 }
132 131
133 132 /*
134 133 * The main objective of this routine is to allocate an array of f_user_t's.
135 134 * In order for it to know how large an array to allocate, it must know
136 135 * the value of v.v_proc in the kernel. To get this, we do a kstat
137 136 * lookup to get the var structure from the kernel.
138 137 */
139 138 static fu_data_t *
140 139 get_f_user_buf()
141 140 {
142 141 fu_data_t fu_header, *fu_data;
143 142 kstat_ctl_t *kc;
144 143 struct var v;
145 144 kstat_t *ksp;
146 145 int count;
147 146
148 147 if ((kc = kstat_open()) == NULL ||
149 148 (ksp = kstat_lookup(kc, "unix", 0, "var")) == NULL ||
150 149 kstat_read(kc, ksp, &v) == -1) {
151 150 perror(gettext("kstat_read() of struct var failed"));
152 151 exit(1);
153 152 }
154 153 (void) kstat_close(kc);
155 154
156 155 /*
157 156 * get a count of the current number of kernel file consumers
158 157 *
159 158 * the number of kernel file consumers can change between
160 159 * the time when we get this count of all kernel file
161 160 * consumers and when we get the actual file usage
162 161 * information back from the kernel.
163 162 *
164 163 * we use the current count as a maximum because we assume
165 164 * that not all kernel file consumers are accessing the
166 165 * file we're interested in. this assumption should make
167 166 * the current number of kernel file consumers a valid
168 167 * upper limit of possible file consumers.
169 168 *
170 169 * this call should never fail
171 170 */
172 171 fu_header.fud_user_max = 0;
173 172 fu_header.fud_user_count = 0;
174 173 (void) utssys(NULL, F_KINFO_COUNT, UTS_FUSERS, &fu_header);
175 174
176 175 count = v.v_proc + fu_header.fud_user_count;
177 176
178 177 fu_data = (fu_data_t *)malloc(fu_data_size(count));
179 178 if (fu_data == NULL) {
180 179 (void) fprintf(stderr,
181 180 gettext("fuser: could not allocate buffer\n"));
182 181 exit(1);
183 182 }
184 183 fu_data->fud_user_max = count;
185 184 fu_data->fud_user_count = 0;
186 185 return (fu_data);
187 186 }
188 187
189 188 /*
190 189 * display the fuser usage message and exit
191 190 */
192 191 static void
193 192 usage()
194 193 {
195 194 (void) fprintf(stderr,
196 195 gettext("Usage: fuser [-[k|s sig]un[c|f|d]] files"
197 196 " [-[[k|s sig]un[c|f|d]] files]..\n"));
198 197 exit(1);
199 198 }
200 199
201 200 static int
202 201 report_process(f_user_t *f_user, int options, int sig)
203 202 {
204 203 struct passwd *pwdp;
205 204 int i;
206 205
207 206 (void) fprintf(stdout, " %7d", (int)f_user->fu_pid);
208 207 (void) fflush(stdout);
209 208
210 209 /* print out any character codes for the process */
211 210 for (i = 0; i < NELEM(code_tab); i++) {
212 211 if (f_user->fu_flags & code_tab[i].c_flag)
213 212 (void) fprintf(stderr, "%c", code_tab[i].c_char);
214 213 }
215 214
216 215 /* optionally print the login name for the process */
217 216 if ((options & OPT_USERID) &&
218 217 ((pwdp = getpwuid(f_user->fu_uid)) != NULL))
219 218 (void) fprintf(stderr, "(%s)", pwdp->pw_name);
220 219
221 220 /* optionally send a signal to the process */
222 221 if (options & OPT_SIGNAL)
223 222 (void) kill(f_user->fu_pid, sig);
224 223
225 224 return (0);
226 225 }
227 226
228 227 static char *
229 228 i_get_dev_path(f_user_t *f_user, char *drv_name, int major, di_node_t *di_root)
230 229 {
231 230 di_minor_t di_minor;
232 231 di_node_t di_node;
233 232 dev_t dev;
234 233 char *path;
235 234
236 235 /*
237 236 * if we don't have a snapshot of the device tree yet, then
238 237 * take one so we can try to look up the device node and
239 238 * some kind of path to it.
240 239 */
241 240 if (*di_root == DI_NODE_NIL) {
242 241 *di_root = di_init("/", DINFOSUBTREE | DINFOMINOR);
243 242 if (*di_root == DI_NODE_NIL) {
244 243 perror(gettext("devinfo snapshot failed"));
245 244 return ((char *)-1);
246 245 }
247 246 }
248 247
249 248 /* find device nodes that are bound to this driver */
250 249 di_node = di_drv_first_node(drv_name, *di_root);
251 250 if (di_node == DI_NODE_NIL)
252 251 return (NULL);
253 252
254 253 /* try to get a dev_t for the device node we want to look up */
255 254 if (f_user->fu_minor == -1)
256 255 dev = DDI_DEV_T_NONE;
257 256 else
258 257 dev = makedev(major, f_user->fu_minor);
259 258
260 259 /* walk all the device nodes bound to this driver */
261 260 do {
262 261
263 262 /* see if we can get a path to the minor node */
264 263 if (dev != DDI_DEV_T_NONE) {
265 264 di_minor = DI_MINOR_NIL;
266 265 while (di_minor = di_minor_next(di_node, di_minor)) {
267 266 if (dev != di_minor_devt(di_minor))
268 267 continue;
269 268 path = di_devfs_minor_path(di_minor);
270 269 if (path == NULL) {
271 270 perror(gettext(
272 271 "unable to get device path"));
273 272 return ((char *)-1);
274 273 }
275 274 return (path);
276 275 }
277 276 }
278 277
279 278 /* see if we can get a path to the device instance */
280 279 if ((f_user->fu_instance != -1) &&
281 280 (f_user->fu_instance == di_instance(di_node))) {
282 281 path = di_devfs_path(di_node);
283 282 if (path == NULL) {
284 283 perror(gettext("unable to get device path"));
285 284 return ((char *)-1);
286 285 }
287 286 return (path);
288 287 }
289 288 } while (di_node = di_drv_next_node(di_node));
290 289
291 290 return (NULL);
292 291 }
293 292
294 293 static int
295 294 report_kernel(f_user_t *f_user, di_node_t *di_root)
296 295 {
297 296 struct modinfo modinfo;
298 297 char *path;
299 298 int major = -1;
300 299
301 300 /* get the module name */
302 301 modinfo.mi_info = MI_INFO_ONE | MI_INFO_CNT | MI_INFO_NOBASE;
303 302 modinfo.mi_id = modinfo.mi_nextid = f_user->fu_modid;
304 303 if (modctl(MODINFO, f_user->fu_modid, &modinfo) < 0) {
305 304 perror(gettext("unable to get kernel module information"));
306 305 return (-1);
307 306 }
308 307
309 308 /*
310 309 * if we don't have any device info then just
311 310 * print the module name
312 311 */
313 312 if ((f_user->fu_instance == -1) && (f_user->fu_minor == -1)) {
314 313 (void) fprintf(stderr, " [%s]", modinfo.mi_name);
315 314 return (0);
316 315 }
317 316
318 317 /* get the driver major number */
319 318 if (modctl(MODGETMAJBIND,
320 319 modinfo.mi_name, strlen(modinfo.mi_name) + 1, &major) < 0) {
321 320 perror(gettext("unable to get driver major number"));
322 321 return (-1);
323 322 }
324 323
325 324 path = i_get_dev_path(f_user, modinfo.mi_name, major, di_root);
326 325 if (path == (char *)-1)
327 326 return (-1);
328 327
329 328 /* check if we couldn't get any device pathing info */
330 329 if (path == NULL) {
331 330 if (f_user->fu_minor == -1) {
332 331 /*
333 332 * we don't really have any more info on the device
334 333 * so display the driver name in the same format
335 334 * that we would for a plain module
336 335 */
337 336 (void) fprintf(stderr, " [%s]", modinfo.mi_name);
338 337 return (0);
339 338 } else {
340 339 /*
341 340 * if we only have dev_t information, then display
342 341 * the driver name and the dev_t info
343 342 */
344 343 (void) fprintf(stderr, " [%s,dev=(%d,%d)]",
345 344 modinfo.mi_name, major, f_user->fu_minor);
346 345 return (0);
347 346 }
348 347 }
349 348
350 349 /* display device pathing information */
351 350 if (f_user->fu_minor == -1) {
352 351 /*
353 352 * display the driver name and a path to the device
354 353 * instance.
355 354 */
356 355 (void) fprintf(stderr, " [%s,dev_path=%s]",
357 356 modinfo.mi_name, path);
358 357 } else {
359 358 /*
360 359 * here we have lot's of info. the driver name, the minor
361 360 * node dev_t, and a path to the device. display it all.
362 361 */
363 362 (void) fprintf(stderr, " [%s,dev=(%d,%d),dev_path=%s]",
364 363 modinfo.mi_name, major, f_user->fu_minor, path);
365 364 }
366 365
367 366 di_devfs_path_free(path);
368 367 return (0);
369 368 }
370 369
371 370 /*
372 371 * Show pids and usage indicators for the nusers processes in the users list.
373 372 * When OPT_USERID is set, give associated login names. When OPT_SIGNAL is
374 373 * set, issue the specified signal to those processes.
375 374 */
376 375 static void
377 376 report(fu_data_t *fu_data, int options, int sig)
378 377 {
379 378 di_node_t di_root = DI_NODE_NIL;
380 379 f_user_t *f_user;
381 380 int err, i;
382 381
383 382 for (err = i = 0; (err == 0) && (i < fu_data->fud_user_count); i++) {
384 383
385 384 f_user = &(fu_data->fud_user[i]);
386 385 if (f_user->fu_flags & F_KERNEL) {
387 386 /* a kernel module is using the file */
388 387 err = report_kernel(f_user, &di_root);
389 388 } else {
390 389 /* a userland process using the file */
391 390 err = report_process(f_user, options, sig);
392 391 }
393 392 }
394 393
395 394 if (di_root != DI_NODE_NIL)
396 395 di_fini(di_root);
397 396 }
398 397
399 398 /*
400 399 * Sanity check the option "nextopt" and OR it into *options.
401 400 */
402 401 static void
403 402 set_option(int *options, int nextopt, opt_flavor_t type)
404 403 {
405 404 static const char *excl_opts[] = {"-c", "-f", "-d"};
406 405 int i;
407 406
408 407 /*
409 408 * Disallow repeating options
410 409 */
411 410 if (*options & nextopt)
412 411 usage();
413 412
414 413 /*
415 414 * If EXCL_OPT, allow only one option to be set
416 415 */
417 416 if ((type == EXCL_OPT) && (*options)) {
418 417 (void) fprintf(stderr,
419 418 gettext("Use only one of the following options :"));
420 419 for (i = 0; i < NELEM(excl_opts); i++) {
421 420 if (i == 0) {
422 421 (void) fprintf(stderr, gettext(" %s"),
423 422 excl_opts[i]);
424 423 } else {
425 424 (void) fprintf(stderr, gettext(", %s"),
426 425 excl_opts[i]);
427 426 }
428 427 }
429 428 (void) fprintf(stderr, "\n"),
430 429 usage();
431 430 }
432 431 *options |= nextopt;
433 432 }
434 433
435 434 /*
436 435 * Determine which processes are using a named file or file system.
437 436 * On stdout, show the pid of each process using each command line file
438 437 * with indication(s) of its use(s). Optionally display the login
439 438 * name with each process. Also optionally, issue the specified signal to
440 439 * each process.
441 440 *
442 441 * X/Open Commands and Utilites, Issue 5 requires fuser to process
443 442 * the complete list of names it is given, so if an error is encountered
444 443 * it will continue through the list, and then exit with a non-zero
445 444 * value. This is a change from earlier behavior where the command
446 445 * would exit immediately upon an error.
447 446 *
448 447 * The preferred use of the command is with a single file or file system.
449 448 */
450 449
451 450 int
452 451 main(int argc, char **argv)
453 452 {
454 453 fu_data_t *fu_data;
455 454 char *mntname, c;
456 455 int newfile = 0, errors = 0, opts = 0, flags = 0;
457 456 int uts_flags, sig, okay, err;
458 457
459 458 (void) setlocale(LC_ALL, "");
460 459 (void) textdomain(TEXT_DOMAIN);
461 460
462 461 if (argc < 2)
463 462 usage();
464 463
465 464 do {
466 465 while ((c = getopt(argc, argv, "cdfkns:u")) != EOF) {
467 466 if (newfile) {
468 467 /*
469 468 * Starting a new group of files.
470 469 * Clear out options currently in
471 470 * force.
472 471 */
473 472 flags = opts = newfile = 0;
474 473 }
475 474 switch (c) {
476 475 case 'd':
477 476 set_option(&opts, OPT_DEVINFO, EXCL_OPT);
478 477 break;
479 478 case 'k':
480 479 set_option(&flags, OPT_SIGNAL, MOD_OPT);
481 480 sig = SIGKILL;
482 481 break;
483 482 case 's':
484 483 set_option(&flags, OPT_SIGNAL, MOD_OPT);
485 484 if (str2sig(optarg, &sig) != 0) {
486 485 (void) fprintf(stderr,
487 486 gettext("Invalid signal %s\n"),
488 487 optarg);
489 488 usage();
490 489 }
491 490 break;
492 491 case 'u':
493 492 set_option(&flags, OPT_USERID, MOD_OPT);
494 493 break;
495 494 case 'n':
496 495 /*
497 496 * Report only users with NBMAND locks
498 497 */
499 498 set_option(&flags, OPT_NBMANDLIST, MOD_OPT);
500 499 break;
501 500 case 'c':
502 501 set_option(&opts, OPT_CONTAINED, EXCL_OPT);
503 502 break;
504 503 case 'f':
505 504 set_option(&opts, OPT_FILE_ONLY, EXCL_OPT);
506 505 break;
507 506 default:
508 507 (void) fprintf(stderr,
509 508 gettext("Illegal option %c.\n"), c);
510 509 usage();
511 510 }
512 511 }
513 512
514 513 if ((optind < argc) && (newfile)) {
515 514 /*
516 515 * Cancel the options currently in
517 516 * force if a lone dash is specified.
518 517 */
519 518 if (strcmp(argv[optind], "-") == 0) {
520 519 flags = opts = newfile = 0;
521 520 optind++;
522 521 }
523 522 }
524 523
525 524 /*
526 525 * newfile is set when a new group of files is found. If all
527 526 * arguments are processed and newfile isn't set here, then
528 527 * the user did not use the correct syntax
529 528 */
530 529 if (optind > argc - 1) {
531 530 if (!newfile) {
532 531 (void) fprintf(stderr,
533 532 gettext("fuser: missing file name\n"));
534 533 usage();
535 534 }
536 535 } else {
537 536 if (argv[optind][0] == '-') {
538 537 (void) fprintf(stderr,
539 538 gettext("fuser: incorrect use of -\n"));
540 539 usage();
541 540 } else {
542 541 newfile = 1;
543 542 }
544 543 }
545 544
546 545 /* allocate a buffer to hold usage data */
547 546 fu_data = get_f_user_buf();
548 547
549 548 /*
550 549 * First print file name on stderr
551 550 * (so stdout (pids) can be piped to kill)
552 551 */
553 552 (void) fflush(stdout);
554 553 (void) fprintf(stderr, "%s: ", argv[optind]);
555 554
556 555 /*
557 556 * if not OPT_FILE_ONLY, OPT_DEVINFO, or OPT_CONTAINED,
558 557 * attempt to translate the target file name to a mount
559 558 * point via /etc/mnttab.
560 559 */
561 560 okay = 0;
562 561 if (!opts &&
563 562 (mntname = spec_to_mount(argv[optind])) != NULL) {
564 563
565 564 uts_flags = F_CONTAINED |
566 565 ((flags & OPT_NBMANDLIST) ? F_NBMANDLIST : 0);
567 566
568 567 err = utssys(mntname, uts_flags, UTS_FUSERS, fu_data);
569 568 if (err == 0) {
570 569 report(fu_data, flags, sig);
571 570 okay = 1;
572 571 }
573 572 }
574 573
575 574 uts_flags = \
576 575 ((opts & OPT_CONTAINED) ? F_CONTAINED : 0) |
577 576 ((opts & OPT_DEVINFO) ? F_DEVINFO : 0) |
578 577 ((flags & OPT_NBMANDLIST) ? F_NBMANDLIST : 0);
579 578
580 579 err = utssys(argv[optind], uts_flags, UTS_FUSERS, fu_data);
581 580 if (err == 0) {
582 581 report(fu_data, flags, sig);
583 582 } else if (!okay) {
584 583 perror("fuser");
585 584 errors = 1;
586 585 free(fu_data);
587 586 continue;
588 587 }
589 588
590 589 (void) fprintf(stderr, "\n");
591 590 free(fu_data);
592 591 } while (++optind < argc);
593 592
594 593 return (errors);
595 594 }
↓ open down ↓ |
535 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX