commit | author | age
|
7f6076
|
1 |
/* vim: set ts=4 sts=4 sw=4 noet : */ |
d7639a
|
2 |
#include<stdio.h> |
SP |
3 |
#include<stdlib.h> |
|
4 |
#include "general.h" |
|
5 |
#include<stdarg.h> |
|
6 |
|
1ab449
|
7 |
#include <sys/time.h> |
SP |
8 |
#include <unistd.h> |
|
9 |
#include <time.h> |
|
10 |
|
fbbc8e
|
11 |
#include <sys/stat.h> |
SP |
12 |
#include <fcntl.h> |
|
13 |
#include <errno.h> |
|
14 |
#include <string.h> |
1ab449
|
15 |
|
a10dd5
|
16 |
ts_uint ts_fprintf(FILE *fd, char *fmt, ...){ |
d7639a
|
17 |
if(quiet) return TS_SUCCESS; |
1ab449
|
18 |
va_list ap; |
SP |
19 |
va_start(ap,fmt); |
|
20 |
char tmbuf[255]; |
|
21 |
struct timeval now; |
|
22 |
gettimeofday(&now, 0); |
|
23 |
strftime(tmbuf, sizeof tmbuf, "%Y-%m-%d %H:%M:%S", localtime(&now.tv_sec)); |
|
24 |
fprintf(fd, "[%s] ",tmbuf); |
a10dd5
|
25 |
vfprintf(fd, fmt, ap); /* Call vfprintf */ |
d7639a
|
26 |
va_end(ap); /* Cleanup the va_list */ |
SP |
27 |
return TS_SUCCESS; |
|
28 |
} |
|
29 |
|
|
30 |
void err(char *text){ |
|
31 |
ts_fprintf(stderr,"Err: %s\n", text); |
|
32 |
} |
|
33 |
|
|
34 |
void fatal(char *text, ts_int errcode){ |
|
35 |
ts_fprintf(stderr,"Fatal: %s. TERMINATED!\n", text); |
|
36 |
exit(errcode); |
|
37 |
} |
|
38 |
|
|
39 |
|
fbbc8e
|
40 |
/* Open/create the file named in 'pidFile', lock it, optionally set the |
SP |
41 |
close-on-exec flag for the file descriptor, write our PID into the file, |
|
42 |
and (in case the caller is interested) return the file descriptor |
|
43 |
referring to the locked file. The caller is responsible for deleting |
|
44 |
'pidFile' file (just) before process termination. 'progName' should be the |
|
45 |
name of the calling program (i.e., argv[0] or similar), and is used only for |
|
46 |
diagnostic messages. If we can't open 'pidFile', or we encounter some other |
|
47 |
error, then we print an appropriate diagnostic and terminate. */ |
|
48 |
|
|
49 |
/* |
|
50 |
This is filelock/create_pid_file.c (Listing 55-4, page 1143), an example program file from the book, The Linux Programming Interface. |
|
51 |
|
|
52 |
The source code file is copyright 2010, Michael Kerrisk, and is licensed under the GNU Lesser General Public License, version 3. |
|
53 |
*/ |
|
54 |
|
|
55 |
#define BUF_SIZE 100 |
|
56 |
int createPidFile(const char *progName, const char *pidFile, int flags) |
|
57 |
{ |
|
58 |
int fd; |
|
59 |
char buf[BUF_SIZE]; |
|
60 |
|
|
61 |
fd = open(pidFile, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); |
|
62 |
if (fd == -1){ |
|
63 |
ts_fprintf(stderr,"Could not open PID file %s", pidFile); |
6e42ef
|
64 |
fatal("Cannot continue (1)",1); |
fbbc8e
|
65 |
} |
SP |
66 |
if (flags & CPF_CLOEXEC) { |
|
67 |
|
|
68 |
/* Set the close-on-exec file descriptor flag */ |
|
69 |
|
|
70 |
/* Instead of the following steps, we could (on Linux) have opened the |
|
71 |
file with O_CLOEXEC flag. However, not all systems support open() |
|
72 |
O_CLOEXEC (which was standardized only in SUSv4), so instead we use |
|
73 |
fcntl() to set the close-on-exec flag after opening the file */ |
|
74 |
|
|
75 |
flags = fcntl(fd, F_GETFD); /* Fetch flags */ |
|
76 |
if (flags == -1){ |
|
77 |
ts_fprintf(stderr,"Could not get flags for PID file %s", pidFile); |
6e42ef
|
78 |
fatal("Cannot continue (2)",1); |
fbbc8e
|
79 |
} |
SP |
80 |
flags |= FD_CLOEXEC; /* Turn on FD_CLOEXEC */ |
|
81 |
|
|
82 |
if (fcntl(fd, F_SETFD, flags) == -1) /* Update flags */ |
|
83 |
ts_fprintf(stderr,"Could not set flags for PID file %s", pidFile); |
6e42ef
|
84 |
fatal("Cannot continue (3)",1); |
fbbc8e
|
85 |
|
SP |
86 |
} |
|
87 |
|
|
88 |
if (lockRegion(fd, F_WRLCK, SEEK_SET, 0, 0) == -1) { |
|
89 |
if (errno == EAGAIN || errno == EACCES){ |
|
90 |
ts_fprintf(stderr,"PID file '%s' is locked; probably " |
|
91 |
"'%s' is already running", pidFile, progName); |
6e42ef
|
92 |
fatal("Cannot continue (4)",1); |
fbbc8e
|
93 |
} |
SP |
94 |
else{ |
|
95 |
ts_fprintf(stderr,"Unable to lock PID file '%s'", pidFile); |
6e42ef
|
96 |
fatal("Cannot continue (5)",1); |
fbbc8e
|
97 |
} |
SP |
98 |
} |
|
99 |
|
|
100 |
if (ftruncate(fd, 0) == -1){ |
|
101 |
ts_fprintf(stderr,"Could not truncate PID file '%s'", pidFile); |
6e42ef
|
102 |
fatal("Cannot continue (6)",1); |
fbbc8e
|
103 |
} |
SP |
104 |
|
|
105 |
snprintf(buf, BUF_SIZE, "%ld\n", (long) getpid()); |
|
106 |
if (write(fd, buf, strlen(buf)) != strlen(buf)){ |
|
107 |
|
|
108 |
ts_fprintf(stderr,"Writing to PID file '%s'", pidFile); |
6e42ef
|
109 |
fatal("Cannot continue (7)",1); |
fbbc8e
|
110 |
} |
SP |
111 |
return fd; |
|
112 |
} |
|
113 |
|
|
114 |
|
|
115 |
|
|
116 |
/* Lock a file region (private; public interfaces below) */ |
|
117 |
|
|
118 |
static int |
|
119 |
lockReg(int fd, int cmd, int type, int whence, int start, off_t len) |
|
120 |
{ |
|
121 |
struct flock fl; |
|
122 |
|
|
123 |
fl.l_type = type; |
|
124 |
fl.l_whence = whence; |
|
125 |
fl.l_start = start; |
|
126 |
fl.l_len = len; |
|
127 |
|
|
128 |
return fcntl(fd, cmd, &fl); |
|
129 |
} |
|
130 |
|
|
131 |
|
|
132 |
int /* Lock a file region using nonblocking F_SETLK */ |
|
133 |
lockRegion(int fd, int type, int whence, int start, int len) |
|
134 |
{ |
|
135 |
return lockReg(fd, F_SETLK, type, whence, start, len); |
|
136 |
} |
|
137 |
|