BigTailWolf
BigTailWolf

Reputation: 1028

How to send SIGTERM to a process by process name in QNX cpp code?

E.g: I have a process called foo.

Typically in console, I can type slay foo then foo terminates. Also, in a cpp code I can issue a system call with system("slay foo");

I know the system() is a heavy fork call that should be avoid. Is there any other function in <csignal> or <cstdlib> I can choose?

I've read SignalKill() and SignalKill_r(), both need pid which I cannot provide.

Upvotes: 1

Views: 2532

Answers (2)

Mark Segal
Mark Segal

Reputation: 5550

It's not as simple as one might think. Linux doesn't provide a syscall that gives you the PID of a process by its name.

Assuming QNXs filesystem is similar to standard UNI, you might want to read this article to understand how to find a process's PID using its name, and then use that PID with SignalKill or SignalKill_r

Here's the code to find a process's PID using its name in C. I can't test it on QNX, but it works on Ubuntu.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <dirent.h>
#include <libgen.h>

/* checks if the string is purely an integer
 * we can do it with `strtol' also
 */
int check_if_number (char *str)
{
  int i;
  for (i=0; str[i] != '\0'; i++)
  {
    if (!isdigit (str[i]))
    {
      return 0;
    }
  }
  return 1;
}

#define MAX_BUF 1024
#define PID_LIST_BLOCK 32

int *pidof (char *pname)
{
  DIR *dirp;
  FILE *fp;
  struct dirent *entry;
  int *pidlist, pidlist_index = 0, pidlist_realloc_count = 1;
  char path[MAX_BUF], read_buf[MAX_BUF];

  dirp = opendir ("/proc/");
  if (dirp == NULL)
  {
    perror ("Fail");
    return NULL;
  }

  pidlist = malloc (sizeof (int) * PID_LIST_BLOCK);
  if (pidlist == NULL)
  {
    return NULL;
  }

  while ((entry = readdir (dirp)) != NULL)
  {
    if (check_if_number (entry->d_name))
    {
      strcpy (path, "/proc/");
      strcat (path, entry->d_name);
      strcat (path, "/comm");

      /* A file may not exist, it may have been removed.
       * dut to termination of the process. Actually we need to
       * make sure the error is actually file does not exist to
       * be accurate.
       */
      fp = fopen (path, "r");
      if (fp != NULL)
      {
        fscanf (fp, "%s", read_buf);
        if (strcmp (read_buf, pname) == 0)
        {
          /* add to list and expand list if needed */
          pidlist[pidlist_index++] = atoi (entry->d_name);
          if (pidlist_index == PID_LIST_BLOCK * pidlist_realloc_count)
          {
            pidlist_realloc_count++;
            pidlist = realloc (pidlist, sizeof (int) * PID_LIST_BLOCK * pidlist_realloc_count); //Error check todo
            if (pidlist == NULL)
            {
              return NULL;
            }
          }
        }
        fclose (fp);
      }
    }
  }


  closedir (dirp);
  pidlist[pidlist_index] = -1; /* indicates end of list */
  return pidlist;
}

int main (int argc, char *argv[])
{
  int *list, i;

  if (argc != 2)
  {
    printf ("Usage: %s proc_name\n", argv[0]);
    return 0;
  }
  list = pidof (argv[1]);
  for (i=0; list[i] != -1; i++)
  {
    printf ("%d ", list[i]);
  }
  free (list);
  if (list[0] != -1)
  {
    printf ("\n");
  }
  return 0;
}

Upvotes: 2

rkrten
rkrten

Reputation: 57

In order to convert a process name to a pid, you need to dig through QNX's /proc filesystem. I wrote a book called "The QNX Cookbook" which is now available for free online at QNX's website (http://www.qnx.com/download/feature.html?programid=26184). Go to page 222, "Iterating through the list of processes" and copy the code that iterates through the list of processes. This will allow you to search through all processes for whichever ones you want to kill (it will give you the PID you need).

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);
}

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/as", 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);
}

By supplying whatever actions you want for "do_process()", you can e.g. kill by name, etc.

Upvotes: 1

Related Questions