/[baselayout]/trunk/src/librc-daemon.c
Gentoo

Contents of /trunk/src/librc-daemon.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2577 - (hide annotations) (download) (as text)
Wed Apr 11 12:44:47 2007 UTC (7 years, 4 months ago) by uberlord
File MIME type: text/x-csrc
File size: 11448 byte(s)
Cuddle up to LKML C style
1 uberlord 2547 /*
2     librc-daemon
3     Finds PID for given daemon criteria
4     Copyright 2007 Gentoo Foundation
5     Released under the GPLv2
6     */
7    
8     #include <sys/types.h>
9     #include <sys/stat.h>
10    
11 uberlord 2549 #if defined(__DragonFly__) || defined(__FreeBSD__) || \
12 uberlord 2577 defined(__NetBSD__) || defined (__OpenBSD__)
13 uberlord 2547 #include <sys/param.h>
14     #include <sys/user.h>
15     #include <sys/sysctl.h>
16     #include <kvm.h>
17     #include <limits.h>
18     #endif
19    
20     #ifndef __linux__
21     #include <libgen.h>
22     #endif
23    
24     #include <dirent.h>
25     #include <errno.h>
26     #include <fcntl.h>
27     #include <stdio.h>
28     #include <stdlib.h>
29     #include <string.h>
30     #include <unistd.h>
31    
32     #include "einfo.h"
33     #include "rc.h"
34     #include "rc-misc.h"
35     #include "strlist.h"
36    
37     #if defined(__linux__)
38     static bool pid_is_cmd (pid_t pid, const char *cmd)
39     {
40 uberlord 2577 char buffer[32];
41     FILE *fp;
42     int c;
43 uberlord 2547
44 uberlord 2577 snprintf(buffer, sizeof (buffer), "/proc/%d/stat", pid);
45     if ((fp = fopen (buffer, "r")) == NULL)
46     return (false);
47 uberlord 2547
48 uberlord 2577 while ((c = getc (fp)) != EOF && c != '(')
49     ;
50 uberlord 2547
51 uberlord 2577 if (c != '(') {
52     fclose(fp);
53     return (false);
54     }
55 uberlord 2547
56 uberlord 2577 while ((c = getc (fp)) != EOF && c == *cmd)
57     cmd++;
58 uberlord 2547
59 uberlord 2577 fclose (fp);
60 uberlord 2547
61 uberlord 2577 return ((c == ')' && *cmd == '\0') ? true : false);
62 uberlord 2547 }
63    
64     static bool pid_is_exec (pid_t pid, const char *exec)
65     {
66 uberlord 2577 char cmdline[32];
67     char buffer[PATH_MAX];
68     char *p;
69     int fd = -1;
70     int r;
71 uberlord 2547
72 uberlord 2577 snprintf (cmdline, sizeof (cmdline), "/proc/%u/exe", pid);
73     memset (buffer, 0, sizeof (buffer));
74     if (readlink (cmdline, buffer, sizeof (buffer)) != -1) {
75     if (strcmp (exec, buffer) == 0)
76     return (true);
77 uberlord 2547
78 uberlord 2577 /* We should cater for deleted binaries too */
79     if (strlen (buffer) > 10) {
80     p = buffer + (strlen (buffer) - 10);
81     if (strcmp (p, " (deleted)") == 0) {
82     *p = 0;
83     if (strcmp (buffer, exec) == 0)
84     return (true);
85     }
86     }
87     }
88 uberlord 2547
89 uberlord 2577 snprintf (cmdline, sizeof (cmdline), "/proc/%u/cmdline", pid);
90     if ((fd = open (cmdline, O_RDONLY)) < 0)
91     return (false);
92 uberlord 2547
93 uberlord 2577 r = read(fd, buffer, sizeof (buffer));
94     close (fd);
95 uberlord 2547
96 uberlord 2577 if (r == -1)
97     return 0;
98 uberlord 2547
99 uberlord 2577 buffer[r] = 0;
100     return (strcmp (exec, buffer) == 0 ? true : false);
101 uberlord 2547 }
102    
103     pid_t *rc_find_pids (const char *exec, const char *cmd,
104 uberlord 2577 uid_t uid, pid_t pid)
105 uberlord 2547 {
106 uberlord 2577 DIR *procdir;
107     struct dirent *entry;
108     int npids = 0;
109     int foundany = false;
110     pid_t p;
111     pid_t *pids = NULL;
112     char buffer[PATH_MAX];
113     struct stat sb;
114     pid_t runscript_pid = 0;
115     char *pp;
116 uberlord 2547
117 uberlord 2577 if ((procdir = opendir ("/proc")) == NULL)
118     eerrorx ("opendir `/proc': %s", strerror (errno));
119 uberlord 2547
120 uberlord 2577 /*
121     We never match RC_RUNSCRIPT_PID if present so we avoid the below
122     scenario
123 uberlord 2547
124 uberlord 2577 /etc/init.d/ntpd stop does
125     start-stop-daemon --stop --name ntpd
126     catching /etc/init.d/ntpd stop
127 uberlord 2547
128 uberlord 2577 nasty
129     */
130 uberlord 2547
131 uberlord 2577 if ((pp = getenv ("RC_RUNSCRIPT_PID"))) {
132     if (sscanf (pp, "%d", &runscript_pid) != 1)
133     runscript_pid = 0;
134     }
135 uberlord 2547
136 uberlord 2577 while ((entry = readdir (procdir)) != NULL) {
137     if (sscanf (entry->d_name, "%d", &p) != 1)
138     continue;
139     foundany = true;
140 uberlord 2547
141 uberlord 2577 if (runscript_pid != 0 && runscript_pid == p)
142     continue;
143 uberlord 2547
144 uberlord 2577 if (pid != 0 && pid != p)
145     continue;
146 uberlord 2547
147 uberlord 2577 if (uid) {
148     snprintf (buffer, sizeof (buffer), "/proc/%d", pid);
149     if (stat (buffer, &sb) != 0 || sb.st_uid != uid)
150     continue;
151     }
152 uberlord 2547
153 uberlord 2577 if (cmd && ! pid_is_cmd (p, cmd))
154     continue;
155 uberlord 2569
156 uberlord 2577 if (exec && ! cmd && ! pid_is_exec (p, exec))
157     continue;
158 uberlord 2547
159 uberlord 2577 pids = realloc (pids, sizeof (pid_t) * (npids + 2));
160     if (! pids)
161     eerrorx ("memory exhausted");
162 uberlord 2547
163 uberlord 2577 pids[npids] = p;
164     pids[npids + 1] = 0;
165     npids++;
166     }
167     closedir (procdir);
168 uberlord 2547
169 uberlord 2577 if (! foundany)
170     eerrorx ("nothing in /proc");
171 uberlord 2547
172 uberlord 2577 return (pids);
173 uberlord 2547 }
174    
175 uberlord 2549 #elif defined(__DragonFly__) || defined(__FreeBSD__) || \
176 uberlord 2577 defined(__NetBSD__) || defined(__OpenBSD__)
177 uberlord 2547
178 uberlord 2549 # if defined(__DragonFly__) || defined(__FreeBSD__)
179     # ifndef KERN_PROC_PROC
180     # define KERN_PROC_PROC KERN_PROC_ALL
181     # endif
182 uberlord 2547 # define _KINFO_PROC kinfo_proc
183     # define _KVM_GETARGV kvm_getargv
184     # define _GET_KINFO_UID(kp) (kp.ki_ruid)
185     # define _GET_KINFO_COMM(kp) (kp.ki_comm)
186     # define _GET_KINFO_PID(kp) (kp.ki_pid)
187     # else
188     # define _KINFO_PROC kinfo_proc2
189     # define _KVM_GETARGV kvm_getargv2
190     # define _GET_KINFO_UID(kp) (kp.p_ruid)
191     # define _GET_KINFO_COMM(kp) (kp.p_comm)
192     # define _GET_KINFO_PID(kp) (kp.p_pid)
193     # endif
194    
195     pid_t *rc_find_pids (const char *exec, const char *cmd,
196 uberlord 2577 uid_t uid, pid_t pid)
197 uberlord 2547 {
198 uberlord 2577 static kvm_t *kd = NULL;
199     char errbuf[_POSIX2_LINE_MAX];
200     struct _KINFO_PROC *kp;
201     int i;
202     int processes = 0;
203     int argc = 0;
204     char **argv;
205     pid_t *pids = NULL;
206     int npids = 0;
207 uberlord 2547
208 uberlord 2577 if ((kd = kvm_openfiles (NULL, NULL, NULL, O_RDONLY, errbuf)) == NULL)
209     eerrorx ("kvm_open: %s", errbuf);
210 uberlord 2547
211 uberlord 2549 #if defined(__DragonFly__) || defined( __FreeBSD__)
212 uberlord 2577 kp = kvm_getprocs (kd, KERN_PROC_PROC, 0, &processes);
213 uberlord 2549 #else
214 uberlord 2577 kp = kvm_getproc2 (kd, KERN_PROC_ALL, 0, sizeof(struct kinfo_proc2),
215     &processes);
216 uberlord 2549 #endif
217 uberlord 2577 for (i = 0; i < processes; i++) {
218     pid_t p = _GET_KINFO_PID (kp[i]);
219     if (pid != 0 && pid != p)
220     continue;
221 uberlord 2547
222 uberlord 2577 if (uid != 0 && uid != _GET_KINFO_UID (kp[i]))
223     continue;
224 uberlord 2547
225 uberlord 2577 if (cmd) {
226     if (! _GET_KINFO_COMM (kp[i]) ||
227     strcmp (cmd, _GET_KINFO_COMM (kp[i])) != 0)
228     continue;
229     }
230 uberlord 2547
231 uberlord 2577 if (exec && ! cmd) {
232     if ((argv = _KVM_GETARGV (kd, &kp[i], argc)) == NULL || ! *argv)
233     continue;
234 uberlord 2547
235 uberlord 2577 if (strcmp (*argv, exec) != 0)
236     continue;
237     }
238 uberlord 2547
239 uberlord 2577 pids = realloc (pids, sizeof (pid_t) * (npids + 2));
240     if (! pids)
241     eerrorx ("memory exhausted");
242 uberlord 2547
243 uberlord 2577 pids[npids] = p;
244     pids[npids + 1] = 0;
245     npids++;
246     }
247     kvm_close(kd);
248 uberlord 2547
249 uberlord 2577 return (pids);
250 uberlord 2547 }
251    
252     #else
253     # error "Platform not supported!"
254     #endif
255    
256     static bool _match_daemon (const char *path, const char *file,
257 uberlord 2577 const char *mexec, const char *mname,
258     const char *mpidfile)
259 uberlord 2547 {
260 uberlord 2577 char buffer[RC_LINEBUFFER];
261     char *ffile = rc_strcatpaths (path, file, (char *) NULL);
262     FILE *fp;
263     int lc = 0;
264     int m = 0;
265 uberlord 2547
266 uberlord 2577 if (! rc_exists (ffile)) {
267     free (ffile);
268     return (false);
269     }
270 uberlord 2547
271 uberlord 2577 if ((fp = fopen (ffile, "r")) == NULL) {
272     eerror ("fopen `%s': %s", ffile, strerror (errno));
273     free (ffile);
274     return (false);
275     }
276 uberlord 2547
277 uberlord 2577 if (! mname)
278     m += 10;
279     if (! mpidfile)
280     m += 100;
281 uberlord 2547
282 uberlord 2577 memset (buffer, 0, sizeof (buffer));
283     while ((fgets (buffer, RC_LINEBUFFER, fp))) {
284     int lb = strlen (buffer) - 1;
285     if (buffer[lb] == '\n')
286     buffer[lb] = 0;
287 uberlord 2547
288 uberlord 2577 if (strcmp (buffer, mexec) == 0)
289     m += 1;
290     else if (mname && strcmp (buffer, mname) == 0)
291     m += 10;
292     else if (mpidfile && strcmp (buffer, mpidfile) == 0)
293     m += 100;
294 uberlord 2547
295 uberlord 2577 if (m == 111)
296     break;
297 uberlord 2547
298 uberlord 2577 lc++;
299     if (lc > 5)
300     break;
301     }
302     fclose (fp);
303     free (ffile);
304 uberlord 2547
305 uberlord 2577 return (m == 111 ? true : false);
306 uberlord 2547 }
307    
308     void rc_set_service_daemon (const char *service, const char *exec,
309 uberlord 2577 const char *name, const char *pidfile,
310     bool started)
311 uberlord 2547 {
312 uberlord 2577 char *dirpath = rc_strcatpaths (RC_SVCDIR, "daemons", basename (service),
313     (char *) NULL);
314     char **files = NULL;
315     char *file;
316     char *ffile = NULL;
317     int i;
318     char *mexec;
319     char *mname;
320     char *mpidfile;
321     int nfiles = 0;
322 uberlord 2547
323 uberlord 2577 if (! exec && ! name && ! pidfile)
324     return;
325 uberlord 2547
326 uberlord 2577 if (exec) {
327     i = strlen (exec) + 6;
328     mexec = rc_xmalloc (sizeof (char *) * i);
329     snprintf (mexec, i, "exec=%s", exec);
330     } else
331     mexec = strdup ("exec=");
332 uberlord 2547
333 uberlord 2577 if (name) {
334     i = strlen (name) + 6;
335     mname = rc_xmalloc (sizeof (char *) * i);
336     snprintf (mname, i, "name=%s", name);
337     } else
338     mname = strdup ("name=");
339 uberlord 2547
340 uberlord 2577 if (pidfile) {
341     i = strlen (pidfile) + 9;
342     mpidfile = rc_xmalloc (sizeof (char *) * i);
343     snprintf (mpidfile, i, "pidfile=%s", pidfile);
344     } else
345     mpidfile = strdup ("pidfile=");
346 uberlord 2547
347 uberlord 2577 /* Regardless, erase any existing daemon info */
348     if (rc_is_dir (dirpath)) {
349     char *oldfile = NULL;
350     files = rc_ls_dir (NULL, dirpath, 0);
351     STRLIST_FOREACH (files, file, i) {
352     ffile = rc_strcatpaths (dirpath, file, (char *) NULL);
353     nfiles++;
354 uberlord 2547
355 uberlord 2577 if (! oldfile) {
356     if (_match_daemon (dirpath, file, mexec, mname, mpidfile)) {
357     unlink (ffile);
358     oldfile = ffile;
359     nfiles--;
360     }
361     } else {
362     rename (ffile, oldfile);
363     free (oldfile);
364     oldfile = ffile;
365     }
366     }
367     if (ffile)
368     free (ffile);
369     free (files);
370     }
371 uberlord 2547
372 uberlord 2577 /* Now store our daemon info */
373     if (started) {
374     char buffer[10];
375     FILE *fp;
376 uberlord 2547
377 uberlord 2577 if (! rc_is_dir (dirpath))
378     if (mkdir (dirpath, 0755) != 0)
379     eerror ("mkdir `%s': %s", dirpath, strerror (errno));
380 uberlord 2547
381 uberlord 2577 snprintf (buffer, sizeof (buffer), "%03d", nfiles + 1);
382     file = rc_strcatpaths (dirpath, buffer, (char *) NULL);
383     if ((fp = fopen (file, "w")) == NULL)
384     eerror ("fopen `%s': %s", file, strerror (errno));
385     else {
386     fprintf (fp, "%s\n%s\n%s\n", mexec, mname, mpidfile);
387     fclose (fp);
388     }
389     free (file);
390     }
391 uberlord 2547
392 uberlord 2577 free (mexec);
393     free (mname);
394     free (mpidfile);
395     free (dirpath);
396 uberlord 2547 }
397    
398     bool rc_service_started_daemon (const char *service, const char *exec,
399 uberlord 2577 int indx)
400 uberlord 2547 {
401 uberlord 2577 char *dirpath;
402     char *file;
403     int i;
404     char *mexec;
405     bool retval = false;
406 uberlord 2547
407 uberlord 2577 if (! service || ! exec)
408     return (false);
409 uberlord 2547
410 uberlord 2577 dirpath = rc_strcatpaths (RC_SVCDIR, "daemons", basename (service),
411     (char *) NULL);
412     if (! rc_is_dir (dirpath)) {
413     free (dirpath);
414     return (false);
415     }
416 uberlord 2547
417 uberlord 2577 i = strlen (exec) + 6;
418     mexec = rc_xmalloc (sizeof (char *) * i);
419     snprintf (mexec, i, "exec=%s", exec);
420 uberlord 2547
421 uberlord 2577 if (indx > 0) {
422     int len = sizeof (char *) * 10;
423     file = rc_xmalloc (len);
424     snprintf (file, len, "%03d", indx);
425     retval = _match_daemon (dirpath, file, mexec, NULL, NULL);
426     free (file);
427     } else {
428     char **files = rc_ls_dir (NULL, dirpath, 0);
429     STRLIST_FOREACH (files, file, i) {
430     retval = _match_daemon (dirpath, file, mexec, NULL, NULL);
431     if (retval)
432     break;
433     }
434     free (files);
435     }
436 uberlord 2547
437 uberlord 2577 free (mexec);
438     return (retval);
439 uberlord 2547 }
440    
441     bool rc_service_daemons_crashed (const char *service)
442     {
443 uberlord 2577 char *dirpath;
444     char **files;
445     char *file;
446     char *path;
447     int i;
448     FILE *fp;
449     char buffer[RC_LINEBUFFER];
450     char *exec = NULL;
451     char *name = NULL;
452     char *pidfile = NULL;
453     pid_t pid = 0;
454     pid_t *pids = NULL;
455     char *p;
456     char *token;
457     bool retval = false;
458 uberlord 2547
459 uberlord 2577 if (! service)
460     return (false);
461 uberlord 2547
462 uberlord 2577 dirpath = rc_strcatpaths (RC_SVCDIR, "daemons", basename (service),
463     (char *) NULL);
464     if (! rc_is_dir (dirpath)) {
465     free (dirpath);
466     return (false);
467     }
468 uberlord 2547
469 uberlord 2577 memset (buffer, 0, sizeof (buffer));
470     files = rc_ls_dir (NULL, dirpath, 0);
471     STRLIST_FOREACH (files, file, i) {
472     path = rc_strcatpaths (dirpath, file, (char *) NULL);
473     fp = fopen (path, "r");
474     free (path);
475     if (! fp) {
476     eerror ("fopen `%s': %s", file, strerror (errno));
477     continue;
478     }
479 uberlord 2547
480 uberlord 2577 while ((fgets (buffer, RC_LINEBUFFER, fp))) {
481     int lb = strlen (buffer) - 1;
482     if (buffer[lb] == '\n')
483     buffer[lb] = 0;
484 uberlord 2547
485 uberlord 2577 p = buffer;
486     if ((token = strsep (&p, "=")) == NULL || ! p)
487     continue;
488 uberlord 2547
489 uberlord 2577 if (strlen (p) == 0)
490     continue;
491 uberlord 2547
492 uberlord 2577 if (strcmp (token, "exec") == 0) {
493     if (exec)
494     free (exec);
495     exec = strdup (p);
496     } else if (strcmp (token, "name") == 0) {
497     if (name)
498     free (name);
499     name = strdup (p);
500     } else if (strcmp (token, "pidfile") == 0) {
501     if (pidfile)
502     free (pidfile);
503     pidfile = strdup (p);
504     }
505     }
506     fclose (fp);
507 uberlord 2547
508 uberlord 2577 pid = 0;
509     if (pidfile) {
510     if (! rc_exists (pidfile)) {
511     retval = true;
512     break;
513     }
514 uberlord 2547
515 uberlord 2577 if ((fp = fopen (pidfile, "r")) == NULL) {
516     eerror ("fopen `%s': %s", pidfile, strerror (errno));
517     retval = true;
518     break;
519     }
520 uberlord 2547
521 uberlord 2577 if (fscanf (fp, "%d", &pid) != 1) {
522     eerror ("no pid found in `%s'", pidfile);
523     fclose (fp);
524     retval = true;
525     break;
526     }
527 uberlord 2547
528 uberlord 2577 fclose (fp);
529     free (pidfile);
530     pidfile = NULL;
531     }
532 uberlord 2547
533 uberlord 2577 if ((pids = rc_find_pids (exec, name, 0, pid)) == NULL) {
534     retval = true;
535     break;
536     }
537     free (pids);
538 uberlord 2547
539 uberlord 2577 if (exec) {
540     free (exec);
541     exec = NULL;
542     }
543     if (name) {
544     free (name);
545     name = NULL;
546     }
547     }
548 uberlord 2547
549 uberlord 2577 if (exec) {
550     free (exec);
551     exec = NULL;
552     }
553     if (name) {
554     free (name);
555     name = NULL;
556     }
557 uberlord 2547
558 uberlord 2577 free (dirpath);
559     rc_strlist_free (files);
560 uberlord 2547
561 uberlord 2577 return (retval);
562 uberlord 2547 }

  ViewVC Help
Powered by ViewVC 1.1.20