Since the /proc filesystem looks like a normal filesystem, it's appropriate to use the filesystem functions opendir() and readdir() to iterate through the process IDs.
The following code sample illustrates how to do this:
void iterate_processes (void) { struct dirent *dirent; DIR *dir; int r; int pid; // 1) find all processes if (!(dir = opendir ("/proc"))) { fprintf (stderr, "%s: couldn't open /proc, errno %d\n", progname, errno); perror (NULL); exit (EXIT_FAILURE); } while (dirent = readdir (dir)) { // 2) we are only interested in process IDs if (isdigit (*dirent -> d_name)) { pid = atoi (dirent -> d_name); iterate_process (pid); } } closedir (dir); }
At this point, we've found all valid process IDs. We use the standard opendir() function in step 1 to open the /proc filesystem. In step 2, we read through all entries in the /proc filesystem, using the standard readdir(). We skip entries that are nonnumeric — as discussed above, there are other things in the /proc filesystem besides process IDs.
Next, we need to search through the processes generated by the directory functions to see which ones match our criteria. For now, we'll just match based on the process name — by the end of this appendix, it will be apparent how to search based on other criteria (short story: ignore the name, and search for your other criteria in a later step).
void iterate_process (int pid) { char paths [PATH_MAX]; int fd; // 1) set up structure static struct { procfs_debuginfo info; char buff [PATH_MAX]; } name; sprintf (paths, "/proc/%d/ctl", pid); if ((fd = open (paths, O_RDONLY)) == -1) { return; } // 2) ask for the name if (devctl (fd, DCMD_PROC_MAPDEBUG_BASE, &name, sizeof (name), 0) != EOK) { if (pid == 1) { strcpy (name.info.path, "(procnto)"); } else { strcpy (name.info.path, "(n/a)"); } } // 3) we can compare against name.info.path here... do_process (pid, fd, name.info.path); close (fd); }
In step 1, we set up an extension to the procfs_debuginfo data structure. The buff buffer is implicitly past the end of the structure, so it's natural to set it up this way. In step 2, we ask for the name, using DCMD_PROC_MAPDEBUG_BASE.
Just before step 3 is a good place to compare the name against whatever it was you're looking for. By not performing any comparison, we match all names.
If the name matches (or for all processes, as shown in the code above), we can call do_process(), which will now work on the process. Notice that we pass do_process() the opened file descriptor, fd, to save on having to reopen the ctl entry again in do_process().