| /* |
| * dmnt.c - Solaris mount support functions for lsof |
| */ |
| |
| |
| /* |
| * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana |
| * 47907. All rights reserved. |
| * |
| * Written by Victor A. Abell |
| * |
| * This software is not subject to any license of the American Telephone |
| * and Telegraph Company or the Regents of the University of California. |
| * |
| * Permission is granted to anyone to use this software for any purpose on |
| * any computer system, and to alter it and redistribute it freely, subject |
| * to the following restrictions: |
| * |
| * 1. Neither the authors nor Purdue University are responsible for any |
| * consequences of the use of this software. |
| * |
| * 2. The origin of this software must not be misrepresented, either by |
| * explicit claim or by omission. Credit to the authors and Purdue |
| * University must appear in documentation and sources. |
| * |
| * 3. Altered versions must be plainly marked as such, and must not be |
| * misrepresented as being the original software. |
| * |
| * 4. This notice may not be removed or altered. |
| */ |
| |
| #ifndef lint |
| static char copyright[] = |
| "@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n"; |
| static char *rcsid = "$Id: dmnt.c,v 1.15 2005/08/29 10:24:25 abe Exp $"; |
| #endif |
| |
| |
| #include "lsof.h" |
| |
| |
| /* |
| * Local static definitions |
| */ |
| |
| static struct mounts *Lmi = (struct mounts *)NULL; /* local mount info */ |
| static int Lmist = 0; /* Lmi status */ |
| |
| |
| _PROTOTYPE(static char *getmntdev,(char *o, int l, struct stat *s, char *f)); |
| |
| |
| /* |
| * getmntdev() - get mount entry's device number |
| */ |
| |
| static char * |
| getmntdev(o, l, s, f) |
| char *o; /* start of device option */ |
| int l; /* length of device keyword (not |
| * including `=') */ |
| struct stat *s; /* pointer to stat buffer to create */ |
| char *f; /* file system type */ |
| { |
| char *opte; |
| |
| memset((char *)s, 0, sizeof(struct stat)); |
| if (!(opte = x2dev(o + l + 1, &s->st_dev))) |
| return((char *)NULL); |
| |
| #if solaris>=70000 && L_BITSMAJOR!=L_BITSMAJOR32 |
| /* |
| * If this is a Solaris 7 system with a 64 bit kernel, convert the 32 bit |
| * device number to a 64 bit device number. |
| */ |
| s->st_dev = (((s->st_dev >> L_BITSMINOR32) & L_MAXMAJ32) << L_BITSMINOR) |
| | (s->st_dev & L_MAXMIN32); |
| #endif /* solaris>=70000 && L_BITSMAJOR!=L_BITSMAJOR32 */ |
| |
| s->st_mode = S_IFDIR | 0777; |
| |
| #if defined(HASFSTYPE) |
| if (f) { |
| (void) strncpy(s->st_fstype, f, sizeof(s->st_fstype)); |
| s->st_fstype[sizeof(s->st_fstype) - 1] = '\0'; |
| } |
| #endif /* defined(HASFSTYPE) */ |
| |
| return(opte); |
| } |
| |
| |
| /* |
| * readmnt() - read mount table |
| */ |
| |
| struct mounts * |
| readmnt() |
| { |
| int devl, ignore; |
| char *cp, *dir, *fs; |
| char *dn = (char *)NULL; |
| char *ln; |
| FILE *mfp; |
| struct mounts *mtp; |
| char *dopt, *dopte; |
| struct stat sb; |
| struct mnttab me; |
| struct mnttab *mp; |
| |
| #if defined(HASPROCFS) |
| int procfs = 0; |
| #endif /* defined(HASPROCFS) */ |
| |
| unsigned char stat; |
| char *zopt; |
| |
| #if defined(HASZONES) |
| int zwarn = 0; |
| #endif /* definesd(HASZONES) */ |
| |
| if (Lmi || Lmist) |
| return(Lmi); |
| devl = strlen(MNTOPT_DEV); |
| /* |
| * Open access to the mount table and read mount table entries. |
| */ |
| if (!(mfp = fopen(MNTTAB, "r"))) { |
| (void) fprintf(stderr, "%s: can't access %s\n", Pn, MNTTAB); |
| return(0); |
| } |
| for (mp = &me; getmntent(mfp, mp) == 0;) { |
| |
| /* |
| * Skip loop-back mounts, since they are aliases for legitimate file |
| * systems and there is no way to determine that a vnode refers to a |
| * loop-back alias. |
| */ |
| if (strcmp(mp->mnt_fstype, MNTTYPE_LO) == 0) |
| continue; |
| /* |
| * Save pointers to the directory and file system names for later use. |
| * |
| * Check the file system name. If it doesn't begin with a `/' |
| * but contains a `:' not followed by a '/', ignore this entry. |
| */ |
| dir = mp->mnt_mountp; |
| fs = mp->mnt_special; |
| if (*fs != '/' && (cp = strchr(fs, ':')) && *(cp+1) != '/') |
| continue; |
| /* |
| * Check for a "ignore" type (SunOS) or "ignore" option (Solaris). |
| */ |
| if (hasmntopt(mp, MNTOPT_IGNORE)) |
| ignore = 1; |
| else |
| ignore = 0; |
| /* |
| * Interpolate a possible symbolic directory link. |
| */ |
| if (dn) |
| (void) free((FREE_P *)dn); |
| if (!(dn = mkstrcpy(dir, (MALLOC_S *)NULL))) { |
| |
| no_space_for_mount: |
| |
| (void) fprintf(stderr, "%s: no space for mount ", Pn); |
| safestrprt(fs, stderr, 0); |
| (void) fprintf(stderr, " ("); |
| safestrprt(dir, stderr, 0); |
| (void) fprintf(stderr, ")\n"); |
| Exit(1); |
| } |
| if (!(ln = Readlink(dn))) { |
| if (!Fwarn) { |
| (void) fprintf(stderr, |
| " Output information may be incomplete.\n"); |
| } |
| continue; |
| } |
| if (ln != dn) { |
| (void) free((FREE_P *)dn); |
| dn = ln; |
| } |
| if (*dn != '/') |
| continue; |
| /* |
| * Stat() the directory. |
| * |
| * Avoid the stat() if the mount entry has an "ignore" option and |
| * try to use the mount entry's device number instead. |
| */ |
| dopt = hasmntopt(mp, MNTOPT_DEV); |
| if (ignore) { |
| if (!dopt |
| || !(dopte = getmntdev(dopt, devl, &sb, |
| |
| #if defined(HASFSTYPE) |
| mp->mnt_fstype |
| #else /* !defined(HASFSTYPE) */ |
| (char *)NULL |
| #endif /* defined(HASFSTYPE) */ |
| |
| )) |
| ) |
| continue; |
| stat = 1; |
| } else if (statsafely(dn, &sb)) { |
| if (dopt) { |
| if (!(dopte = getmntdev(dopt, devl, &sb, |
| |
| #if defined(HASFSTYPE) |
| mp->mnt_fstype |
| #else /* !defined(HASFSTYPE) */ |
| (char *)NULL |
| #endif /* defined(HASFSTYPE) */ |
| |
| )) |
| ) |
| dopt = (char *)NULL; |
| } else |
| dopte = (char *)NULL; |
| if (!Fwarn) { |
| |
| #if defined(HASZONES) |
| if ((zopt = hasmntopt(mp, "zone")) && dopte) |
| zwarn++; |
| #else /* !defined(HASZONES) */ |
| zopt = (char *)NULL; |
| #endif /* defined(HASZONES) */ |
| |
| if (!zopt || !dopte) { |
| (void) fprintf(stderr, |
| "%s: WARNING: can't stat() ", Pn); |
| safestrprt(mp->mnt_fstype, stderr, 0); |
| (void) fprintf(stderr, " file system "); |
| safestrprt(dir, stderr, 1); |
| (void) fprintf(stderr, |
| " Output information may be incomplete.\n"); |
| if (dopte) { |
| (void) fprintf(stderr, |
| " assuming \"%.*s\" from %s\n", |
| (int)(dopte - dopt), dopt, MNTTAB); |
| } |
| } |
| } |
| if (!dopt) |
| continue; |
| stat = 1; |
| } else |
| stat = 0; |
| /* |
| * Allocate and fill a local mount structure. |
| */ |
| if (!(mtp = (struct mounts *)malloc(sizeof(struct mounts)))) |
| goto no_space_for_mount; |
| |
| #if defined(HASFSTYPE) |
| if (!(mtp->fstype = mkstrcpy(sb.st_fstype, (MALLOC_S *)NULL))) |
| goto no_space_for_mount; |
| #endif /* defined(HASFSTYPE) */ |
| |
| mtp->dir = dn; |
| dn = (char *)NULL; |
| mtp->next = Lmi; |
| mtp->dev = sb.st_dev; |
| mtp->rdev = sb.st_rdev; |
| mtp->inode = (INODETYPE)sb.st_ino; |
| mtp->mode = sb.st_mode; |
| |
| #if solaris>=80000 |
| mtp->nlink = sb.st_nlink; |
| mtp->size = sb.st_size; |
| #endif /* solaris>=80000 */ |
| |
| #if defined(HASMNTSTAT) |
| mtp->stat = stat; |
| #endif /* defined(HASMNTSTAT) */ |
| |
| #if defined(HASPROCFS) |
| if (strcmp(sb.st_fstype, HASPROCFS) == 0) { |
| |
| /* |
| * Save information on exactly one proc file system. |
| */ |
| if (procfs) |
| Mtprocfs = (struct mounts *)NULL; |
| else { |
| procfs = 1; |
| Mtprocfs = mtp; |
| } |
| } |
| #endif /* defined(HASPROCFS) */ |
| |
| /* |
| * Interpolate a possible file system (mounted-on) device name link. |
| */ |
| if (!(dn = mkstrcpy(fs, (MALLOC_S *)NULL))) |
| goto no_space_for_mount; |
| mtp->fsname = dn; |
| ln = Readlink(dn); |
| dn = (char *)NULL; |
| /* |
| * Stat() the file system (mounted-on) name and add file system |
| * information to the local mount table entry. |
| */ |
| if (!ln || statsafely(ln, &sb)) |
| sb.st_mode = 0; |
| mtp->fsnmres = ln; |
| mtp->fs_mode = sb.st_mode; |
| Lmi = mtp; |
| |
| #if defined(HAS_AFS) |
| /* |
| * If an AFS device number hasn't yet been defined, look for it. |
| */ |
| if (!AFSdevStat |
| && mtp->dir && strcmp(mtp->dir, "/afs") == 0 |
| && mtp->fsname && strcmp(mtp->fsname, "AFS") == 0) { |
| AFSdev = mtp->dev; |
| AFSdevStat = 1; |
| } |
| #endif /* defined(HAS_AFS) && solaris>=20600 */ |
| |
| } |
| (void) fclose(mfp); |
| |
| #if defined(HASZONES) |
| /* |
| * If some zone file systems were encountered, issue a warning. |
| */ |
| if (!Fwarn && zwarn) { |
| (void) fprintf(stderr, |
| "%s: WARNING: can't stat() %d zone file system%s", Pn, zwarn, |
| (zwarn == 1) ? "" : "s"); |
| (void) fprintf(stderr, "; using dev= option%s\n", |
| (zwarn == 1) ? "" : "s"); |
| } |
| #endif /* defined(HASZONES) */ |
| |
| /* |
| * Clean up and return local mount info table address. |
| */ |
| if (dn) |
| (void) free((FREE_P *)dn); |
| Lmist = 1; |
| return(Lmi); |
| } |
| |
| |
| /* |
| * readvfs() - read vfs structure |
| */ |
| |
| struct l_vfs * |
| readvfs(ka, la, lv) |
| KA_T ka; /* vfs structure kernel address, if |
| * must be read from kernel */ |
| struct vfs *la; /* local vfs structure address, non- |
| * NULL if already read from kernel */ |
| struct vnode *lv; /* local vnode */ |
| { |
| struct vfs *v, tv; |
| struct l_vfs *vp; |
| |
| if (!ka && !la) |
| return((struct l_vfs *)NULL); |
| for (vp = Lvfs; vp; vp = vp->next) { |
| if (ka == vp->addr) |
| return(vp); |
| } |
| if (!(vp = (struct l_vfs *)malloc(sizeof(struct l_vfs)))) { |
| (void) fprintf(stderr, "%s: PID %d, no space for vfs\n", |
| Pn, Lp->pid); |
| Exit(1); |
| } |
| vp->dir = (char *)NULL; |
| vp->fsname = (char *)NULL; |
| |
| #if defined(HASFSINO) |
| vp->fs_ino = 0; |
| #endif /* defined(HASFSINO) */ |
| |
| /* |
| * Read vfs structure from kernel, if necessary. |
| */ |
| if (la) |
| v = la; |
| else { |
| v = &tv; |
| if (kread((KA_T)ka, (char *)v, sizeof(tv))) { |
| (void) free((FREE_P *)vp); |
| return((struct l_vfs *)NULL); |
| } |
| } |
| |
| #if defined(HAS_AFS) |
| /* |
| * Fake the device number for an AFS device. |
| */ |
| if (v->vfs_fstype == AFSfstype) { |
| if (!AFSdevStat) |
| (void) readmnt(); |
| v->vfs_dev = AFSdevStat ? AFSdev : 0; |
| } |
| #endif /* defined(HAS_AFS) */ |
| |
| /* |
| * Complete mount information. |
| */ |
| |
| (void) completevfs(vp, (dev_t *)&v->vfs_dev); |
| vp->next = Lvfs; |
| vp->addr = ka; |
| Lvfs = vp; |
| return(vp); |
| } |