-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathdaemon.c
More file actions
150 lines (145 loc) · 4.84 KB
/
Copy pathdaemon.c
File metadata and controls
150 lines (145 loc) · 4.84 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/*
* daemon.c - functions for running in background like a daemon
*
* Copyright 2013 Edward V. Emelianoff <eddy@sao.ru>
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
#include <stdio.h> // printf, fopen, ...
#include <unistd.h> // getpid
#include <signal.h>
#include <stdio.h> // perror
#include <sys/types.h> // opendir
#include <dirent.h> // opendir
#include <sys/stat.h> // stat
#include <fcntl.h> // fcntl
#include <stdlib.h> // exit
#include <string.h> // memset
#include "usefull_macros.h"
/**
* @brief sl_getPSname - read process name from /proc/PID/cmdline
* @param pid - PID of interesting process
* @return filename or NULL if not found
* don't use this function twice for different names without copying
* its returning by strdup, because `name` contains in static array
*/
char *sl_getPSname(pid_t pid){
static char name[PATH_MAX];
char *pp = name, byte, path[PATH_MAX];
FILE *file;
int cntr = 0;
size_t sz;
snprintf(path, PATH_MAX, PROC_BASE "/%d/cmdline", pid);
file = fopen(path, "r");
if(!file) return NULL; // there's no such file
do{ // read basename
sz = fread(&byte, 1, 1, file);
if(sz != 1) break;
if(byte != '/') *pp++ = byte;
else{
pp = name;
cntr = 0;
}
}while(byte && cntr++ < PATH_MAX-1);
name[cntr] = 0;
fclose(file);
return name;
}
/**
* @brief sl_iffound_deflt - default action when running process found
* @param pid - another process' pid
* Redefine this function for user action
*/
void WEAK sl_iffound_deflt(pid_t pid){
fprintf(stderr, _("\nFound running process (pid=%d), exit.\n"), pid);
exit(-1);
}
/**
* check wether there is a same running process
* exit if there is a running process or error
* Checking have 2 steps:
* 1) check pidfile and its owner (if you run a copy?)
* 2) check /proc for executables with the same name (no/wrong pidfile)
* @param selfname - deprecated, maybe remove in next versions
* @param pidfilename - name of pidfile or NULL if none
*/
void sl_check4running(char _U_ *selfname, char *pidfilename){
DIR *dir;
FILE *pidfile;
struct dirent *de;
struct stat s_buf;
pid_t pid = 0, self;
char *name, *myname;
self = getpid(); // get self PID
if(!(dir = opendir(PROC_BASE))){ // open /proc directory
ERR(PROC_BASE);
}
if(!(name = sl_getPSname(self))){ // error reading self name
ERR(_("Can't read self name"));
}
myname = strdup(name);
if(pidfilename && stat(pidfilename, &s_buf) == 0){ // pidfile exists
pidfile = fopen(pidfilename, "r");
if(pidfile){
if(fscanf(pidfile, "%d", &pid) == 1){ // read PID of (possibly) running process
if((name = sl_getPSname(pid)) && strncmp(name, myname, 255) == 0){
sl_iffound_deflt(pid);
exit(1); // run `exit` if user forgot to do it himself
}
}
fclose(pidfile);
}
}
// There is no pidfile or it consists a wrong record
while((de = readdir(dir))){ // scan /proc
if(!(pid = (pid_t)atoi(de->d_name)) || pid == self) // pass non-PID files and self
continue;
if((name = sl_getPSname(pid)) && strncmp(name, myname, 255) == 0){
sl_iffound_deflt(pid);
exit(1);
}
}
closedir(dir);
free(myname);
if(pidfilename){
pidfile = fopen(pidfilename, "w");
if(!pidfile) ERR(_("Can't open PID file"));
fprintf(pidfile, "%d\n", self); // write self PID to pidfile
fclose(pidfile);
}
}
/**
* @brief sl_daemonize - prepare for daemonize:
* - close stdin/out/err and reopen to /dev/null
* - croot /
* - umask(0)
* - ignore SIGHUP
* @return non-zero if failed
*/
int sl_daemonize(){
if(chdir("/")) return -1;
umask(0);
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
int ofd = open("/dev/null", O_RDWR);
if(ofd < 0) return -1;
if(dup(ofd) < 0) return -1; // STDIN
if(dup(ofd) < 0) return -1; // STDOUT
if(dup(ofd) < 0) return -1; // STDERR
if(SIG_ERR == signal(SIGHUP, SIG_IGN)) return -1;
return 0;
}