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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2577 - (show annotations) (download) (as text)
Wed Apr 11 12:44:47 2007 UTC (7 years, 7 months ago) by uberlord
File MIME type: text/x-csrc
File size: 11448 byte(s)
Cuddle up to LKML C style
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 <sys/types.h>
9 #include <sys/stat.h>
10
11 #if defined(__DragonFly__) || defined(__FreeBSD__) || \
12 defined(__NetBSD__) || defined (__OpenBSD__)
13 #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 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 if (strcmp (exec, buffer) == 0)
76 return (true);
77
78 /* 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
89 snprintf (cmdline, sizeof (cmdline), "/proc/%u/cmdline", pid);
90 if ((fd = open (cmdline, O_RDONLY)) < 0)
91 return (false);
92
93 r = read(fd, buffer, sizeof (buffer));
94 close (fd);
95
96 if (r == -1)
97 return 0;
98
99 buffer[r] = 0;
100 return (strcmp (exec, buffer) == 0 ? true : false);
101 }
102
103 pid_t *rc_find_pids (const char *exec, const char *cmd,
104 uid_t uid, pid_t pid)
105 {
106 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
117 if ((procdir = opendir ("/proc")) == NULL)
118 eerrorx ("opendir `/proc': %s", strerror (errno));
119
120 /*
121 We never match RC_RUNSCRIPT_PID if present so we avoid the below
122 scenario
123
124 /etc/init.d/ntpd stop does
125 start-stop-daemon --stop --name ntpd
126 catching /etc/init.d/ntpd stop
127
128 nasty
129 */
130
131 if ((pp = getenv ("RC_RUNSCRIPT_PID"))) {
132 if (sscanf (pp, "%d", &runscript_pid) != 1)
133 runscript_pid = 0;
134 }
135
136 while ((entry = readdir (procdir)) != NULL) {
137 if (sscanf (entry->d_name, "%d", &p) != 1)
138 continue;
139 foundany = true;
140
141 if (runscript_pid != 0 && runscript_pid == p)
142 continue;
143
144 if (pid != 0 && pid != p)
145 continue;
146
147 if (uid) {
148 snprintf (buffer, sizeof (buffer), "/proc/%d", pid);
149 if (stat (buffer, &sb) != 0 || sb.st_uid != uid)
150 continue;
151 }
152
153 if (cmd && ! pid_is_cmd (p, cmd))
154 continue;
155
156 if (exec && ! cmd && ! pid_is_exec (p, exec))
157 continue;
158
159 pids = realloc (pids, sizeof (pid_t) * (npids + 2));
160 if (! pids)
161 eerrorx ("memory exhausted");
162
163 pids[npids] = p;
164 pids[npids + 1] = 0;
165 npids++;
166 }
167 closedir (procdir);
168
169 if (! foundany)
170 eerrorx ("nothing in /proc");
171
172 return (pids);
173 }
174
175 #elif defined(__DragonFly__) || defined(__FreeBSD__) || \
176 defined(__NetBSD__) || defined(__OpenBSD__)
177
178 # if defined(__DragonFly__) || defined(__FreeBSD__)
179 # ifndef KERN_PROC_PROC
180 # define KERN_PROC_PROC KERN_PROC_ALL
181 # endif
182 # 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 uid_t uid, pid_t pid)
197 {
198 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
208 if ((kd = kvm_openfiles (NULL, NULL, NULL, O_RDONLY, errbuf)) == NULL)
209 eerrorx ("kvm_open: %s", errbuf);
210
211 #if defined(__DragonFly__) || defined( __FreeBSD__)
212 kp = kvm_getprocs (kd, KERN_PROC_PROC, 0, &processes);
213 #else
214 kp = kvm_getproc2 (kd, KERN_PROC_ALL, 0, sizeof(struct kinfo_proc2),
215 &processes);
216 #endif
217 for (i = 0; i < processes; i++) {
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 if (! _GET_KINFO_COMM (kp[i]) ||
227 strcmp (cmd, _GET_KINFO_COMM (kp[i])) != 0)
228 continue;
229 }
230
231 if (exec && ! cmd) {
232 if ((argv = _KVM_GETARGV (kd, &kp[i], argc)) == NULL || ! *argv)
233 continue;
234
235 if (strcmp (*argv, exec) != 0)
236 continue;
237 }
238
239 pids = realloc (pids, sizeof (pid_t) * (npids + 2));
240 if (! pids)
241 eerrorx ("memory exhausted");
242
243 pids[npids] = p;
244 pids[npids + 1] = 0;
245 npids++;
246 }
247 kvm_close(kd);
248
249 return (pids);
250 }
251
252 #else
253 # error "Platform not supported!"
254 #endif
255
256 static bool _match_daemon (const char *path, const char *file,
257 const char *mexec, const char *mname,
258 const char *mpidfile)
259 {
260 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
266 if (! rc_exists (ffile)) {
267 free (ffile);
268 return (false);
269 }
270
271 if ((fp = fopen (ffile, "r")) == NULL) {
272 eerror ("fopen `%s': %s", ffile, strerror (errno));
273 free (ffile);
274 return (false);
275 }
276
277 if (! mname)
278 m += 10;
279 if (! mpidfile)
280 m += 100;
281
282 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
288 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
295 if (m == 111)
296 break;
297
298 lc++;
299 if (lc > 5)
300 break;
301 }
302 fclose (fp);
303 free (ffile);
304
305 return (m == 111 ? true : false);
306 }
307
308 void rc_set_service_daemon (const char *service, const char *exec,
309 const char *name, const char *pidfile,
310 bool started)
311 {
312 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
323 if (! exec && ! name && ! pidfile)
324 return;
325
326 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
333 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
340 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
347 /* 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
355 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
372 /* Now store our daemon info */
373 if (started) {
374 char buffer[10];
375 FILE *fp;
376
377 if (! rc_is_dir (dirpath))
378 if (mkdir (dirpath, 0755) != 0)
379 eerror ("mkdir `%s': %s", dirpath, strerror (errno));
380
381 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
392 free (mexec);
393 free (mname);
394 free (mpidfile);
395 free (dirpath);
396 }
397
398 bool rc_service_started_daemon (const char *service, const char *exec,
399 int indx)
400 {
401 char *dirpath;
402 char *file;
403 int i;
404 char *mexec;
405 bool retval = false;
406
407 if (! service || ! exec)
408 return (false);
409
410 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
417 i = strlen (exec) + 6;
418 mexec = rc_xmalloc (sizeof (char *) * i);
419 snprintf (mexec, i, "exec=%s", exec);
420
421 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
437 free (mexec);
438 return (retval);
439 }
440
441 bool rc_service_daemons_crashed (const char *service)
442 {
443 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
459 if (! service)
460 return (false);
461
462 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
469 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
480 while ((fgets (buffer, RC_LINEBUFFER, fp))) {
481 int lb = strlen (buffer) - 1;
482 if (buffer[lb] == '\n')
483 buffer[lb] = 0;
484
485 p = buffer;
486 if ((token = strsep (&p, "=")) == NULL || ! p)
487 continue;
488
489 if (strlen (p) == 0)
490 continue;
491
492 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
508 pid = 0;
509 if (pidfile) {
510 if (! rc_exists (pidfile)) {
511 retval = true;
512 break;
513 }
514
515 if ((fp = fopen (pidfile, "r")) == NULL) {
516 eerror ("fopen `%s': %s", pidfile, strerror (errno));
517 retval = true;
518 break;
519 }
520
521 if (fscanf (fp, "%d", &pid) != 1) {
522 eerror ("no pid found in `%s'", pidfile);
523 fclose (fp);
524 retval = true;
525 break;
526 }
527
528 fclose (fp);
529 free (pidfile);
530 pidfile = NULL;
531 }
532
533 if ((pids = rc_find_pids (exec, name, 0, pid)) == NULL) {
534 retval = true;
535 break;
536 }
537 free (pids);
538
539 if (exec) {
540 free (exec);
541 exec = NULL;
542 }
543 if (name) {
544 free (name);
545 name = NULL;
546 }
547 }
548
549 if (exec) {
550 free (exec);
551 exec = NULL;
552 }
553 if (name) {
554 free (name);
555 name = NULL;
556 }
557
558 free (dirpath);
559 rc_strlist_free (files);
560
561 return (retval);
562 }

  ViewVC Help
Powered by ViewVC 1.1.20