1 /**********************************************************************
2  * setproctitle.c                                              May 2001
3  * Horms                                             horms@verge.net.au
4  *
5  * The code in this file, setproctitle.c is heavily based on code from
6  * proftpd, please see the licensing information below.
7  *
8  * Code to portably change the title of a programme as displayed
9  * by ps(1).
10  *
11  * perdition
12  * Mail retrieval proxy server
13  * Copyright (C) 1999-2005  Horms
14  *
15  * This program is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU General Public License as
17  * published by the Free Software Foundation; either version 2 of the
18  * License, or (at your option) any later version.
19  *
20  * This program is distributed in the hope that it will be useful, but
21  * WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23  * General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with this program; if not, write to the Free Software Foundation,
27  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
28  *
29  **********************************************************************/
30 
31 /*
32  * ProFTPD - FTP server daemon
33  * Copyright (c) 1997, 1998 Public Flood Software
34  * Copyright (C) 1999, 2000 MacGyver aka Habeeb J. Dihu <macgyver@tos.net>
35  *
36  * This program is free software; you can redistribute it and/or modify
37  * it under the terms of the GNU General Public License as published by
38  * the Free Software Foundation; either version 2 of the License, or
39  * (at your option) any later version.
40  *
41  * This program is distributed in the hope that it will be useful,
42  * but WITHOUT ANY WARRANTY; without even the implied warranty of
43  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
44  * GNU General Public License for more details.
45  *
46  * You should have received a copy of the GNU General Public License
47  * along with this program; if not, write to the Free Software Foundation,
48  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
49  *
50  * As a special exemption, Public Flood Software/MacGyver aka Habeeb J. Dihu
51  * and other respective copyright holders give permission to link this program
52  * with OpenSSL, and distribute the resulting executable, without including
53  * the source code for OpenSSL in the source distribution.
54  */
55 
56 #ifdef HAVE_CONFIG_H
57 #include "config.h"
58 #endif
59 
60 #include <stdlib.h>
61 #include <string.h>
62 #include <stdio.h>
63 #include <unistd.h>
64 #include <stdarg.h>
65 
66 #define PF_ARGV_NONE            0
67 #define PF_ARGV_NEW             1
68 #define PF_ARGV_WRITEABLE       2
69 #define PF_ARGV_PSTAT           3
70 #define PF_ARGV_PSSTRINGS       4
71 
72 #if PF_ARGV_TYPE == PF_ARGV_PSTAT
73 #	include <pstat.h>
74 #endif
75 
76 #include "setproctitle.h"
77 
78 static char **Argv = NULL;
79 static char *LastArgv = NULL;
80 extern char **environ;
81 
82 #ifdef HAVE___PROGNAME
83   extern char *__progname, *__progname_full;
84 #endif /* HAVE___PROGNAME */
85 
init_set_proc_title(int argc,char * argv[],char * envp[])86 void init_set_proc_title(int argc, char *argv[], char *envp[])
87 {
88   int i, envpsize;
89   char **p;
90 
91   /* Move the environment so setproctitle can use the space.
92    */
93   for(i = envpsize = 0; envp[i] != NULL; i++)
94     envpsize += strlen(envp[i]) + 1;
95 
96   if((p = (char **) malloc((i + 1) * sizeof(char *))) != NULL ) {
97     environ = p;
98 
99     for(i = 0; envp[i] != NULL; i++) {
100       if((environ[i] = malloc(strlen(envp[i]) + 1)) != NULL)
101 	strcpy(environ[i], envp[i]);
102     }
103 
104     environ[i] = NULL;
105   }
106 
107   Argv = argv;
108 
109   for(i = 0; i < argc; i++) {
110     if(!i || (LastArgv + 1 == argv[i]))
111       LastArgv = argv[i] + strlen(argv[i]);
112   }
113 
114   for(i = 0; envp[i] != NULL; i++) {
115     if((LastArgv + 1) == envp[i])
116       LastArgv = envp[i] + strlen(envp[i]);
117   }
118 
119 #ifdef HAVE___PROGNAME
120   /* Set the __progname and __progname_full variables so glibc and company don't
121    * go nuts. - MacGyver
122    */
123   __progname = strdup(get_progname(argv[0]));
124   __progname_full = strdup(argv[0]);
125 #endif /* HAVE___PROGNAME */
126 
127 #if 0
128   /* Save argument/environment globals for use by set_proc_title */
129 
130   Argv = argv;
131   while(*envp)
132     envp++;
133 
134   LastArgv = envp[-1] + strlen(envp[-1]);
135 #endif
136 }
137 
set_proc_title(const char * fmt,...)138 void set_proc_title(const char *fmt,...)
139 {
140   va_list msg;
141   static char statbuf[BUFSIZ];
142 
143 #ifndef HAVE_SETPROCTITLE
144 #if PF_ARGV_TYPE == PF_ARGV_PSTAT
145    union pstun pst;
146 #endif /* PF_ARGV_PSTAT */
147   int i;
148 #if PF_ARGV_TYPE == PF_ARGV_WRITEABLE
149   int maxlen = (LastArgv - Argv[0]) - 2;
150   char *p;
151 #endif
152 #endif /* HAVE_SETPROCTITLE */
153 
154   va_start(msg,fmt);
155 
156   memset(statbuf, 0, sizeof(statbuf));
157   vsnprintf(statbuf, sizeof(statbuf), fmt, msg);
158 
159 #ifdef HAVE_SETPROCTITLE
160   /* On systems with setproctitle(), v*printf are used on the arguments.
161    * Prevent any possible format attacks.
162    */
163   setproctitle("%s", statbuf);
164 #endif /* HAVE_SETPROCTITLE */
165 
166   va_end(msg);
167 
168 #ifdef HAVE_SETPROCTITLE
169   return;
170 #else
171   i = strlen(statbuf);
172 
173 #if PF_ARGV_TYPE == PF_ARGV_NEW
174   /* We can just replace argv[] arguments.  Nice and easy.
175    */
176   Argv[0] = statbuf;
177   Argv[1] = NULL;
178 #endif /* PF_ARGV_NEW */
179 
180 #if PF_ARGV_TYPE == PF_ARGV_WRITEABLE
181   /* We can overwrite individual argv[] arguments.  Semi-nice.
182    */
183   snprintf(Argv[0], maxlen, "%s", statbuf);
184   p = &Argv[0][i];
185 
186   while(p < LastArgv)
187     *p++ = '\0';
188   Argv[1] = NULL;
189 #endif /* PF_ARGV_WRITEABLE */
190 
191 #if PF_ARGV_TYPE == PF_ARGV_PSTAT
192   pst.pst_command = statbuf;
193   pstat(PSTAT_SETCMD, pst, i, 0, 0);
194 #endif /* PF_ARGV_PSTAT */
195 
196 #if PF_ARGV_TYPE == PF_ARGV_PSSTRINGS
197   PS_STRINGS->ps_nargvstr = 1;
198   PS_STRINGS->ps_argvstr = statbuf;
199 #endif /* PF_ARGV_PSSTRINGS */
200 
201 #endif /* HAVE_SETPROCTITLE */
202 }
203 
204 
205 const char *
get_progname(const char * argv_0)206 get_progname(const char *argv_0)
207 {
208 	const char *progname;
209 
210 	progname = strrchr(argv_0, '/');
211 	if (progname)
212 	   	return progname+1;
213 
214 	return argv_0;
215 }
216