1/* *****************************************************************************
2
3libcsc: System Subsystem
4
5	----------------------------------------------------------------
6
7Copyright (c) 1999, 2001, 2002 Douglas R. Jerome, Peoria, AZ USA
8
9	This program is free software; you can redistribute it and/or modify
10	it under the terms of the GNU Library General Public License as
11	published by the Free Software Foundation; either version 2 of the
12	License, or (at your option) any later version.
13
14	This program is distributed in the hope that it will be useful,
15	but WITHOUT ANY WARRANTY; without even the implied warranty of
16	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17	GNU General Public License for more details.
18
19	You should have received a copy of the GNU Library General Public
20	License along with this program; if not, write to the Free Software
21	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22
23	----------------------------------------------------------------
24
25FILE NAME
26
27	$RCSfile: csc_sys.c,v $
28	$Revision: 1.7 $
29	$Date: 2002/05/11 04:56:05 $
30
31PROGRAM INFORMATION
32
33	Developed by:	libcsc project
34	Developer:	Douglas R. Jerome, drj, <jerome@primenet.com>
35
36FILE DESCRIPTION
37
38<SUBSYSTEM NAME="csc_sys">
39
40NAME
41	csc_sys
42
43DESCRIPTION
44	System Subsystem
45
46FUNCTIONS
47	CSCsysLimitsGet     - find some system limits
48	CSCsysInstallSignal - fairly portable signal installer
49        CSCsysUsleep        - sleep some microseconds
50</SUBSYSTEM>
51
52CHANGE LOG
53
54	10may02	drj	Miscellaneous c-switching and header file changes.
55
56	02may02	drj	Small changes to support Solaris.
57
58	20apr02	drj	Small comments changes.
59
60	13apr02	drj	Added CSCsysUsleep().
61
62	25jun01	drj	Converted to libcsc: renamed everything from rt to csc,
63			removed some debug message printing code.
64
65	29apr99	drj	Rebaselined from librt version 0.3.1.
66
67***************************************************************************** */
68
69
70/* ************************************************************************* */
71/*                                                                           */
72/*      F e a t u r e   S w i t c h e s                                      */
73/*                                                                           */
74/* ************************************************************************* */
75
76/*
77 * Select these feature by moving them from the `if UNDEF' into the `else'
78 * section.
79 */
80#ifdef	UNDEF
81#   define	_BSD_SOURCE	1	/* 4.3+bsd subsystems            */
82#   define	_POSIX_SOURCE	1	/* posix.1                       */
83#   define	_POSIX_C_SOURCE	199309L	/* posix.1 and posix.4           */
84#else
85#   define	_POSIX_C_SOURCE	199506L	/* posix.1 and posix.4, and more */
86#   ifndef	_REENTRANT
87#      define	_REENTRANT		/* for glibc                     */
88#   endif
89#endif
90
91
92/* ************************************************************************* */
93/*                                                                           */
94/*      I n c l u d e d   F i l e s                                          */
95/*                                                                           */
96/* ************************************************************************* */
97
98/*
99 * OS Specific Header Files
100 */
101/*  (None.)  */
102
103/*
104 * Standard C (ANSI) Header Files
105 */
106#include	<errno.h>
107#include	<string.h>
108#ifdef	DEBUG
109#   include	<stdio.h>
110#endif
111
112/*
113 * Posix Header Files
114 */
115#include	<unistd.h>
116#include	<signal.h>  /* use POSIX signal API */
117
118/*
119 * 4.3+BSD Header Files
120 */
121#ifdef	SOLARIS                /* Use extensions because the use of POSIX */
122#   define	__EXTENSIONS__ /* disables "struct timeval".              */
123#endif
124#include	<sys/time.h>
125#ifdef	SOLARIS
126#   undef	__EXTENSIONS__
127#endif
128
129/*
130 * Project Specific Header Files
131 */
132#include	"libcsc_debug.h"
133#include	"libcsc.h"
134
135
136/* ************************************************************************* */
137/*                                                                           */
138/*      M a n i f e s t   C o n s t a n t s                                  */
139/*                                                                           */
140/* ************************************************************************* */
141
142/*  (None.)  */
143
144
145/* ************************************************************************* */
146/*                                                                           */
147/*      E x t e r n a l   R e f e r e n c e s                                */
148/*                                                                           */
149/* ************************************************************************* */
150
151/*  (None.)  */
152
153
154/* ************************************************************************* */
155/*                                                                           */
156/*      S c a l a r   D a t a   T y p e s                                    */
157/*                                                                           */
158/* ************************************************************************* */
159
160/*  (None.)  */
161
162
163/* ************************************************************************* */
164/*                                                                           */
165/*      N o n - S c a l a r   D a t a   S t r u c t u r e s                  */
166/*                                                                           */
167/* ************************************************************************* */
168
169/*  (None.)  */
170
171
172/* ************************************************************************* */
173/*                                                                           */
174/*      P u b l i c   G l o b a l   V a r i a b l e s                        */
175/*                                                                           */
176/* ************************************************************************* */
177
178/*  (None.)  */
179
180
181/* ************************************************************************* */
182/*                                                                           */
183/*      P r i v a t e   G l o b a l   V a r i a b l e s                      */
184/*                                                                           */
185/* ************************************************************************* */
186
187/*  (None.)  */
188
189
190/* ************************************************************************* */
191/*                                                                           */
192/*      E x e c u t a b l e   C o d e   (Locally Used Functions)             */
193/*                                                                           */
194/* ************************************************************************* */
195
196
197/**************************************************************************
198 * Private Function Prototypes
199 **************************************************************************/
200
201/*  (None.)  */
202
203
204/* ---------------------------------------------------------------------- */
205
206
207/**************************************************************************
208 * Private Function
209 **************************************************************************/
210
211/*  (None.)  */
212
213
214/* ************************************************************************* */
215/*                                                                           */
216/*      E x e c u t a b l e   C o d e   (External Interface Functions)       */
217/*                                                                           */
218/* ************************************************************************* */
219
220
221/***************************************************************************
222 * Public Function rtusleep
223 ***************************************************************************
224
225<SUBROUTINE NAME="CSCsysUsleep">
226
227NAME
228        CSCsysUsleep - sleep some microseconds (rounded to kernel capability)
229
230SYNOPSYS
231        #include "libcsc.h"
232
233        void   CSCsysUsleep (
234                            const size_t   microseconds
235                            );
236
237RETURN VALUE
238        CSCsysUsleep() has no return value.
239
240DESCRIPTION
241        The calling process/task will block for microseconds.  The actual time
242        blocked will be descretized to the granularity implemented by the
243        kernel.
244
245SEE ALSO
246        CSCsysInstallSignal(3)
247        CSCsysLimitsGet(3)
248</SUBROUTINE>
249
250 ***************************************************************************/
251
252PUBLIC void   (CSCsysUsleep) (
253                             const size_t   microseconds
254                             )
255   {
256   struct timeval  timeout;
257          fd_set   readfds;
258          fd_set   writefds;
259          fd_set   exceptfds;
260
261   FD_ZERO (&readfds);
262   FD_ZERO (&writefds);
263   FD_ZERO (&exceptfds);
264
265   timeout.tv_sec  = microseconds / 1000000u;
266   timeout.tv_usec = microseconds % 1000000u;
267
268   select (1, &readfds, &writefds, &exceptfds, &timeout);
269   }
270
271
272/***************************************************************************
273 * Public Function CSCsysLimitsGet
274 ***************************************************************************
275
276<SUBROUTINE NAME="CSCsysLimitsGet">
277
278NAME
279        CSCsysLimitsGet - find some system limits
280
281SYNOPSYS
282        #include "libcsc.h"
283
284        int   CSCsysLimitsGet (
285                              int*    const fileOpenMaxPtr,
286                              int*    const fileNameLengthPtr,
287                              int*    const filePathLengthPtr
288                              );
289
290RETURN VALUE
291        RTS_OK ........ successful
292
293        CSC_BADARG .... fileOpenMaxPtr, or fileNameLengthPtr, or
294                        filePathLengthPtr is NULL
295
296        CSC_ERROR ..... error getting limit from system call
297
298DESCRIPTION
299        CSCsysLimitsGet() makes some system calls and writes the integer
300        information to the addresses specified in the arguments.
301
302        `fileOpenMaxPtr' must be a non-NULL pointer to an integer. If the call
303        to CSCsysLimitsGet() is successful, the integer value will be the
304        maximum number of open files allowed per process.
305
306        `fileNameLenghtPtr' must be a non-NULL pointer to an integer. If the
307        call to CSCsysLimitsGet() is successful, the integer value will be the
308        maximum files name length allowed by the system.
309
310        `filePathLengthPtr' must be a non-NULL pointer to an integer. If the
311        call to CSCsysLimitsGet() is successful, the integer value will be the
312        maximum path length allowed by the system.
313
314SEE ALSO
315        CSCsysInstallSignal(3)
316        CSCsysUsleep(3)
317</SUBROUTINE>
318
319 ***************************************************************************/
320
321PUBLIC int   (CSCsysLimitsGet) (
322                               int*    const fileOpenMaxPtr,
323                               int*    const fileNameLengthPtr,
324                               int*    const filePathLengthPtr
325                               )
326   {
327   int   errCode    = CSC_OK;
328   int   configItem = 0;
329
330   ASSERT_RTN (							\
331              fileOpenMaxPtr    != NULL,			\
332              "CSCsysLimitsGet: NULL fileOpenMaxPtr",		\
333              CSC_BADARG					\
334              );
335   ASSERT_RTN (							\
336              fileNameLengthPtr != NULL,			\
337              "CSCsysLimitsGet: NULL fileNameLengthPtr",	\
338              CSC_BADARG					\
339              );
340   ASSERT_RTN (							\
341              filePathLengthPtr != NULL,			\
342              "CSCsysLimitsGet: NULL filePathLengthPtr",	\
343              CSC_BADARG					\
344              );
345
346#define	I_HAVE_A_BAD_ARGUMENT	((fileOpenMaxPtr == NULL) ||	\
347				(fileNameLengthPtr == NULL) ||	\
348				(filePathLengthPtr == NULL))
349   if (I_HAVE_A_BAD_ARGUMENT) return (CSC_BADARG);
350#undef	I_HAVE_A_BAD_ARGUMENT
351
352   /*
353    * Find the maximum number of open files allowed per process. Don't use
354    * the constant OPEN_MAX from the POSIX.1 header file `limits.h' because,
355    * as a portable constant, it is restrictive. Use the posix function
356    * `sysconf(_SC_OPEN_MAX)' to dynamically find the system's true
357    * capabilities. Don't use the constant _POSIX_OPEN_MAX because it seems to
358    * be even more restrictive than the constant OPEN_MAX.
359    */
360
361   configItem = sysconf (_SC_OPEN_MAX);
362   if (configItem > 0)
363      {
364      *fileOpenMaxPtr = configItem;
365      }
366   else
367      {
368      if (errno == 0)
369         {
370         CSCioWarnPrint (
371                        "libcsc",
372                        "CSCsysLimitsGet",
373                        "guessing at maximum open file count (%d).\n",
374                        255
375                        );
376         *fileOpenMaxPtr = 255;  /* Guess at it. */
377         }
378      else
379         {
380#ifdef	DEBUG
381         perror ("error for sysconf(_SC_OPEN_MAX)");
382#endif
383         errCode = CSC_ERROR;
384         }
385      }
386
387/*
388 * Find the maximum file name length. Don't use the constant NAME_MAX from the
389 * POSIX.1 header file `limits.h' because, as a portable constant, it is
390 * restrictive. Use the posix function `sysconf(_PC_NAME_MAX)' to dynamically
391 * find the system's true capabilities. Don't use the constant _POSIX_NAME_MAX
392 * because it seems to be even more restrictive than the constant NAME_MAX.
393 */
394
395   configItem = pathconf ("/", _PC_NAME_MAX);
396   if (configItem > 0)
397      {
398      *fileNameLengthPtr = configItem;
399      }
400   else
401      {
402      if (errno == 0)
403         {
404         CSCioWarnPrint (
405                        "libcsc",
406                        "CSCsysLimitsGet",
407                        "guessing at maximum file name size (%d).\n",
408                        255
409                        );
410         *fileNameLengthPtr = 255;  /* Guess at it. */
411         }
412      else
413         {
414#ifdef	DEBUG
415         perror ("error for pathconf(\"/\",_PC_NAME_MAX)");
416#endif
417         errCode = CSC_ERROR;
418         }
419      }
420
421/*
422 * Find the maximum path length. Don't use the constant PATH_MAX from the
423 * POSIX.1 header file `limits.h' because, as a portable constant, it is
424 * restrictive. Use the posix function `pathconf(_PC_PATH_MAX)' to dynamically
425 * find the system's true capabilities. Don't use the constant _POSIX_PATH_MAX
426 * because it seems to be even more restrictive than the constant PATH_MAX.
427 */
428
429   configItem = pathconf ("/", _PC_PATH_MAX);
430   if (configItem > 0)
431      {
432      *filePathLengthPtr = configItem;
433      }
434   else
435      {
436      if (errno == 0)
437         {
438         CSCioWarnPrint (
439                        "libcsc",
440                        "CSCsysLimitsGet",
441                        "guessing at maximum path size (%d).\n",
442                        255
443                        );
444         *filePathLengthPtr = 255;  /* Guess at it. */
445         }
446      else
447         {
448#ifdef	DEBUG
449         perror ("error for pathconf(\"/\",_PC_PATH_MAX)");
450#endif
451         errCode = CSC_ERROR;
452         }
453      }
454
455   return (errCode);
456   }
457
458
459/***************************************************************************
460 * Public Function CSCsysInstallSignal
461 ***************************************************************************
462
463<SUBROUTINE NAME="CSCsysInstallSignal">
464
465NAME
466        CSCsysInstallSignal - fairly portable signal installer
467
468SYNOPSYS
469        #include "libcsc.h"
470
471        CSCsigFnType   CSCsysInstallSignal (
472                                           const int              signo,
473                                           const CSCsigFnType     func,
474                                           const CSCsigModeType   mode
475                                           );
476
477RETURN VALUE
478        The return value from CSCsysInstallSignal() is a function pointer to a
479        signal handler.
480
481        If CSCsysInstallSignal() is NOT successful, then the return value is
482        SIG_ERR cast as a signal handler function.
483
484        If CSCsysInstallSignal() is successful, then the return value is a
485        function pointer to the previously installed handler cast as a
486        signal handler function; this might be NULL in the typical case that
487        there was no previous signal handler.
488
489DESCRIPTION
490        CSCsysInstallSignal() is a reliable version of signal() using POSIX
491        sigaction().
492
493        `signo' is the signal number of the signal for which the signal handler
494        function `func' is installed.
495
496        `mode' is CSC_SIG_INTERRUPT or CSC_SIG_RESTART; it is used to control
497        behavior, specifically for slow system calls:
498
499                mode                    behavior
500                ----                    --------
501                CSC_SIG_INTERRUPT       slow system calls are interrupted
502
503                CSC_SIG_RESTART         slow system calls are not interrupted
504
505        An illustration of slow system call and signal interrupt is a program
506        that creates children and has a signal handler for SIGCHLD. If this
507        program blocks on something like an accept() on a TCP socket connection
508        and a child process terminates, then the registered SIGCHLD signal
509        handler runs; but, the process unblocks and returns from the accept()
510        with no connection (errno should be EINTR). This can be avoided by
511        using CSCsysInstallSignal() to install the SIGCHLD signal handler
512        function `func' and specifying CSC_SIG_RESTART for `mode'.
513
514SEE ALSO
515        CSCsysLimitsGet(3)
516        CSCsysUsleep(3)
517</SUBROUTINE>
518
519 ***************************************************************************
520
521 If you want to set, or possibly change, the return value or type of the
522 variable `installStat', then spend some time digging through the system
523 header files. Start with `signal.h'. You can really mess up things if you
524 don't completely understand SIG_ERR.
525
526 ***************************************************************************/
527
528PUBLIC CSCsigFnType   (CSCsysInstallSignal) (
529                                            const int              signo,
530                                            const CSCsigFnType     func,
531                                            const CSCsigModeType   mode
532                                            )
533   {
534          CSCsigFnType   installStat = SIG_ERR;
535   struct sigaction      newAction;
536   struct sigaction      oldAction;
537
538   newAction.sa_handler = func;
539   newAction.sa_flags   = 0;
540   if (sigemptyset(&newAction.sa_mask) == 0)
541      {
542      switch (mode)
543         {
544         default:
545            ASSERT_RTN (						\
546                       CSC_FALSE,					\
547                       "CSCsysInstallSignal: terrible excuse for a mode",\
548                       SIG_ERR						\
549                       );
550            break;
551
552         case CSC_SIG_INTERRUPT:
553#ifdef SA_INTERRUPT
554            newAction.sa_flags |= SA_INTERRUPT;  /* SunOS 4.1.x */
555#endif
556            break;
557
558         case CSC_SIG_RESTART:
559#ifdef SA_RESTART
560            newAction.sa_flags |= SA_RESTART;    /* SVR4, 4.3+BSD */
561#endif
562            break;
563         }
564      if (sigaction(signo,&newAction,&oldAction) == 0)
565         {
566         installStat = oldAction.sa_handler;
567         }
568#ifdef	DEBUG
569      else
570         {
571         perror ("sigaction() failed");
572         CSCioErrorPrint (
573                         "libcsc",
574                         "CSCsysInstallSignal",
575                         "can't install signal %d handler (errno %d).\n\t",
576                         signo,
577                         errno
578                         );
579         }
580#endif
581      }
582#ifdef	DEBUG
583   else
584      {
585      perror ("sigemptyset() failed");
586      CSCioErrorPrint (
587                      "libcsc",
588                      "CSCsysInstallSignal",
589                      "can't create empty signal mask (errno %d).\n\t",
590                      errno
591                      );
592      }
593#endif
594
595   return (installStat);
596   }
597
598
599/* End of file. */
600