File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / pimd / libite / pidfilefn.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jun 14 09:12:58 2017 UTC (7 years, 4 months ago) by misho
Branches: pimd, MAIN
CVS tags: v2_3_2, HEAD
libite

    1: /* Functions for dealing with PID files (client side)
    2:  *
    3:  * Copyright (c) 2009-2015  Joachim Nilsson <troglobit@gmail.com>
    4:  *
    5:  * Permission to use, copy, modify, and/or distribute this software for any
    6:  * purpose with or without fee is hereby granted, provided that the above
    7:  * copyright notice and this permission notice appear in all copies.
    8:  *
    9:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   10:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   11:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   12:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   13:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   14:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
   15:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   16:  */
   17: 
   18: #include <errno.h>
   19: #include <stdio.h>
   20: #include <stdlib.h>
   21: #include <signal.h>
   22: #include <unistd.h>
   23: 
   24: extern char *__pidfile_name;
   25: extern char *chomp(char *str);
   26: 
   27: /**
   28:  * pidfile_read - Reads a PID value from a pidfile.
   29:  * @pidfile: File containing PID, usually in /var/run/<PROC>.pid
   30:  *
   31:  * This function takes a @pidfile and returns the PID found therein.
   32:  *
   33:  * Returns:
   34:  * On invalid @pidfile -1 and errno set to %EINVAL, when @pidfile does not exist -1
   35:  * and errno set to %ENOENT.  When the pidfile is empty or when its contents cannot
   36:  * be translated this function returns zero (0), on success this function returns
   37:  * a PID value greater than one. PID 1 is reserved for the system init process.
   38:  */
   39: pid_t pidfile_read(const char *pidfile)
   40: {
   41: 	int pid = 0;
   42: 	char buf[16];
   43: 	FILE *fp;
   44: 
   45: 	if (!pidfile) {
   46: 		errno = EINVAL;
   47: 		return -1;
   48: 	}
   49: 
   50: 	fp = fopen(pidfile, "r");
   51: 	if (!fp)
   52: 		return -1;
   53: 
   54: 	if (fgets(buf, sizeof(buf), fp)) {
   55:                 char *ptr = chomp(buf);
   56: 
   57:                 if (ptr) {
   58:                         errno = 0;
   59:                         pid = strtoul(ptr, NULL, 0);
   60:                         if (errno)
   61:                                 pid = 0; /* Failed conversion. */
   62:                 }
   63: 	}
   64: 	fclose(fp);
   65: 
   66: 	return pid;
   67: }
   68: 
   69: /**
   70:  * pidfile_poll - Poll for the existence of a pidfile and return PID
   71:  * @pidfile: Path to pidfile to poll for
   72:  *
   73:  * This function polls for the pidfile at @pidfile for at most 5 seconds
   74:  * before timing out. If the file is created within that time span the
   75:  * file is read and its PID contents returned.
   76:  *
   77:  * Returns:
   78:  * The PID read from @pidfile, or zero on timeout.
   79:  */
   80: pid_t pidfile_poll(const char *pidfile)
   81: {
   82: 	pid_t pid = 0;
   83: 	int tries = 0;
   84: 
   85: 	/* Timeout = 100 * 50ms = 5s */
   86: 	while ((pid = pidfile_read(pidfile)) <= 0 && tries++ < 100)
   87: 		usleep(50000);	/* Wait 50ms between retries */
   88: 
   89: 	if (pid < 0)
   90: 		pid = 0;
   91: 
   92: 	return pid;
   93: }
   94: 
   95: /**
   96:  * pidfile_signal - Send signal to a PID and cleanup pidfile afterwards
   97:  * @pidfile: File containing PID, usually in /var/run/<PROC>.pid
   98:  * @signal: Signal to send to PID found in @pidfile.
   99:  *
  100:  * If @signal is any of %SIGTERM, %SIGKILL, or if kill() returns -1 the
  101:  * @pidfile is removed.
  102:  *
  103:  * Returns:
  104:  * POSIX OK(0) on success, non-zero otherwise.
  105:  */
  106: int pidfile_signal(const char *pidfile, int signal)
  107: {
  108: 	int pid = -1, ret = -1;
  109: 
  110: 	pid = pidfile_read(pidfile);
  111: 	if (pid <= 0)
  112: 		return 1;
  113: 
  114: 	ret = kill(pid, signal);
  115: 	if ((ret == -1) || (signal == SIGTERM) || (signal == SIGKILL))
  116: 		(void)remove(pidfile);
  117: 
  118: 	return 0;
  119: }
  120: 
  121: 
  122: /********************************* UNIT TESTS ************************************/
  123: #ifdef UNITTEST
  124: #include <paths.h>
  125: #include "lite.h"
  126: 
  127: extern char *__progname;
  128: static char PIDFILE[42];
  129: 
  130: static void sigterm_handler(int UNUSED(signo))
  131: {
  132: 	printf("Exiting ...\n");
  133: }
  134: 
  135: static void sigalrm_handler(int UNUSED(signo))
  136: {
  137: 	printf("Testing pidfile() ...\n");
  138: 	pidfile(NULL);
  139: 
  140: 	if (!fexist(PIDFILE))
  141: 		err(1, "pidfile() failed creating %s", PIDFILE);
  142: }
  143: 
  144: int main(void)
  145: {
  146: 	char cmd[80];
  147: 
  148: 	snprintf(PIDFILE, sizeof(PIDFILE), "%s%s.pid", _PATH_VARRUN, __progname);
  149: 
  150: 	signal(SIGTERM, sigterm_handler);
  151: 	signal(SIGALRM, sigalrm_handler);
  152: 	alarm(1);
  153: 
  154: 	printf("Testing pidfile_poll() ...\n");
  155: 	if (!pidfile_poll(PIDFILE))
  156: 		printf("Timed out!\n");
  157: 	else
  158: 		printf("We got signal!\n");
  159: 
  160: 	printf("Reading pid file, should be %d ...\n", getpid());
  161:         printf("=> %d\n", pidfile_read(PIDFILE));
  162: 
  163: 	printf("\nComparing __pidfile_name with our guessed PID filename ...\n");
  164: 	printf("strcmp(\"%s\",\n       \"%s\") => %s\n\n", __pidfile_name, PIDFILE,
  165: 	       !strcmp(__pidfile_name, PIDFILE) ? "OK" : "FAIL");
  166: 
  167: 	/* Occular verification that calling pidfile() again updates mtime */
  168: 	snprintf(cmd, sizeof(cmd), "ls -l --full-time %s", PIDFILE);
  169: 	system(cmd);
  170: 	printf("Before ^^ pidfile() vv after ...\n");
  171: 	pidfile(NULL);
  172: 	system(cmd);
  173: 	
  174:         printf("Signalling ourselves ...\n");
  175: 
  176: 	return pidfile_signal(PIDFILE, SIGTERM);
  177: }
  178: #endif  /* UTEST_PIDFN */
  179: 
  180: /**
  181:  * Local Variables:
  182:  *  compile-command: "make V=1 -f pidfilefn.mk"
  183:  *  version-control: t
  184:  *  indent-tabs-mode: t
  185:  *  c-file-style: "linux"
  186:  * End:
  187:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>