Home > Articles, Operating Systems > Helper functions for handling the PID file of a background daemon.

Helper functions for handling the PID file of a background daemon.

October 19, 2014 Leave a comment Go to comments

In this article I will present to you some useful functions for handling the PID file of a background daemon. Most of the background daemons maintain a PID file usually in a well-known path such as the “/var/run”. For example, the GNOME Display Manager which runs as a background daemon (gdm3) maintains the following file “/var/run/gdm3.pid”. A PID file contains the PID number of the daemon process currently running. This information is useful either for validation or for sending various signals to the daemon process. Also, if a background daemon must have a single running instance this can be accomplished by checking if the PID number of the PID file really exists in the system.

Firstly, before showing you the functions related specific with PID files I would like to present to you first some functions related with files in general. So, here is the header of the functions related with files in general:

/*
 *  Copyright (C) 2014  Efstathios Chatzikyriakidis (contact@efxa.org).
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef _FILE_UTILITY_H_
#define _FILE_UTILITY_H_

#include "shared-types.h"

/*
 * function prototypes.
 */

bool_t remove_file (const string_t const file_path);

bool_t file_exists (const string_t const file_path);

bool_t file_is_readable (const string_t const file_path);

#endif // _FILE_UTILITY_H_

Next, follows the implementation of the functions related with files in general:

/*
 *  Copyright (C) 2014  Efstathios Chatzikyriakidis (contact@efxa.org).
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#include <unistd.h>

#include "file-utility.h"

/*
 * functions.
 */

bool_t
remove_file (const string_t const file_path)
{
  return (unlink (file_path) ? false : true);
}

bool_t
file_exists (const string_t const file_path)
{
  return (access (file_path, F_OK) ? false : true);
}

bool_t
file_is_readable (const string_t const file_path)
{
  return (access (file_path, R_OK) ? false : true);
}

These functions are generic and can be used with any kind of files. You can use these functions for removing a file, checking for the existence of a file and checking if a file is readable. Now, it is time to present the header of the functions related with PID files:

/*
 *  Copyright (C) 2014  Efstathios Chatzikyriakidis (contact@efxa.org).
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef _PID_FILE_UTILITY_H_
#define _PID_FILE_UTILITY_H_

#include <sys/types.h>

#include "shared-types.h"

/*
 * function prototypes.
 */

pid_t read_pid_from_file (const string_t const file_path);

bool_t write_pid_to_file (const string_t const file_path, const pid_t pid);

bool_t pid_exists (const pid_t pid);

#endif // _PID_FILE_UTILITY_H_

Next, follows the implementation of the functions related with PID files:

/*
 *  Copyright (C) 2014  Efstathios Chatzikyriakidis (contact@efxa.org).
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#include <errno.h>
#include <signal.h>
#include <stdio.h>

#include "pid-file-utility.h"

/*
 * functions.
 */

pid_t
read_pid_from_file (const string_t const file_path)
{
  const pid_t pid_error = -1;

  FILE * const file = fopen (file_path, "r");

  if (!file)
  {
    return pid_error;
  }

  pid_t pid = pid_error;

  fscanf (file, "%d", &pid);

  if (fclose(file) == EOF)
  {
    return pid_error;
  }

  return pid;
}

bool_t
write_pid_to_file (const string_t const file_path, const pid_t pid)
{
  FILE * const file = fopen (file_path, "w");

  if (!file)
  {
    return false;
  }

  fprintf (file, "%d\n", pid);

  if (fclose(file) == EOF)
  {
    return false;
  }

  return true;
}

bool_t
pid_exists (const pid_t pid)
{
  if (pid <= 0)
  {
    return false;
  }

  if (kill (pid, 0) < 0 && errno == ESRCH)
  {
    return false;
  }

  return true;
}

As you can see, with these functions you can read the PID number from a PID file, write the PID number to a PID file and checking if there is a process in the operating system with a PID number. Also, I would like to show you a code snippet of a single instance background daemon handling and maintaining its PID file.

Here is the code snippet:

  ... code before

  // in case the pid file already exists.
  if (file_exists (pid_file_path))
  {
    // try to check if the pid file is readable.
    if (!file_is_readable (pid_file_path))
    {
      log_error (pid_file_is_not_readable_message);

      return false;
    }

    // try to read the pid from the pid file.
    const pid_t pid_from_pid_file = read_pid_from_file (pid_file_path);

    // if there is a pid that really exists in the system.
    if (pid_from_pid_file != -1 && pid_exists (pid_from_pid_file))
    {
      log_error (another_instance_probably_running_message);

      return false;
    }

    // try to remove the pid file since it is garbage.
    if (!remove_file (pid_file_path))
    {
      log_error (failed_to_remove_pid_file_message);

      return false;
    }
  }

  // try to create the pid file and write the pid of the daemon to it.
  if (!write_pid_to_file (pid_file_path, getpid ()))
  {
    log_error (failed_to_write_pid_file_message);

    return false;
  }

  ... code after

Lastly, it is a good practice to remove the PID file whenever the daemon terminates.

Happy Hacking!

  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: