Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / lib / tt / lib / util / tt_port.C
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 //%%  (c) Copyright 1993, 1994 Hewlett-Packard Company                  
24 //%%  (c) Copyright 1993, 1994 International Business Machines Corp.    
25 //%%  (c) Copyright 1993, 1994 Sun Microsystems, Inc.                   
26 //%%  (c) Copyright 1993, 1994 Novell, Inc.                             
27 //%%  $TOG: tt_port.C /main/5 1999/10/14 19:02:43 mgreess $                                                     
28 /* @(#)tt_port.C        1.20 93/09/07
29  *
30  * tt_port.cc
31  *
32  * Routines for centralizing non-portable constructs.
33  *
34  * Copyright (c) 1992 by Sun Microsystems, Inc.
35  */
36
37 #include "tt_options.h"
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <sys/param.h>
41 #include <string.h>
42 #include <sys/time.h>
43 #include <sys/resource.h>
44 #include <unistd.h>
45 #include <stdlib.h>
46 #include <stdarg.h>
47 #include <syslog.h>
48 #if defined(OPT_BUG_HPUX) && !defined(hpV4)
49 extern "C" {
50         int syslog(int priority, const char *message, ...);
51         int openlog(const char *ident, int logopt, int facility);
52 }
53 #endif
54 #if defined(sun)
55 #include <sys/utsname.h>
56 #endif
57 #include <errno.h>
58 #include "tt_port.h"
59 #include "tt_global_env.h"
60 #include "tt_string.h"
61
62 #if defined(OPT_BUG_SUNOS_4)
63 #       if defined(__GNUG__)
64 #               define uname NotAnAnsiCPrototypeForUname
65 #               include <sys/utsname.h>
66 #               undef uname
67                 extern "C" { int uname( struct utsname * ); }
68 #       else
69 #               include <sysent.h>
70 #               include <sys/utsname.h>
71 #       endif
72 #else
73 #       include <sys/utsname.h>
74 #endif
75
76 #if defined(OPT_SYSINFO)
77 #       include <sys/systeminfo.h>
78 #else
79 #       include <stdlib.h>      // atol()
80 #endif
81
82 #if defined(OPT_BUG_SGI) || defined(OPT_BUG_AIX)
83         extern "C" {extern int getdtablesize(void);}
84 #endif
85
86
87 /*
88  * Get the name of the host.
89  */
90 _Tt_string
91 _tt_gethostname()
92 {
93         /*
94          * If for some reason we can't get a host name, use "localhost".
95          * This at least has a chance of doing the right thing, say on
96          * a non-networked machine, and so is more useful than just returning
97          * null or an error and having our callers bail out.
98          */
99
100         const char *default_hostname = "localhost";
101         _Tt_string result;
102
103 #if !defined(OPT_GETHOSTNAME)
104         struct utsname uts_name;
105         
106
107         if (uname(&uts_name) >= 0) {
108                 result = uts_name.nodename;
109         } else {
110                 result = default_hostname;
111         }
112 #else
113         // It's not completely clear to me whether or not MAXHOSTNAMELEN is
114         // supposed to have room for the null byte at the end.  Leave an
115         // extra byte just to be sure.
116         
117         char curhostname[MAXHOSTNAMELEN+1];
118         if (0==gethostname(curhostname, sizeof curhostname)) {
119                 result = curhostname;
120         } else {
121                 result = default_hostname;
122         }
123 #endif /* OPT_GETHOSTNAME */
124
125 #ifdef __osf__
126 // An environment variable will be created by /usr/dt/bin/Xsession if
127 // we have started the system without a network configured. This will
128 // be true during an initial system installation.
129
130     if (getenv("DTNONETWORK"))
131         result = default_hostname;
132 #endif
133
134         return result;
135 }
136
137 /*
138  * Get the number of currently possible file descriptors.
139  */
140 int
141 _tt_getdtablesize(void)
142 {
143 #if !defined(OPT_GETDTABLESIZE)
144         struct rlimit rl;
145         if (getrlimit(RLIMIT_NOFILE, &rl) == 0) {
146                 return (int)rl.rlim_cur;
147         } else {
148                 return 0;
149         }
150 #else
151         return getdtablesize();
152 #endif /* OPT_GETDTABLESIZE */
153 }
154
155
156 static struct rlimit original_dtablesize = { 0, 0 };
157 /*
158  * Maximize the number of possible file descriptors.
159  *
160  * Returns
161  *      0       Success
162  *      -1      Error (errno is set)
163  */
164 int
165 _tt_zoomdtablesize(void)
166 {
167 #if defined(_AIX)
168         return 1;
169 #else
170         struct rlimit rl;
171         if (getrlimit(RLIMIT_NOFILE, &rl) != 0) {
172                 return -1;
173         }
174         if (original_dtablesize.rlim_cur == 0) {
175                 original_dtablesize = rl;
176         }
177         if (rl.rlim_cur < rl.rlim_max) {
178                 rl.rlim_cur = rl.rlim_max;
179                 return setrlimit(RLIMIT_NOFILE, &rl);
180         }
181         return 0;
182 #endif
183 }
184
185 int
186 _tt_restoredtablesize(void)
187 {
188 #if defined(_AIX)
189         return 1;
190 #else
191         if (original_dtablesize.rlim_cur == 0) {
192                 return 0;
193         } else {
194                 return setrlimit(RLIMIT_NOFILE, &original_dtablesize);
195         }
196 #endif
197 }
198
199
200 long
201 _tt_gethostid(void)
202 {
203         long _hostid;
204 #if defined(OPT_SYSINFO)
205         {
206                 char            serial_num[40];
207
208                 if (sysinfo(SI_HW_SERIAL, serial_num, 40) > 0) {
209                         sscanf(serial_num, "%12lx", &_hostid);
210                 }
211         }
212 #elif defined(hpux) || defined(_AIX) || defined(__osf__)
213         struct utsname uts_name;
214         
215         uname(&uts_name);
216 #       if defined(_AIX) || defined(__osf__)
217                 _hostid = atol(uts_name.machine);
218 #       else
219                 _hostid = atol(uts_name.idnumber);
220 #       endif
221 #else
222         _hostid = gethostid();
223 #endif
224         return _hostid;
225 }
226
227 /*
228  * _tt_sigset sets up a signal handler in such a way that the handler
229  * is *not* unregistered when the signal handler is entered.  If
230  * returns 0 if an error occurs, else 1, and leaves errno set according
231  * to the underlying system call (sigaction, signal, sigset.)
232  */
233 int
234 _tt_sigset(
235         int     sig,
236         SIG_PF  handler )
237 {
238 #if defined(OPT_POSIX_SIGNAL)
239 /* 
240  * There seems to be some controversy over the type of sa_handler in
241  * C++ programs.  Everybody\'s man page seems to say it is of type
242  * "void (*)()", and that\'s what Solaris does, and I think that\'s what
243  * POSIX says, but both HP and IBM define it as the arguably much more
244  * useful "void (*)(int)", a/k/a SIG_PF.
245  * 
246  * [4 Apr 95] Solaris 2.5 has switched to use void (*)(int), which
247  * is nice for the long run but causes us some short-run problems
248  * as we want this level of the source to compile both on
249  * Solaris 2.4 and Solaris 2.5 for a while. To solve this, we use
250  * the "sa_sigaction" element of the sigaction structure, which is the
251  * three-argument flavor of the function pointer.  This is, strictly, 
252  * a lie, but it's safe since our signal handlers never look at the
253  * arguments anyway.  sa_sigaction is, fortunately, the same on all
254  * Solaris versions.
255  * Once the requirement to compile on Solaris 2.4 goes away, we can
256  * simply remove the OPT_BUG_SUNOS_5 ifdefs here, leaving only the
257  * UnixWare one.
258  */
259         struct sigaction act;
260 #if defined(OPT_BUG_SUNOS_5)    
261         act.sa_sigaction = (void (*)(int, siginfo_t *, void *)) handler;
262 #elif defined(OPT_BUG_USL) || defined(OPT_BUG_UXP)
263         act.sa_handler = (void (*)()) handler;
264 #else
265         act.sa_handler = handler;
266 #endif  
267         sigemptyset(&act.sa_mask);
268         act.sa_flags = 0;
269         return 0==sigaction(sig, &act, NULL);
270 #elif defined(OPT_BSD_SIGNAL)
271         return SIG_ERR!=signal(sig, handler);
272 #else
273         return SIG_ERR!=sigset(sig, handler);
274 #endif
275 }
276
277 /*
278  * _tt_putenv - putenv()s a buffer containing "variable=value"
279  * On success, returns the malloc()ed buffer that was passed to putenv().
280  * On failure, returns 0.
281  *
282  * Note: the returned buffer becomes a storage leak after this or any
283  * other form of putenv() replaces variable in the environment.
284  */
285 char *
286 _tt_putenv(
287         const char *variable,
288         const char *value
289 )
290 {
291         if (variable == 0) {
292                 return 0;
293         }
294         if (value == 0) {
295                 value = "";
296         }
297         char *buf = (char *)malloc( strlen(variable) + strlen(value) + 2 );
298         if (buf == 0) {
299                 return 0;
300         }
301         sprintf( buf, "%s=%s", variable, value );
302         if (putenv( buf ) != 0) {
303                 return 0;
304         } else {
305                 return buf;
306         }
307 }
308
309 // prefix passed to _tt_openlog()
310 static _Tt_string *_tt_syslog_prefix = 0;
311
312 // prefix if _tt_openlog() has never been called
313 static _Tt_string *_tt_syslog_default_prefix = 0;
314
315 void
316 _tt_openlog(
317         const char     *prefix,
318         int             logopt,
319         int             facility
320 )
321 {
322         if (_tt_syslog_prefix == 0) {
323                 _tt_syslog_prefix = new _Tt_string;
324         }
325         //
326         // Save the prefix, for when we write the prefix ourselves
327         // instead of letting syslog() do it
328         //
329         *_tt_syslog_prefix = prefix;
330         if (logopt & LOG_PID) {
331                 *_tt_syslog_prefix =
332                         _tt_syslog_prefix->cat("[").cat( getpid() ).cat("]");
333         }
334         *_tt_syslog_prefix = _tt_syslog_prefix->cat(": ");
335         openlog( prefix, logopt, facility );
336 }
337
338 void
339 _tt_vsyslog(
340         FILE           *sink,
341         int             priority,
342         const char     *format,
343         va_list         args
344 )
345 {
346         // XXX also log to ~/.dt/errorlog
347         if (_tt_global && _tt_global->silent) {
348                 return;
349         }
350         _Tt_string _format( format );
351         if (   (_tt_syslog_default_prefix == 0)
352             && (_tt_syslog_prefix == 0))
353         {
354                 //
355                 // Only initialize default prefix if openlog() is uncalled
356                 //
357                 _tt_syslog_default_prefix = new _Tt_string( "libtt[" );
358                 *_tt_syslog_default_prefix =
359                         _tt_syslog_default_prefix->cat( getpid() ).cat( "]: " );
360         }
361         if ((_tt_syslog_prefix == 0) && (_tt_syslog_default_prefix != 0)) {
362                 //
363                 // libtt cannot presume to call openlog(),
364                 // so we add our own prefix when openlog() is uncalled
365                 //
366                 _format = _tt_syslog_default_prefix->cat( _format );
367         }
368         if (sink != 0) {
369                 if (_tt_syslog_prefix != 0) {
370                         _tt_syslog_prefix->print( sink );
371                 }
372                 // XXX We do not handle %%m.
373                 _format = _format.replace( "%m", strerror( errno ) );
374                 vfprintf( sink, _format, args );
375                 fputc( '\n', sink );
376                 fflush( sink );
377                 return;
378         }
379
380 #if defined(OPT_BUG_AIX) || defined(OPT_BUG_HPUX) || defined(OPT_BUG_USL) || defined(OPT_BUG_UXP) || defined(__osf__)
381         char buf[5000];
382         vsprintf( buf, _format, args );
383         syslog( priority, buf );
384 #else
385         vsyslog( priority, _format, args );
386 #endif
387 }
388
389 void
390 _tt_syslog(
391         FILE           *sink,
392         int             priority,
393         const char     *format,
394         ...
395 )
396 {
397         va_list args;
398
399         va_start( args, format );
400         _tt_vsyslog( sink, priority, format, args );
401         va_end( args );
402 }
403
404
405 //
406 // _tt_get_first_set_env_var - getenvs i_num_names char*s in the environment, and returns 
407 // the value of the first one found with a non-null value, or NULL if all have no value.
408 // The check is done from left to right across the supplied names.
409 // e.g. _tt_get_first_set_env_var (2, "FOO", "BAR") is functionally equivalent to 
410 // getenv("FOO") ? getenv("FOO") : getenv("BAR");
411 //
412
413 char* _tt_get_first_set_env_var (int i_num_names, ...) {
414     
415     // set up for variable number of arguments
416     va_list p_var;
417     va_start(p_var, i_num_names);
418     
419     char* pc_name_to_check;  // name of the environment var we're currently looking for
420     char* pc_value = NULL;   // value of environment var we're currently looking for
421     int i_index;             // indexes through each of the names supplied
422     
423     // check each of the names in turn
424     for (i_index = 0; i_index < i_num_names; i_index++) {
425         
426         // get the next name to check
427         pc_name_to_check = va_arg(p_var, char*);
428         
429         if (!pc_name_to_check)  // ignore any null names
430             continue;
431         
432         // get the environment value (if any)
433         pc_value = getenv(pc_name_to_check);
434         
435         if (pc_value) // we found one with a value
436             break;
437     }
438     
439     // clean up var args
440     va_end(p_var); 
441     
442     // return the value
443     return pc_value;
444 }
445
446
447 // _tt_put_all_env_var - sets i_num_names char*s in the environment, to pc_val, using _tt_putenv.
448 // NOTE: xxx see the _tt_putenv comments about memory leakage.
449 // _tt_putenv are processed from left to right across the supplied names.  If any
450 // _tt_putenv fails, putenv'ing stops.  The number of successful putenv's is returned
451 // e.g. _tt_put_all_env_var (2, "HELLO", "FOO", "BAR") is functionally equivalent to 
452 // _tt_putenv("FOO", "HELLO") ? 0 : (_tt_putenv("BAR", "HELLO") ? 1 : 2);
453
454 int _tt_put_all_env_var (int i_num_names, const char* pc_val, ...) {
455     
456     // set up for variable number of arguments
457     va_list p_var;
458     va_start(p_var, pc_val);
459     
460     char* pc_name_to_set;  // name of the environment var we're currently looking for
461     char* pc_buff;         // value of _tt_putenv call
462     int i_index;           // indexes through each of the names supplied
463     
464     // check each of the names in turn
465     for (i_index = 0; i_index < i_num_names; i_index++) {
466         
467         // get the next name to check
468         pc_name_to_set = va_arg(p_var, char*);
469         
470         if (!pc_name_to_set)  // ignore any null names
471             continue;
472         
473         // set the environment value (if any)
474         pc_buff = _tt_putenv(pc_name_to_set, pc_val);
475         
476         if (!pc_buff) // we had a problem
477             break;
478     }
479     
480     // clean up var args
481     va_end(p_var); 
482     
483     // return the value
484     return i_index;
485 }
486