1 | /* |
---|
2 | * ---------------------------------------------------------------------- |
---|
3 | * Rappture::daemon |
---|
4 | * |
---|
5 | * Programs call this to dissociate themselves from their parents, |
---|
6 | * so they can continue to run in the background as a daemon process. |
---|
7 | * ====================================================================== |
---|
8 | * AUTHOR: Michael McLennan, Purdue University |
---|
9 | * Copyright (c) 2004-2007 Purdue Research Foundation |
---|
10 | * |
---|
11 | * See the file "license.terms" for information on usage and |
---|
12 | * redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES. |
---|
13 | * ====================================================================== |
---|
14 | */ |
---|
15 | #include <tcl.h> |
---|
16 | #include <unistd.h> |
---|
17 | #include <sys/types.h> |
---|
18 | #include <sys/stat.h> |
---|
19 | #include <fcntl.h> |
---|
20 | #include <errno.h> |
---|
21 | #include <assert.h> |
---|
22 | |
---|
23 | static int RpDaemonCmd _ANSI_ARGS_((ClientData cdata, |
---|
24 | Tcl_Interp *interp, int argc, CONST84 char *argv[])); |
---|
25 | |
---|
26 | /* |
---|
27 | * ------------------------------------------------------------------------ |
---|
28 | * RpDaemon_Init() |
---|
29 | * |
---|
30 | * Called in Rappture_Init() to initialize the commands defined |
---|
31 | * in this file. |
---|
32 | * ------------------------------------------------------------------------ |
---|
33 | */ |
---|
34 | int |
---|
35 | RpDaemon_Init(interp) |
---|
36 | Tcl_Interp *interp; /* interpreter being initialized */ |
---|
37 | { |
---|
38 | /* install the daemon command */ |
---|
39 | Tcl_CreateCommand(interp, "::Rappture::daemon", RpDaemonCmd, |
---|
40 | (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL); |
---|
41 | |
---|
42 | return TCL_OK; |
---|
43 | } |
---|
44 | |
---|
45 | /* |
---|
46 | * ------------------------------------------------------------------------ |
---|
47 | * RpDaemonCmd() |
---|
48 | * |
---|
49 | * Invoked whenever someone uses the "daemon" command to fork |
---|
50 | * and dissociate this process from its parent. Handles the |
---|
51 | * following syntax: |
---|
52 | * |
---|
53 | * daemon |
---|
54 | * |
---|
55 | * Returns TCL_OK on success, and TCL_ERROR (along with an error |
---|
56 | * message in the interpreter) if anything goes wrong. |
---|
57 | * |
---|
58 | * For details, see W. Richard Stevens, "Advanced Programming in |
---|
59 | * the Unix Environment," p. 418, Addison Wesley, 1992. |
---|
60 | * ------------------------------------------------------------------------ |
---|
61 | */ |
---|
62 | static int |
---|
63 | RpDaemonCmd(cdata, interp, argc, argv) |
---|
64 | ClientData cdata; /* not used */ |
---|
65 | Tcl_Interp *interp; /* interpreter handling this request */ |
---|
66 | int argc; /* number of command line args */ |
---|
67 | CONST84 char *argv[]; /* strings for command line args */ |
---|
68 | { |
---|
69 | pid_t pid; |
---|
70 | int result; |
---|
71 | |
---|
72 | pid = fork(); |
---|
73 | if (pid < 0) { |
---|
74 | Tcl_AppendResult(interp, "can't fork daemon", (char*)NULL); |
---|
75 | if (errno == EAGAIN) { |
---|
76 | Tcl_AppendResult(interp, ": resource limit", |
---|
77 | (char*)NULL); |
---|
78 | } else if (errno == ENOMEM) { |
---|
79 | Tcl_AppendResult(interp, ": out of memory", |
---|
80 | (char*)NULL); |
---|
81 | } |
---|
82 | return TCL_ERROR; |
---|
83 | } |
---|
84 | else if (pid != 0) { |
---|
85 | Tcl_Exit(0); /* parent exits here */ |
---|
86 | } |
---|
87 | |
---|
88 | /* child continues... */ |
---|
89 | setsid(); /* become session leader */ |
---|
90 | result = chdir("/"); /* root never goes away, so sit here */ |
---|
91 | assert(result == 0); |
---|
92 | /* close at least this much, so pipes in exec'ing process get closed */ |
---|
93 | Tcl_UnregisterChannel(interp, Tcl_GetStdChannel(TCL_STDIN)); |
---|
94 | Tcl_UnregisterChannel(interp, Tcl_GetStdChannel(TCL_STDOUT)); |
---|
95 | Tcl_UnregisterChannel(interp, Tcl_GetStdChannel(TCL_STDERR)); |
---|
96 | |
---|
97 | /* make sure that these are really closed */ |
---|
98 | close(0); |
---|
99 | close(1); |
---|
100 | close(2); |
---|
101 | |
---|
102 | Tcl_ResetResult(interp); /* in case there was an error above */ |
---|
103 | return TCL_OK; |
---|
104 | } |
---|