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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2549 - (hide annotations) (download) (as text)
Thu Apr 5 15:01:09 2007 UTC (7 years, 5 months ago) by uberlord
File MIME type: text/x-csrc
File size: 12187 byte(s)
We now compile on OpenBSD (no idea if it works or not yet)
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     return (true);
79    
80     /* We should cater for deleted binaries too */
81     if (strlen (buffer) > 10)
82     {
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     }
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     uid_t uid, pid_t pid)
109     {
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     */
134    
135     if ((pp = getenv ("RC_RUNSCRIPT_PID")))
136     {
137     if (sscanf (pp, "%d", &runscript_pid) != 1)
138     runscript_pid = 0;
139     }
140    
141     while ((entry = readdir (procdir)) != NULL)
142     {
143     if (sscanf (entry->d_name, "%d", &p) != 1)
144     continue;
145     foundany = true;
146    
147     if (runscript_pid != 0 && runscript_pid == p)
148     continue;
149    
150     if (pid != 0 && pid != p)
151     continue;
152    
153     if (uid)
154     {
155     snprintf (buffer, sizeof (buffer), "/proc/%d", pid);
156     if (stat (buffer, &sb) != 0 || sb.st_uid != uid)
157     continue;
158     }
159    
160     if (cmd && ! pid_is_cmd (p, cmd))
161     continue;
162    
163     if (exec && ! cmd && ! pid_is_exec (p, exec))
164     continue;
165    
166     pids = realloc (pids, sizeof (pid_t) * (npids + 2));
167     if (! pids)
168     eerrorx ("memory exhausted");
169    
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     uid_t uid, pid_t pid)
204     {
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     &processes);
223     #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     continue;
229    
230     if (uid != 0 && uid != _GET_KINFO_UID (kp[i]))
231     continue;
232    
233     if (cmd)
234     {
235     if (! _GET_KINFO_COMM (kp[i]) ||
236     strcmp (cmd, _GET_KINFO_COMM (kp[i])) != 0)
237     continue;
238     }
239    
240     if (exec && ! cmd)
241     {
242     if ((argv = _KVM_GETARGV (kd, &kp[i], argc)) == NULL || ! *argv)
243     continue;
244    
245     if (strcmp (*argv, exec) != 0)
246     continue;
247     }
248    
249     pids = realloc (pids, sizeof (pid_t) * (npids + 2));
250     if (! pids)
251     eerrorx ("memory exhausted");
252    
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     const char *mexec, const char *mname,
268     const char *mpidfile)
269     {
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     buffer[lb] = 0;
300    
301     if (strcmp (buffer, mexec) == 0)
302     m += 1;
303     else if (mname && strcmp (buffer, mname) == 0)
304     m += 10;
305     else if (mpidfile && strcmp (buffer, mpidfile) == 0)
306     m += 100;
307    
308     if (m == 111)
309     break;
310    
311     lc++;
312     if (lc > 5)
313     break;
314     }
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     const char *name, const char *pidfile,
323     bool started)
324     {
325 uberlord 2549 char *dirpath = rc_strcatpaths (RC_SVCDIR, "daemons", basename (service),
326     (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     {
373 uberlord 2549 ffile = rc_strcatpaths (dirpath, file, (char *) NULL);
374 uberlord 2547 nfiles++;
375    
376     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     if (ffile)
393     free (ffile);
394     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     if (mkdir (dirpath, 0755) != 0)
405     eerror ("mkdir `%s': %s", dirpath, strerror (errno));
406    
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     eerror ("fopen `%s': %s", file, strerror (errno));
411     else
412     {
413     fprintf (fp, "%s\n%s\n%s\n", mexec, mname, mpidfile);
414     fclose (fp);
415     }
416     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     int indx)
427     {
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     (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     file = rc_xmalloc (sizeof (char *) * 10);
452     snprintf (file, sizeof (file), "%03d", indx);
453     retval = _match_daemon (dirpath, file, mexec, NULL, NULL);
454     free (file);
455     }
456     else
457     {
458     char **files = rc_ls_dir (NULL, dirpath, 0);
459     STRLIST_FOREACH (files, file, i)
460     {
461     retval = _match_daemon (dirpath, file, mexec, NULL, NULL);
462     if (retval)
463     break;
464     }
465     free (files);
466     }
467    
468     free (mexec);
469     return (retval);
470     }
471    
472     bool rc_service_daemons_crashed (const char *service)
473     {
474     char *dirpath;
475     char **files;
476     char *file;
477     char *path;
478     int i;
479     FILE *fp;
480     char buffer[RC_LINEBUFFER];
481     char *exec = NULL;
482     char *name = NULL;
483     char *pidfile = NULL;
484     pid_t pid = 0;
485     pid_t *pids = NULL;
486     char *p;
487     char *token;
488     bool retval = false;
489    
490     if (! service)
491     return (false);
492    
493 uberlord 2549 dirpath = rc_strcatpaths (RC_SVCDIR, "daemons", basename (service),
494     (char *) NULL);
495 uberlord 2547 if (! rc_is_dir (dirpath))
496     {
497     free (dirpath);
498     return (false);
499     }
500    
501     memset (buffer, 0, sizeof (buffer));
502     files = rc_ls_dir (NULL, dirpath, 0);
503     STRLIST_FOREACH (files, file, i)
504     {
505 uberlord 2549 path = rc_strcatpaths (dirpath, file, (char *) NULL);
506 uberlord 2547 fp = fopen (path, "r");
507     free (path);
508     if (! fp)
509     {
510     eerror ("fopen `%s': %s", file, strerror (errno));
511     continue;
512     }
513    
514     while ((fgets (buffer, RC_LINEBUFFER, fp)))
515     {
516     int lb = strlen (buffer) - 1;
517     if (buffer[lb] == '\n')
518     buffer[lb] = 0;
519    
520     p = buffer;
521     if ((token = strsep (&p, "=")) == NULL || ! p)
522     continue;
523    
524     if (strlen (p) == 0)
525     continue;
526    
527     if (strcmp (token, "exec") == 0)
528     {
529     if (exec)
530     free (exec);
531     exec = strdup (p);
532     }
533     else if (strcmp (token, "name") == 0)
534     {
535     if (name)
536     free (name);
537     name = strdup (p);
538     }
539     else if (strcmp (token, "pidfile") == 0)
540     {
541     if (pidfile)
542     free (pidfile);
543     pidfile = strdup (p);
544     }
545     }
546     fclose (fp);
547    
548     pid = 0;
549     if (pidfile)
550     {
551     if (! rc_exists (pidfile))
552     {
553     retval = true;
554     break;
555     }
556    
557     if ((fp = fopen (pidfile, "r")) == NULL)
558     {
559     eerror ("fopen `%s': %s", pidfile, strerror (errno));
560     retval = true;
561     break;
562     }
563    
564     if (fscanf (fp, "%d", &pid) != 1)
565     {
566     eerror ("no pid found in `%s'", pidfile);
567     fclose (fp);
568     retval = true;
569     break;
570     }
571    
572     fclose (fp);
573     free (pidfile);
574     pidfile = NULL;
575     }
576    
577     if ((pids = rc_find_pids (exec, name, 0, pid)) == NULL)
578     {
579     retval = true;
580     break;
581     }
582     free (pids);
583    
584     if (exec)
585     {
586     free (exec);
587     exec = NULL;
588     }
589     if (name)
590     {
591     free (name);
592     name = NULL;
593     }
594     }
595    
596     if (exec)
597     {
598     free (exec);
599     exec = NULL;
600     }
601     if (name)
602     {
603     free (name);
604     name = NULL;
605     }
606    
607     free (dirpath);
608     rc_strlist_free (files);
609    
610     return (retval);
611     }

  ViewVC Help
Powered by ViewVC 1.1.20