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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20