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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2547 - (hide annotations) (download) (as text)
Thu Apr 5 11:18:42 2007 UTC (7 years, 4 months ago) by uberlord
File MIME type: text/x-csrc
File size: 11866 byte(s)
    Rewrite the core parts in C. We now provide librc so other programs can
    query runlevels, services and state without using bash. We also provide
    libeinfo so other programs can easily use our informational functions.

    As such, we have dropped the requirement of using bash as the init script
    shell. We now use /bin/sh and have strived to make the scripts as portable
    as possible. Shells that work are bash and dash. busybox works provided
    you disable s-s-d. If you have WIPE_TMP set to yes in conf.d/bootmisc you
    should disable find too.
    zsh and ksh do not work at this time.

    Networking support is currently being re-vamped also as it was heavily bash
    array based. As such, a new config format is available like so
    config_eth0="1.2.3.4/24 5.6.7.8/16"
    or like so
    config_eth0="'1.2.3.4 netmask 255.255.255.0' '5.6.7.8 netmask 255.255.0.0'"

    We will still support the old bash array format provided that /bin/sh IS
    a link it bash.

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

  ViewVC Help
Powered by ViewVC 1.1.20