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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20