fix tricky regression noticed by Vyacheslav Tokarev on Google Reader.
[kdelibs.git] / kinit / proctitle.cpp
blobca3a7da3a845ce2f9798e9b1769f8d183f372363
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>
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.
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.
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
22 #include "proctitle.h"
23 #include <config.h>
24 #include <config-kdeinit.h>
26 #include <string.h>
27 #include <stdio.h>
28 #include <stdarg.h>
29 #include <stdlib.h>
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
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 */
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
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 */
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 */
67 # endif /* !__GNU_HURD__ */
69 #endif /* !HAVE_SETPROCTITLE */
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;
79 static char **Argv = NULL;
81 #if PF_ARGV_TYPE == PF_ARGV_WRITEABLE /* Only this mode uses LastArgv */
82 static char *LastArgv = NULL;
83 #endif
85 /**
86 * Set up the memory space for setting the proctitle
88 void proctitle_init(int argc, char *argv[], char *envp[]) {
89 register int i, envpsize;
90 char **p;
92 /* Move the environment so proctitle_set can use the space. */
93 for ( i = envpsize = 0; envp[i] != NULL; i++ ) {
94 envpsize += strlen(envp[i]) + 1;
97 if ((p = (char **) malloc((i + 1) * sizeof(char *))) != NULL) {
98 environ = p;
100 for (i = 0; envp[i] != NULL; i++) {
101 if ((environ[i] = static_cast<char *>(malloc(strlen(envp[i]) + 1))) != NULL) {
102 strcpy(environ[i], envp[i]);
106 environ[i] = NULL;
109 Argv = argv;
111 # if PF_ARGV_TYPE == PF_ARGV_WRITEABLE /* Only this mode uses LastArgv */
112 for (i = 0; i < argc; i++) {
113 if (!i || (LastArgv + 1 == argv[i])) {
114 LastArgv = argv[i] + strlen(argv[i]);
118 for (i = 0; envp[i] != NULL; i++) {
119 /* must not overwrite XDG_SESSION_COOKIE */
120 if (!strncmp(envp[i], "XDG_", 4))
121 break;
122 if ((LastArgv + 1) == envp[i]) {
123 LastArgv = envp[i] + strlen(envp[i]);
126 #endif
128 # ifdef HAVE___PROGNAME
129 /* Set the __progname variable so glibc and company
130 * don't go nuts.
132 __progname = strdup("kdeinit4");
133 # endif /* HAVE___PROGNAME */
134 # ifdef HAVE____PROGNAME_FULL
135 /* __progname_full too */
136 __progname_full = strdup(argv[0]);
137 # endif /* HAVE___PROGNAME_FULL */
140 void proctitle_set(const char *fmt, ...) {
141 va_list msg;
142 static char statbuf[BUFSIZ];
144 #ifndef HAVE_SETPROCTITLE
145 # if PF_ARGV_TYPE == PF_ARGV_PSTAT
146 union pstun pst;
147 # endif /* PF_ARGV_PSTAT */
148 char *p;
149 int i;
150 #endif /* HAVE_SETPROCTITLE */
152 if ( !fmt ) {
153 return;
156 va_start(msg, fmt);
158 memset(statbuf, 0, sizeof(statbuf));
160 #ifdef HAVE_SETPROCTITLE
161 # if __FreeBSD__ >= 4 && !defined(FREEBSD4_0) && !defined(FREEBSD4_1)
162 /* FreeBSD's setproctitle() automatically prepends the process name. */
163 vsnprintf(statbuf, sizeof(statbuf), fmt, msg);
165 # else /* FREEBSD4 */
166 /* Manually append the process name for non-FreeBSD platforms. */
167 snprintf(statbuf, sizeof(statbuf), "%s", "kdeinit4: ");
168 vsnprintf(statbuf + strlen(statbuf),
169 sizeof(statbuf) - strlen(statbuf),
170 fmt,
171 msg);
173 # endif /* FREEBSD4 */
174 setproctitle("%s", statbuf);
176 #else /* HAVE_SETPROCTITLE */
177 /* Manually append the process name for non-setproctitle() platforms. */
178 snprintf(statbuf, sizeof(statbuf), "%s", "kdeinit4: ");
179 vsnprintf(statbuf + strlen(statbuf),
180 sizeof(statbuf) - strlen(statbuf),
181 fmt,
182 msg);
184 #endif /* HAVE_SETPROCTITLE */
186 va_end(msg);
188 #ifdef HAVE_SETPROCTITLE
189 return;
190 #else
191 i = strlen(statbuf);
193 # if PF_ARGV_TYPE == PF_ARGV_NEW
194 /* We can just replace argv[] arguments. Nice and easy. */
195 Argv[0] = statbuf;
196 Argv[1] = NULL;
197 # endif /* PF_ARGV_NEW */
199 # if PF_ARGV_TYPE == PF_ARGV_WRITEABLE
200 const int maxlen = (LastArgv - Argv[0]) - 1;
201 /* We can overwrite individual argv[] arguments. Semi-nice. */
202 snprintf(Argv[0], maxlen, "%s", statbuf);
203 p = &Argv[0][i];
205 /* null terminate it, but don't clear the rest of the
206 memory that is usually used for environment variables. Some
207 tools, like ConsoleKit must have access to the process'es initial
208 environment (more exact, the XDG_SESSION_COOKIE variable stored there).
209 If this code causes another side effect, we have to specifically
210 always append those variables to our environment. */
212 if (p < LastArgv)
213 *p = '\0';
215 Argv[1] = NULL;
216 # endif /* PF_ARGV_WRITEABLE */
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 */
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 */
228 #endif /* HAVE_SETPROCTITLE */