Iterating through the list of processes

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.

Note: Note that some versions of QNX Neutrino didn't provide a “name” for the process manager. This is easy to work around, because the process manager is always process ID 1.

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().