1 | /* |
2 | * ProFTPD - FTP server daemon |
3 | * Copyright (c) 2007 The ProFTPD Project team //krazy:exclude=copyright |
4 | * Copyright (c) 2007 Alex Merry <alex.merry@kdemail.net> |
5 | * |
6 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by |
8 | * the Free Software Foundation; either version 2 of the License, or |
9 | * (at your option) any later version. |
10 | * |
11 | * This program is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | * GNU General Public License for more details. |
15 | * |
16 | * You should have received a copy of the GNU General Public License |
17 | * along with this program; if not, write to the |
18 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
19 | * Boston, MA 02110-1301 USA |
20 | */ |
21 | |
22 | #include "proctitle.h" |
23 | #include <config.h> |
24 | #include <config-kdeinit.h> |
25 | |
26 | #include <string.h> |
27 | #include <stdio.h> |
28 | #include <stdarg.h> |
29 | #include <stdlib.h> |
30 | |
31 | #define PF_ARGV_NONE 0 |
32 | #define PF_ARGV_NEW 1 |
33 | #define PF_ARGV_WRITEABLE 2 |
34 | #define PF_ARGV_PSTAT 3 |
35 | #define PF_ARGV_PSSTRINGS 4 |
36 | |
37 | #ifdef HAVE_SETPROCTITLE |
38 | # define PF_ARGV_TYPE PF_ARGV_NONE |
39 | # ifdef HAVE_SYS_TYPES_H |
40 | # include <sys/types.h> |
41 | # endif /* HAVE_SYS_TYPES_H */ |
42 | # ifdef HAVE_UNISTD_H |
43 | # include <unistd.h> |
44 | # endif /* HAVE_UNISTD_H */ |
45 | |
46 | #else /* HAVE_SETPROCTITLE */ |
47 | # ifdef __GNU_HURD__ |
48 | # define PF_ARGV_TYPE PF_ARGV_NEW |
49 | # else /* __GNU_HURD__ */ |
50 | # define PF_ARGV_TYPE PF_ARGV_WRITEABLE |
51 | |
52 | # if defined(HAVE_SYS_PSTAT_H) && defined(HAVE_PSTAT) |
53 | # include <sys/pstat.h> |
54 | # undef PF_ARGV_TYPE |
55 | # define PF_ARGV_TYPE PF_ARGV_PSTAT |
56 | # endif /* HAVE_SYS_PSTAT_H && HAVE_PSTAT */ |
57 | |
58 | # ifdef HAVE_SYS_EXEC_H |
59 | # include <sys/exec.h> |
60 | # ifdef PS_STRINGS |
61 | # include <machine/vmparam.h> |
62 | # undef PF_ARGV_TYPE |
63 | # define PF_ARGV_TYPE PF_ARGV_PSSTRINGS |
64 | # endif /* PS_STRINGS */ |
65 | # endif /* HAVE_SYS_EXEC_H */ |
66 | |
67 | # endif /* !__GNU_HURD__ */ |
68 | |
69 | #endif /* !HAVE_SETPROCTITLE */ |
70 | |
71 | #ifdef HAVE___PROGNAME |
72 | extern char *__progname; |
73 | #endif /* HAVE___PROGNAME */ |
74 | #ifdef HAVE___PROGNAME_FULL |
75 | extern char *__progname_full; |
76 | #endif /* HAVE___PROGNAME_FULL */ |
77 | extern char **environ; |
78 | |
79 | static char **Argv = NULL; |
80 | |
81 | #if PF_ARGV_TYPE == PF_ARGV_WRITEABLE /* Only this mode uses LastArgv */ |
82 | static char *LastArgv = NULL; |
83 | static char *cleanUpTo = NULL; |
84 | #endif |
85 | |
86 | /** |
87 | * Set up the memory space for setting the proctitle |
88 | */ |
89 | void proctitle_init(int argc, char *argv[], char *envp[]) { |
90 | register int i, envpsize; |
91 | char **p; |
92 | |
93 | /* Move the environment so proctitle_set can use the space. */ |
94 | for ( i = envpsize = 0; envp[i] != NULL; i++ ) { |
95 | envpsize += strlen(envp[i]) + 1; |
96 | } |
97 | |
98 | if ((p = (char **) malloc((i + 1) * sizeof(char *))) != NULL) { |
99 | environ = p; |
100 | |
101 | for (i = 0; envp[i] != NULL; i++) { |
102 | if ((environ[i] = static_cast<char *>(malloc(strlen(envp[i]) + 1))) != NULL) { |
103 | strcpy(environ[i], envp[i]); |
104 | } |
105 | } |
106 | |
107 | environ[i] = NULL; |
108 | } |
109 | |
110 | Argv = argv; |
111 | |
112 | # if PF_ARGV_TYPE == PF_ARGV_WRITEABLE /* Only this mode uses LastArgv */ |
113 | for (i = 0; i < argc; i++) { |
114 | if (!i || (LastArgv + 1 == argv[i])) { |
115 | LastArgv = argv[i] + strlen(argv[i]); |
116 | } |
117 | } |
118 | cleanUpTo = LastArgv; |
119 | |
120 | for (i = 0; envp[i] != NULL; i++) { |
121 | /* must not overwrite XDG_SESSION_COOKIE */ |
122 | if (!strncmp(envp[i], "XDG_" , 4)) |
123 | break; |
124 | if ((LastArgv + 1) == envp[i]) { |
125 | LastArgv = envp[i] + strlen(envp[i]); |
126 | } |
127 | } |
128 | #endif |
129 | |
130 | # ifdef HAVE___PROGNAME |
131 | /* Set the __progname variable so glibc and company |
132 | * don't go nuts. |
133 | */ |
134 | __progname = strdup("kdeinit4" ); |
135 | # endif /* HAVE___PROGNAME */ |
136 | # ifdef HAVE___PROGNAME_FULL |
137 | /* __progname_full too */ |
138 | __progname_full = strdup(argv[0]); |
139 | # endif /* HAVE___PROGNAME_FULL */ |
140 | } |
141 | |
142 | void proctitle_set(const char *fmt, ...) { |
143 | va_list msg; |
144 | static char statbuf[BUFSIZ]; |
145 | |
146 | #ifndef HAVE_SETPROCTITLE |
147 | # if PF_ARGV_TYPE == PF_ARGV_PSTAT |
148 | union pstun pst; |
149 | # endif /* PF_ARGV_PSTAT */ |
150 | char *p; |
151 | int i; |
152 | #endif /* HAVE_SETPROCTITLE */ |
153 | |
154 | if ( !fmt ) { |
155 | return; |
156 | } |
157 | |
158 | va_start(msg, fmt); |
159 | |
160 | memset(statbuf, 0, sizeof(statbuf)); |
161 | |
162 | #ifdef HAVE_SETPROCTITLE |
163 | # if __FreeBSD__ >= 4 && !defined(FREEBSD4_0) && !defined(FREEBSD4_1) |
164 | /* FreeBSD's setproctitle() automatically prepends the process name. */ |
165 | vsnprintf(statbuf, sizeof(statbuf), fmt, msg); |
166 | |
167 | # else /* FREEBSD4 */ |
168 | /* Manually append the process name for non-FreeBSD platforms. */ |
169 | snprintf(statbuf, sizeof(statbuf), "%s" , "kdeinit4: " ); |
170 | vsnprintf(statbuf + strlen(statbuf), |
171 | sizeof(statbuf) - strlen(statbuf), |
172 | fmt, |
173 | msg); |
174 | |
175 | # endif /* FREEBSD4 */ |
176 | setproctitle("%s" , statbuf); |
177 | |
178 | #else /* HAVE_SETPROCTITLE */ |
179 | /* Manually append the process name for non-setproctitle() platforms. */ |
180 | snprintf(statbuf, sizeof(statbuf), "%s" , "kdeinit4: " ); |
181 | vsnprintf(statbuf + strlen(statbuf), |
182 | sizeof(statbuf) - strlen(statbuf), |
183 | fmt, |
184 | msg); |
185 | |
186 | #endif /* HAVE_SETPROCTITLE */ |
187 | |
188 | va_end(msg); |
189 | |
190 | #ifdef HAVE_SETPROCTITLE |
191 | return; |
192 | #else |
193 | i = strlen(statbuf); |
194 | |
195 | # if PF_ARGV_TYPE == PF_ARGV_NEW |
196 | /* We can just replace argv[] arguments. Nice and easy. */ |
197 | Argv[0] = statbuf; |
198 | Argv[1] = NULL; |
199 | # endif /* PF_ARGV_NEW */ |
200 | |
201 | # if PF_ARGV_TYPE == PF_ARGV_WRITEABLE |
202 | const int maxlen = (LastArgv - Argv[0]) - 1; |
203 | /* We can overwrite individual argv[] arguments. Semi-nice. */ |
204 | snprintf(Argv[0], maxlen, "%s" , statbuf); |
205 | p = &Argv[0][i]; |
206 | /* Clear the rest used by arguments, but don't clear the memory |
207 | that is usually used for environment variables. Some |
208 | tools, like ConsoleKit must have access to the process'es initial |
209 | environment (more exact, the XDG_SESSION_COOKIE variable stored there). |
210 | If this code causes another side effect, we have to specifically |
211 | always append those variables to our environment. */ |
212 | while (p < cleanUpTo) |
213 | *p++ = '\0'; |
214 | |
215 | Argv[1] = NULL; |
216 | # endif /* PF_ARGV_WRITEABLE */ |
217 | |
218 | # if PF_ARGV_TYPE == PF_ARGV_PSTAT |
219 | pst.pst_command = statbuf; |
220 | pstat(PSTAT_SETCMD, pst, i, 0, 0); |
221 | # endif /* PF_ARGV_PSTAT */ |
222 | |
223 | # if PF_ARGV_TYPE == PF_ARGV_PSSTRINGS |
224 | PS_STRINGS->ps_nargvstr = 1; |
225 | PS_STRINGS->ps_argvstr = statbuf; |
226 | # endif /* PF_ARGV_PSSTRINGS */ |
227 | |
228 | #endif /* HAVE_SETPROCTITLE */ |
229 | } |
230 | |