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
72extern char *__progname;
73#endif /* HAVE___PROGNAME */
74#ifdef HAVE___PROGNAME_FULL
75extern char *__progname_full;
76#endif /* HAVE___PROGNAME_FULL */
77extern char **environ;
78
79static char **Argv = NULL;
80
81#if PF_ARGV_TYPE == PF_ARGV_WRITEABLE /* Only this mode uses LastArgv */
82static char *LastArgv = NULL;
83static char *cleanUpTo = NULL;
84#endif
85
86/**
87 * Set up the memory space for setting the proctitle
88 */
89void 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
142void 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