]> git.saurik.com Git - wxWidgets.git/blame - src/unix/utilsunx.cpp
Another solaris 2.5 fix.
[wxWidgets.git] / src / unix / utilsunx.cpp
CommitLineData
518b5d2f
VZ
1/////////////////////////////////////////////////////////////////////////////
2// Name: utilsunx.cpp
3// Purpose: generic Unix implementation of many wx functions
4// Author: Vadim Zeitlin
5// Id: $Id$
6// Copyright: (c) 1998 Robert Roebling, Vadim Zeitlin
7// Licence: wxWindows licence
8/////////////////////////////////////////////////////////////////////////////
9
10// ============================================================================
11// declarations
12// ============================================================================
13
14// ----------------------------------------------------------------------------
15// headers
16// ----------------------------------------------------------------------------
17
18#include "wx/defs.h"
19#include "wx/string.h"
20
21#include "wx/intl.h"
22#include "wx/log.h"
23
24#include "wx/utils.h"
25#include "wx/process.h"
26
27#include "wx/unix/execute.h"
28
29#include <stdarg.h>
30#include <dirent.h>
31#include <string.h>
32#include <sys/stat.h>
33#include <sys/types.h>
34#include <unistd.h>
35#include <sys/wait.h>
36#include <pwd.h>
37#include <errno.h>
38#include <netdb.h>
39#include <signal.h>
40#include <fcntl.h> // for O_WRONLY and friends
41#include <time.h> // nanosleep() and/or usleep()
42
43#ifdef HAVE_UNAME
44 #include <sys/utsname.h> // for uname()
45#endif // HAVE_UNAME
46
47// ----------------------------------------------------------------------------
48// conditional compilation
49// ----------------------------------------------------------------------------
50
51// many versions of Unices have this function, but it is not defined in system
52// headers - please add your system here if it is the case for your OS.
53// SunOS < 5.6 (i.e. Solaris < 2.6) and DG-UX are like this.
54#if (defined(__SUN__) && !defined(__SunOs_5_6) && \
55 !defined(__SunOs_5_7) && !defined(__SUNPRO_CC)) || \
56 defined(__osf__)
57 extern "C"
58 {
59 void usleep(unsigned long usec);
60 };
61#endif // Unices without usleep()
62
63// many versions of Unices have this function, but it is not defined in system
64// headers - please add your system here if it is the case for your OS.
65// SunOS (and Solaris) and DG-UX are like this.
66#if defined(__SOLARIS__) || defined(__osf__)
67 extern "C"
68 {
69 pid_t wait4(pid_t pid, int *statusp, int options,
70 struct rusage *rusage);
71 }
72
73 #define wxWait4(pid, stat, flags, rusage) wait4(pid, stat, flags, rusage)
74#elif defined(__sgi) || defined(__HPUX__)
75 // no wait4() at all on these systems
76 // TODO verify whether wait3() really works in this situation
77 #define wxWait4(pid, stat, flags, rusage) wait3(stat, flags, rusage)
78#else
79 // other Unices: assume have wait4(), although it's not standard (but
80 // Linux and FreeBSD do have it)
81 #define wxWait4(pid, stat, flags, rusage) wait4(pid, stat, flags, rusage)
82#endif // wait4()
83
84// ============================================================================
85// implementation
86// ============================================================================
87
88// ----------------------------------------------------------------------------
89// sleeping
90// ----------------------------------------------------------------------------
91
92void wxSleep(int nSecs)
93{
94 sleep(nSecs);
95}
96
97void wxUsleep(unsigned long milliseconds)
98{
99#if defined(HAVE_NANOSLEEP)
100 timespec tmReq;
101 tmReq.tv_sec = milliseconds / 1000;
102 tmReq.tv_nsec = (milliseconds % 1000) * 1000 * 1000;
103
104 // we're not interested in remaining time nor in return value
105 (void)nanosleep(&tmReq, (timespec *)NULL);
106#elif defined(HAVE_USLEEP)
107 // uncomment this if you feel brave or if you are sure that your version
108 // of Solaris has a safe usleep() function but please notice that usleep()
109 // is known to lead to crashes in MT programs in Solaris 2.[67] and is not
110 // documented as MT-Safe
111 #if defined(__SUN__) && defined(wxUSE_THREADS)
112 #error "usleep() cannot be used in MT programs under Solaris."
113 #endif // Sun
114
115 usleep(milliseconds * 1000); // usleep(3) wants microseconds
116#else // !sleep function
117 #error "usleep() or nanosleep() function required for wxUsleep"
118#endif // sleep function
119}
120
121// ----------------------------------------------------------------------------
122// process management
123// ----------------------------------------------------------------------------
124
125int wxKill(long pid, int sig)
126{
127 return kill(pid, sig);
128}
129
130long wxExecute( const wxString& command, bool sync, wxProcess *process )
131{
132 static const char *IFS = " \t\n";
133
134 wxCHECK_MSG( !command.IsEmpty(), 0, "can't exec empty command" );
135
136 int argc = 0;
137 char *argv[127];
138 char *tmp = new char[command.Len() + 1];
139 strcpy(tmp, command);
140
141 argv[argc++] = strtok(tmp, IFS);
142 while ((argv[argc++] = strtok((char *) NULL, IFS)) != NULL)
143 /* loop */ ;
144
145 long lRc = wxExecute(argv, sync, process);
146
147 delete [] tmp;
148
149 return lRc;
150}
151
152bool wxShell(const wxString& command)
153{
154 wxString cmd;
155 if ( !!command )
156 cmd.Printf("xterm -e %s", command.c_str());
157 else
158 cmd = command;
159
160 return wxExecute(cmd) != 0;
161}
162
163void wxHandleProcessTermination(wxEndProcessData *proc_data)
164{
165 int pid = (proc_data->pid > 0) ? proc_data->pid : -(proc_data->pid);
166
167 int status = 0;
168 wxWait4(pid, &status, 0, (rusage *) NULL);
169
170 if (proc_data->process)
171 proc_data->process->OnTerminate(proc_data->pid, status);
172
173 if (proc_data->pid > 0)
174 {
175 delete proc_data;
176 }
177 else
178 {
179 // wxExecute() will know about it
180 proc_data->exitcode = status;
181
182 proc_data->pid = 0;
183 }
184}
185
186long wxExecute( char **argv, bool sync, wxProcess *process )
187{
188 wxCHECK_MSG( *argv, 0, "can't exec empty command" );
189
190 int end_proc_detect[2];
191
192 // create pipes
193 if (pipe(end_proc_detect) == -1)
194 {
195 wxLogSysError( _("Pipe creation failed") );
196 return 0;
197 }
198
199 // fork the process
200#ifdef HAVE_VFORK
201 pid_t pid = vfork();
202#else
203 pid_t pid = fork();
204#endif
205 if (pid == -1)
206 {
207 wxLogSysError( _("Fork failed") );
208 return 0;
209 }
210 else if (pid == 0)
211 {
212 // we're in child
213 close(end_proc_detect[0]); // close reading side
214
215 // These three lines close the open file descriptors to to avoid any
216 // input/output which might block the process or irritate the user. If
217 // one wants proper IO for the subprocess, the "right thing to do is
218 // to start an xterm executing it.
219 if (sync == 0)
220 {
221 // leave stderr opened, it won't do any hurm
222 for ( int fd = 0; fd < FD_SETSIZE; fd++ )
223 {
224 if ( fd != end_proc_detect[1] && fd != STDERR_FILENO )
225 close(fd);
226 }
227 }
228
229#if 0
230 close(STDERR_FILENO);
231
232 // some programs complain about stderr not being open, so redirect
233 // them:
234 open("/dev/null", O_RDONLY); // stdin
235 open("/dev/null", O_WRONLY); // stdout
236 open("/dev/null", O_WRONLY); // stderr
237#endif
238
239#ifdef _AIX
240 execvp ((const char *)*argv, (const char **)argv);
241#else
242 execvp (*argv, argv);
243#endif
244
245 // there is no return after successful exec()
246 fprintf(stderr, _("Can't execute '%s'\n"), *argv);
247
248 _exit(-1);
249 }
250 else
251 {
252 // we're in parent
253 close(end_proc_detect[1]); // close writing side
254
255 wxEndProcessData *data = new wxEndProcessData;
256 data->tag = wxAddProcessCallback(data, end_proc_detect[0]);
257
258 if ( sync )
259 {
260 wxASSERT_MSG( !process, "wxProcess param ignored for sync exec" );
261 data->process = NULL;
262
263 // sync execution: indicate it by negating the pid
264 data->pid = -pid;
265
266 // it will be set to 0 from GTK_EndProcessDetector
267 while (data->pid != 0)
268 wxYield();
269
270 int exitcode = data->exitcode;
271
272 delete data;
273
274 return exitcode;
275 }
276 else
277 {
278 // async execution, nothing special to do - caller will be
279 // notified about the process terminationif process != NULL, data
280 // will be deleted in GTK_EndProcessDetector
281 data->process = process;
282 data->pid = pid;
283
284 return pid;
285 }
286 }
287}
288
289// ----------------------------------------------------------------------------
290// file and directory functions
291// ----------------------------------------------------------------------------
292
293const char* wxGetHomeDir( wxString *home )
294{
295 *home = wxGetUserHome( wxString() );
296 if ( home->IsEmpty() )
297 *home = "/";
298
299 return home->c_str();
300}
301
302char *wxGetUserHome( const wxString &user )
303{
304 struct passwd *who = (struct passwd *) NULL;
305
306 if (user.IsNull() || (user== ""))
307 {
308 register char *ptr;
309
310 if ((ptr = getenv("HOME")) != NULL)
311 {
312 return ptr;
313 }
314 if ((ptr = getenv("USER")) != NULL || (ptr = getenv("LOGNAME")) != NULL)
315 {
316 who = getpwnam(ptr);
317 }
318
319 // We now make sure the the user exists!
320 if (who == NULL)
321 {
322 who = getpwuid(getuid());
323 }
324 }
325 else
326 {
327 who = getpwnam (user);
328 }
329
330 return who ? who->pw_dir : (char*)NULL;
331}
332
333// ----------------------------------------------------------------------------
334// id routines
335// ----------------------------------------------------------------------------
336
337bool wxGetHostName(char *buf, int sz)
338{
339 wxCHECK_MSG( buf, FALSE, "NULL pointer in wxGetHostName" );
340
341 *buf = '\0';
342
343 // we're using uname() which is POSIX instead of less standard sysinfo()
344#if defined(HAVE_UNAME)
cc743a6f 345 struct utsname uts;
518b5d2f
VZ
346 bool ok = uname(&uts) != -1;
347 if ( ok )
348 {
349 strncpy(buf, uts.nodename, sz - 1);
350 buf[sz] = '\0';
351 }
352#elif defined(HAVE_GETHOSTNAME)
353 bool ok = gethostname(buf, sz) != -1;
354#else
355 wxFAIL_MSG("don't know host name for this machibe");
356
357 bool ok = FALSE;
358#endif
359
360 if ( !ok )
361 {
362 wxLogSysError(_("Cannot get the hostname"));
363 }
364
365 return ok;
366}
367
368bool wxGetUserId(char *buf, int sz)
369{
370 struct passwd *who;
371
372 *buf = '\0';
373 if ((who = getpwuid(getuid ())) != NULL)
374 {
375 strncpy (buf, who->pw_name, sz - 1);
376 return TRUE;
377 }
378
379 return FALSE;
380}
381
382bool wxGetUserName(char *buf, int sz)
383{
384 struct passwd *who;
385 char *comma;
386
387 *buf = '\0';
388 if ((who = getpwuid (getuid ())) != NULL) {
389 comma = strchr(who->pw_gecos, ',');
390 if (comma)
391 *comma = '\0'; // cut off non-name comment fields
392 strncpy (buf, who->pw_gecos, sz - 1);
393 return TRUE;
394 }
395
396 return FALSE;
397}
398
399// ----------------------------------------------------------------------------
400// error and debug output routines (deprecated, use wxLog)
401// ----------------------------------------------------------------------------
402
403void wxDebugMsg( const char *format, ... )
404{
405 va_list ap;
406 va_start( ap, format );
407 vfprintf( stderr, format, ap );
408 fflush( stderr );
409 va_end(ap);
410}
411
412void wxError( const wxString &msg, const wxString &title )
413{
414 fprintf( stderr, _("Error ") );
415 if (!title.IsNull()) fprintf( stderr, "%s ", WXSTRINGCAST(title) );
416 if (!msg.IsNull()) fprintf( stderr, ": %s", WXSTRINGCAST(msg) );
417 fprintf( stderr, ".\n" );
418}
419
420void wxFatalError( const wxString &msg, const wxString &title )
421{
422 fprintf( stderr, _("Error ") );
423 if (!title.IsNull()) fprintf( stderr, "%s ", WXSTRINGCAST(title) );
424 if (!msg.IsNull()) fprintf( stderr, ": %s", WXSTRINGCAST(msg) );
425 fprintf( stderr, ".\n" );
426 exit(3); // the same exit code as for abort()
427}
428
429//------------------------------------------------------------------------
430// directory routines
431//------------------------------------------------------------------------
432
433bool wxDirExists( const wxString& dir )
434{
435 char buf[500];
436 strcpy( buf, WXSTRINGCAST(dir) );
437 struct stat sbuf;
438 return ((stat(buf, &sbuf) != -1) && S_ISDIR(sbuf.st_mode) ? TRUE : FALSE);
439}