/proc on Mac OS X
The "process" file system (procfs for brevity, or simply /proc, where it is usually mounted) has become relatively common on Unix and Unix-like systems (Linux, FreeBSD, Solaris ...). procfs is meant to be a file system representation of the process table, although some systems put so many features and functionality into procfs (Linux, for example) that renders such implementations nothing short of the proverbial kitchen-sink.
In its simplest form procfs provides file-system abstraction for processes, presenting information about processes, their execution environment, resource utilization etc. as files. The original design goal of procfs was to make debugger implementation easier. Systems like Linux have exposed a lot of other system interfaces and information through procfs. There are Linux system utilities that essentially cat files in procfs! There is plenty of documentation for procfs on various systems that you can refer to.
Mac OS X does not have procfs. While it would be nice to have, I don't think it is a limitation. Things that could make use of procfs would have to be done differently, that's all: ps would have to be written differently from, say, on Linux. On Mac OS X, ps uses the kvm and sysctl interfaces. gdb, and various other programs also have such differences.
Sometimes it is better for the more inquisitive to have procfs. Consider a simple example: you could simply cat a file (/proc/cpuinfo) on Linux and glean a lot of information about the CPU. On Mac OS X, you can look at "About This Mac", or do a "sysctl -a hw" and try to look at relevant information in the output. In general, the Linux output is more detailed. There are instances where it is extremely hard (or even impossible) to look at certain information on Mac OS X:
Suppose you had a "discussion" with a colleague about the size of the disk drive buffer on a particular Mac. You look at the drive's model string in "About This Mac" and look at the specifications on the manufacturer's web site. I found that Hitachi had two different pages with conflicting information regarding the buffer size (2MB and 8MB) for IC25N080ATMR04. The fastest way I could come up with was to boot Linux from a CD-ROM and look at files under /proc/ide (for each drive, various pieces of information are listed, including the buffer size). This may seem contrived. It is.
Even in light of the previous "example", I don't feel a compelling need for procfs on Mac OS X. It would be instructive to add such support to Mac OS X for "academic" reasons, though. The other night I was fooling around with xnu, and I thought about adding a quick and dirty procfs to it. Darwin 7.0's BSD components come from FreeBSD 5.0. FreeBSD does have procfs, although I realized later that it's not that straightforward a port. The rest of this document contains notes on porting procfs from FreeBSD to Darwin.
FreeBSD --> xnu/bsd
Given that code for the vfs layer and various system calls in xnu derived from FreeBSD, it would be reasonable to port procfs from FreeBSD. That said, there are enough differences between the two systems, as we shall see. The following notes describe steps taken to add a very simple (only /proc/<pid> directories visible with support for only cmdline and status).
pseudofs
FreeBSD contains linprocfs, a process file system that emulates (a subset of) Linux's procfs. linprocfs is needed for Linux binary emulation to work completely. This is in addition to FreeBSD's own procfs. In order to reduce (eliminate) code duplication between such pseudo file systems, pseudofs was added to FreeBSD. pseudofs is a framework (rather than a full-fledged file system) for implementing pseudo file systems on top of it. In FreeBSD 5.0, procfs is implemented using pseudofs, which means that in order to port the former, we need to port the latter first.
As an aside, note that that xnu/bsd does have in-memory file systems like synthfs, which is used to create arbitrary directory trees (if you wanted to synthesize mount points for random things, say). synthfs is not in FreeBSD 5.0. Similarly, volfs, the "volume file system" on OS X is a virtual file system that exists over the HFS VFS and serves the needs of two differing APIs (Unix pathnames and MacOS <Volume ID><Directory><File Name>). Other than these, FreeBSD and xnu/bsd share file systems (to various extents) such as deadfs, devfs, fdescfs, fifofs, nullfs, specfs, unionfs etc.
pseudofs.h
pseudofs.h needs to be modified with the following points in mind:
MFSNAMELEN(length of file system name type) in<sys/mount.h>includes null underxnu/bsd, but not under FreeBSD.xnu/bsduses "simple locks" in many places where FreeBSD uses mutexes.- Where FreeBSD passes around "struct thread" pointers,
xnu/bsdpasses around "struct proc" pointers. xnu/bsdVFS does not have extended attribute support.VFS_SET(...),MODULE_VERSION(...)andMODULE_DEPEND(...)macros are not applicable underxnu/bsd. This also means we would have to do something else (as opposed to calling functions when FreeBSD module load/unload events occur) to enablepseudofs.
pseudofs_internal.h
pseudofs_internal.h contains only structure definitions and function prototypes that can be used as is.
The rest of the source files need numerous changes, some of which are outlined below.
pseudofs.c
- <sys/module.h>, <sys/mutex.h> and <sys/sbuf.h> do not exist under
xnu/bsd. We would not needmodule.has we are not using loadable modules. We would not needmutex.has we are using simple locks. We do needsbuf.h. Quoted from the man page: ... the sbuf family of functions allows one to safely allocate, construct and release bounded null-terminated strings in kernel space. Instead of arrays of characters, these functions operate on structures called sbufs, defined in <sys/sbuf.h>. Since sbufs are used as the basis ofpseudofs, we simply include them inxnu/bsdfor our "dirty" implementation. - We copy over
sbuf.handsubr_sbuf.cfrom FreeBSD toxnu/bsd. Since sbufs useva_list, the correctstdarg.hneeds to be used. Moreover, macros such asisdigit()need to be pulled in. There is no memory typeM_SBUFdefined onxnu/bsd, of course. - Functions that take a thread pointer would take a process pointer, as mentioned earlier.
- The
pfs_modevent()function is not needed. - Simple locks are used in place of mutexes.
pseudofs_fileno.c
The only changes are adjustments for M_PFSFILENO and mutexes.
pseudofs_vncache.c
M_PFSVNCACHEis not defined. Make adjustments.- Make adjustments for mutexes.
vop_tis not defined. Define it.rm_at_exit()does not exist. For now, we leave it out! (/* XXX */).vget()andvn_lock()needcurrent_proc()instead ofcurthread.getnewvnode()is called slightly differently. Rather than specify a string name for the file system as the first argument, we use a newenum(VT_PROCFS, say).- Instead of
(*vpp)->v_vflag = VV_ROOT, use(*vpp)->v_flag = VROOT. Moreover,VV_PROCDEPis not defined. Define it.
pseudofs_vnops.c
- Instead of <sys/ctype.h>, simply define the
isdigit()macro. - <sys/mutex.h> and <sys/sx.h> do not exist.
- Pull in <vfs/vfs_support.h>
- Functions that take a thread pointer would take a process pointer. Consequently, things like
td->td_proc->p_pidwould becometd->p_pid,curthreadwould becomecurrent_proc(),cn_threadbecomescn_proc, etc. - We provide a dummy implementation (to begin with) of
p_cansee(). - We provide an implementation of
vaccess(). - Instead of
vrefcnt(vn), we examinevn->v_usecountdirectly. - Instead of "real" uid/gid, simply use uid/gid.
- We leave out
pfs_getextattr(). - We create simple implementations of
vop_defaultop()andvop_eopnotsupp(). - We declare and populate a
struct vnodeopv_entry_descarray, with appropriate defaults. - We leave out
VNODEOP_SET()- we would perform the equivalent action elsewhere.
We copy over procfs.c, procfs.h, procfs_note.c and procfs_status.c from FreeBSD's procfs/ directory.
procfs.c
- We declare
vfs_opv_numopsandpfs_vnodeop_opv_descas externs. - Instead of
vn_fullpath(), simply use "unknown" for now. - Get the pid from the process pointer directly.
- Leave out everything from the constructor except the root,
cmdlineandcurproc. - Declare a static pointer to
struct vfsconf. - Declare
#define's forprocfs_start,procfs_quotactl,procfs_sync,procfs_vget,procfs_fhtovp,procfs_vptofhandprocfs_sysctl, castingeopnotsuppappropriately. - Declare a static
struct pfs_infoforprocfs. - Implement
_procfs_mount()(simply callpfs_mount()),_procfs_init()(simply callpfs_init()),_procfs_uninit()(simply callpfs_uninit(). - Use the following
struct vfsops:
struct vfsops procfs_vfsops = { _procfs_mount, procfs_start, pfs_unmount, pfs_root, procfs_quotactl, pfs_statfs, procfs_sync, procfs_vget, procfs_fhtovp, procfs_vptofh, _procfs_init, procfs_sysctl, };
- Implement
procfs_kernel_mount()along the lines ofdevfs_kernel_mount(). - Initialize
pseudofsat boot time frombsd/kern/bsd_init.c. - Mount
procfson/procat boot time frombsd/kern/bsd_init.c.
Status
I believe everything is in place, though there is a kernel panic soon after /proc is mounted :-) Before I could even begin over-the-network two-machine kernel debugging, one of my two Macs, an iBook, "died". As if that's not frustrating enough, here's what ensued (it's not a rant, but a mere statement of facts):
The iBook was about 7 months old when it had its first problem: a pinched (by the screen hinge, apparently) display cable that garbled the display for random periods of time. I took the iBook for service (covered by the 1 year warranty).
The iBook was returned to me within a few days with the display fixed, but with a "dead" (not just unbootable, but uninstallable, unusable) disk drive. Needless to say, I had to take it back immediately.
The iBook was returned with a new drive, but random cosmetic damage, which I chose to ignore. Within a few weeks, its display went blank (apparently a "logic board failure"). It is at this point that I needed it for 2-machine debugging to chase the kernel panic.
The iBook was in service for almost three weeks this time. It was returned to me with a damaged (scratched) LCD that wasn't put back together properly either, as well as more cosmetic damage.
Exasperated, I took it back, and it was in service for almost two more weeks. They changed the LCD screen, and (I believe) even the casing (to make up for the cosmetic damage).
At this point, the iBook has a new casing, a new logic board, a new hard drive and a new LCD screen. It has been in service for at least 45 days in its first 9 months. However, I have not gotten around to looking at /proc since I got the iBook back.
Disclaimer: I do not know how typical an Apple service experience this is. My other Mac, a PowerBook 17, has not had any problems.