Annotation of embedaddon/pimd/libite/pidfilefn.c, revision 1.1
1.1 ! misho 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>