xref: /onnv-gate/usr/src/lib/libkmsagent/common/SYSCommon.c (revision 12720:3db6e0082404)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 
26 /*---------------------------------------------------------------------------
27  * Module:            SYSCommon.c
28  *-------------------------------------------------------------------------*/
29 
30 #include <stdio.h>
31 #include "SYSCommon.h"
32 #include <time.h>
33 #include <errno.h>
34 #include <sys/stat.h>
35 #include <sys/types.h>
36 #include <signal.h>
37 
38 #ifndef WIN32
39 #include <unistd.h>
40 #endif
41 
42 #ifdef WIN32
43 #include <io.h>
44 #include <stdlib.h>   /* for malloc, calloc, and free */
45 #elif defined K_LINUX_PLATFORM
46 #include <unistd.h>   /* it includes usleep(us) */
47 #include <sys/time.h>
48 #include <fts.h>
49 #else
50 /*
51  * Directory traversal code is not yet available for Solaris.
52  * If such code will need to be written, then it will probably use ftw.h.
53  */
54 #endif
55 
56 #ifdef K_SOLARIS_PLATFORM
57 /* For K_AdjustLocalClock */
58 #include <unistd.h>
59 /* For K_SetRootPassword */
60 #define    __EXTENSIONS__    /* to expose flockfile and friends in stdio.h */
61 #include <errno.h>
62 #include <libgen.h>
63 #include <malloc.h>
64 #include <signal.h>
65 #include <stdio.h>
66 #include <stdlib.h>
67 #include <strings.h>
68 #include <stropts.h>
69 #include <unistd.h>
70 #include <termio.h>
71 #include <security/pam_appl.h>
72 #include <widec.h>
73 #endif
74 
75 #ifdef K_LINUX_PLATFORM
76 extern int pthread_mutexattr_settype __P ((pthread_mutexattr_t *__attr,
77                        int __kind));
78 #endif
79 
80 #ifdef K_HPUX_PLATFORM
atoll(const char * str)81 int64 atoll(const char *str)
82 {
83     int64 tmp = 0;
84     sscanf(str, "%lld", &tmp);
85     return tmp;
86 }
87 
88 #endif
89 
90 
91 /*---------------------------------------------------------------------------
92  * Function: K_CreateThread
93  *
94  * Description:
95  *  Thread creation function "CreateThread" takes a thread function
96  *  and its parameter to create a thread. It also has a Boolean
97  *  parameter to indicate if the thread is detached or joinable.
98  *  A new thread's handle is returned through the output parameter.
99  *
100  * Input
101  * -----
102  *    i_pFunc         Function pointer of the thread function
103  *    i_pvData        The point of the parameter passed to the thread function
104  *    i_bIsDetached   The thread is detached or not
105  *                    (Note: It is not supported on Win32)
106  *
107  * Output
108  * ------
109  *    o_pNewThread    The Thread handle
110  *
111  * Return value       Error code
112  *
113  *--------------------------------------------------------------------------*/
114 
K_CreateThread(K_ThreadFunc i_pFunc,void * i_pvData,int i_bIsDetached,K_THREAD_HANDLE * o_pNewThread)115 int K_CreateThread(K_ThreadFunc i_pFunc,
116                   void *i_pvData,
117                   int i_bIsDetached,
118                   K_THREAD_HANDLE *o_pNewThread)
119 {
120     int iOK = K_SYS_OK;
121     int iReturn = 0;
122 
123 #ifdef WIN32
124 
125     {
126        unsigned id;
127 
128         *o_pNewThread = (HANDLE)_beginthreadex(NULL,
129                                         0,
130                                         (int (_stdcall *) (void *vpData))i_pFunc,
131                                         i_pvData,
132                                         0,
133                                         &id);
134 
135 
136         if(*o_pNewThread == 0)
137         {
138 #ifdef SYS_DEBUG
139             printf(" (%s, %d): error creating pthread, error = %d\n",
140                 __FILE__, __LINE__, iReturn);
141 #endif
142             return K_SYS_ERR_CREATE_THREAD;
143         }
144 
145         return K_SYS_OK;
146     }
147 
148 #else
149     pthread_attr_t attr;
150 
151     iReturn = pthread_attr_init(&attr);
152 
153     if ( iReturn == 0 )
154     {
155         iReturn = pthread_attr_setdetachstate(&attr, (i_bIsDetached) ?
156                     PTHREAD_CREATE_DETACHED :
157                     PTHREAD_CREATE_JOINABLE);
158     }
159 
160 #ifdef UNIX
161     if ( iReturn == 0 )
162     {
163         iReturn = pthread_attr_setstacksize(&attr, 1024*1024);
164     }
165 #endif
166 
167     if ( iReturn == 0 )
168     {
169         iReturn = pthread_create(o_pNewThread, &attr, (void *(*)(void *)) i_pFunc, i_pvData);
170     }
171 
172     if ( iReturn == 0 )
173     {
174         iReturn = pthread_attr_destroy(&attr);
175     }
176 
177     // TODO: Log error?
178     if ( iReturn )
179     {
180 #ifdef SYS_DEBUG
181         printf(" (%s, %d): error creating pthread, error = %d\n",
182                 __FILE__, __LINE__, iReturn);
183 #endif
184 
185         iOK = K_SYS_ERR_CREATE_THREAD;
186     }
187 
188     return iOK;
189 #endif
190 }
191 
192 
193 /*---------------------------------------------------------------------------
194  * Function: K_JoinThread
195  *
196  * Description:
197  *  Thread joining function is called when the current thread
198  *  waits another thread to terminate.
199  *
200  * Input
201  * -----
202  *    i_hThread        The thread handle of the to-be-joined thread
203  *
204  * Output
205  * ------
206  *    (none)
207  *
208  * Return value        Error code
209  *
210  *--------------------------------------------------------------------------*/
211 
K_JoinThread(K_THREAD_HANDLE i_hThread)212 int  K_JoinThread(K_THREAD_HANDLE i_hThread)
213 {
214     int iOK = K_SYS_OK;
215 #ifdef WIN32
216 
217     WaitForSingleObject(i_hThread, INFINITE);
218 
219 #else
220     {
221         int iReturn;
222         iReturn = pthread_join(i_hThread, NULL);
223 
224         if ( iReturn )
225         {
226 
227 #ifdef SYS_DEBUG
228             printf(" (%s, %d): error creating pthread, error = %d\n",
229                     __FILE__, __LINE__, iReturn);
230 #endif
231             iOK = K_SYS_ERR_JOIN_THREAD;
232         }
233     }
234 
235 #endif
236     return iOK;
237 }
238 
239 
240 /*---------------------------------------------------------------------------
241  * Function: K_GetCurrentThreadId
242  *
243  * Description:
244  *  Returns the thread ID of the current thread.
245  *
246  * Input
247  * -----
248  *    (none)
249  *
250  * Output
251  * ------
252  *    (none)
253  *
254  * Return value        The thread ID
255  *
256  *--------------------------------------------------------------------------*/
257 
K_GetCurrentThreadId()258 int K_GetCurrentThreadId()
259 {
260 #ifdef WIN32
261     return GetCurrentThreadId();
262 #else
263     return pthread_self();
264 #endif
265 
266 }
267 
268 
269 /*---------------------------------------------------------------------------
270  * Function: K_CreateMutex
271  *
272  * Description:
273  *  The mutex creation function creates a mutex according to the given
274  *  mutex type, and returns the mutex handle to the output parameter.
275  *
276  * Input
277  * -----
278  *    i_bIsRecursive   Indication whether the mutex can be entered recursively
279  *
280  * Output
281  * ------
282  *    o_phandle        the handle pointer to the mutex
283  *
284  * Return value        Error Code
285  *
286  *--------------------------------------------------------------------------*/
287 
K_CreateMutex(K_MUTEX_HANDLE * o_phandle)288 int K_CreateMutex( K_MUTEX_HANDLE *o_phandle )
289 {
290     int iOK = K_SYS_OK;
291     BOOL bIsRecursive = 1;  // this used to be an input -- but why do we want this to be optional?
292 
293 #ifdef WIN32
294     {
295         *o_phandle = (WIN32Mutex *)malloc(sizeof(WIN32Mutex));
296         if(*o_phandle == NULL)
297         {
298             return K_SYS_ERR_NO_MEMORY;
299         }
300         (*o_phandle)->m_bIsRecursive = bIsRecursive;
301         if(bIsRecursive)
302         {
303                 InitializeCriticalSection(&((*o_phandle)->m_stCriticalSection));
304         }
305         else
306         {
307             (*o_phandle)->m_handle = CreateMutex(NULL, FALSE, NULL);
308         }
309 
310     }
311 #else
312     {
313         int iType;
314         pthread_mutexattr_t attr;
315 
316         if ( pthread_mutexattr_init(&attr) )
317         {
318             return K_SYS_ERR_COND;
319         }
320 
321         if(bIsRecursive)
322         {
323             iType =
324 #ifdef K_LINUX_PLATFORM
325             PTHREAD_MUTEX_RECURSIVE_NP;
326 #else
327             PTHREAD_MUTEX_RECURSIVE;
328 #endif
329 
330             if ( pthread_mutexattr_settype(&attr, iType) )
331             {
332                 return K_SYS_ERR_COND;
333             }
334         }
335 
336         *o_phandle = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t));
337         if(*o_phandle == NULL)
338         {
339             return K_SYS_ERR_NO_MEMORY;
340         }
341 
342         if ( pthread_mutex_init(*o_phandle, &attr) )
343         {
344             return K_SYS_ERR_COND;
345         }
346 
347         if ( pthread_mutexattr_destroy(&attr) )
348         {
349             return K_SYS_ERR_COND;
350         }
351     }
352 #endif
353 
354     return iOK;
355 }
356 
357 
358 /*---------------------------------------------------------------------------
359  * Function: K_LockMutex
360  *
361  * Description:
362  *  K_LockMutex is used to lock the mutex, and K_UnlockMutex is
363  *  used to unlock it.
364  *
365  * Input
366  * -----
367  *    i_handle        the mutex handle
368  *
369  * Output
370  * ------
371  *    (none)
372  *
373  * Return value       Error Code
374  *
375  *--------------------------------------------------------------------------*/
376 
K_LockMutex(K_MUTEX_HANDLE i_handle)377 int K_LockMutex(K_MUTEX_HANDLE i_handle)
378 {
379     int iOK = K_SYS_OK;
380 #ifdef WIN32
381 
382     if(i_handle->m_bIsRecursive)
383     {
384         EnterCriticalSection(&(i_handle->m_stCriticalSection));
385     }
386     else
387     {
388         WaitForSingleObject(i_handle->m_handle, INFINITE);
389     }
390 
391 #else
392 
393     if ( pthread_mutex_lock(i_handle) )
394     {
395         return K_SYS_ERR_COND;
396     }
397 
398 #endif
399     return iOK; // TODO: better error handling
400 }
401 
402 
403 /*---------------------------------------------------------------------------
404  * Function: K_UnlockMutex
405  *
406  * Description:
407  *  K_UnlockMutex is used to unlock the lock.
408  *
409  * Input
410  * -----
411  *    i_handle        the mutex handle
412  *
413  * Output
414  * ------
415  *    (none)
416  *
417  * Return value       Error Code
418  *
419  *--------------------------------------------------------------------------*/
420 
K_UnlockMutex(K_MUTEX_HANDLE i_handle)421 int K_UnlockMutex(K_MUTEX_HANDLE i_handle)
422 {
423     int iOK = K_SYS_OK;
424 
425 #ifdef WIN32
426     if(i_handle->m_bIsRecursive)
427     {
428         LeaveCriticalSection(&(i_handle->m_stCriticalSection));
429     }
430     else
431     {
432         ReleaseMutex(i_handle->m_handle);
433     }
434 
435 #else
436 
437     if ( pthread_mutex_unlock(i_handle) )
438     {
439         return K_SYS_ERR_COND;
440     }
441 #endif
442 
443     return iOK; // TODO: better error handling
444 }
445 
446 
447 /*---------------------------------------------------------------------------
448  * Function: K_DestroyMutex
449  *
450  * Description:
451  *  When a mutex is no longer needed, K_DestroyMutex must be called
452  *  to destroy it.
453  *
454  * Input
455  * -----
456  *    i_handle        the mutex handle
457  * Output
458  * ------
459  *    (none)
460  *
461  * Return value       Error Code
462  *
463  *--------------------------------------------------------------------------*/
464 
K_DestroyMutex(K_MUTEX_HANDLE i_handle)465 int K_DestroyMutex(K_MUTEX_HANDLE i_handle)
466 {
467 
468     int iOK = K_SYS_OK;
469 
470 #ifdef WIN32
471 
472     if(i_handle->m_bIsRecursive)
473     {
474         DeleteCriticalSection(&(i_handle->m_stCriticalSection));
475     }
476     else
477     {
478         CloseHandle(i_handle->m_handle);
479     }
480     free(i_handle);
481 
482 #else
483     pthread_mutex_destroy(i_handle);
484     free(i_handle);
485 #endif
486     return iOK; // TODO: better error handling
487 }
488 
489 
490 /*---------------------------------------------------------------------------
491  * Function: K_InitConditionalVariable
492  *
493  * Description:
494  *  This function initializes a conditional variable.  Upon successful
495  *  completion, the new condition variable is returned via the condition
496  *  parameter, and 0 is returned.  Otherwise, an error code is returned.
497  *
498  * Input
499  * -----
500  *    i_pCond         the pointer to the conditional variable which is to be
501  *                    initialized
502  *
503  * Output
504  * ------
505  *    (none)
506  *
507  * Return value       Error Code
508  *
509  *--------------------------------------------------------------------------*/
510 
K_InitConditionalVariable(K_ConditionalVariable * i_pCond)511 int K_InitConditionalVariable (K_ConditionalVariable * i_pCond)
512 {
513     int iOK = K_SYS_OK;
514 #ifdef WIN32
515 
516     i_pCond->m_hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
517     i_pCond->m_hMutex = CreateMutex(NULL, FALSE, NULL);
518     i_pCond->m_iSignalAll = 0;
519     i_pCond->m_iNumWaiting = 0;
520 
521 #else
522 
523     if ( pthread_cond_init(i_pCond, NULL) )
524     {
525         return K_SYS_ERR_COND;
526     }
527 
528 #endif
529 
530     return iOK;
531 }
532 
533 
534 /*---------------------------------------------------------------------------
535  * Function: K_DestroyConditionalVariable
536  *
537  * Description:
538  *  This function destroys a conditional variable.  Upon successful
539  *  completion, the condition variable is destroyed, and 0 is returned.
540  *  Otherwise, an error code is returned.
541  *  After deletion of the condition variable, the condition parameter
542  *  is not valid until it is initialized again by a call to the
543  *  K_InitConditionalVariable subroutine.
544  *
545  * Input
546  * -----
547  *    i_pCond        the pointer to the conditional variable which is to be
548  *                   destroyed
549  * Output
550  * ------
551  *    (none)
552  *
553  * Return value      Error Code
554  *
555  *--------------------------------------------------------------------------*/
556 
K_DestroyConditionalVariable(K_ConditionalVariable * i_pCond)557 int K_DestroyConditionalVariable(K_ConditionalVariable * i_pCond)
558 {
559     int iOK = K_SYS_OK;
560 #ifdef WIN32
561     CloseHandle(i_pCond->m_hMutex);
562     CloseHandle(i_pCond->m_hEvent);
563 #else
564 
565     if ( pthread_cond_destroy(i_pCond) )
566     {
567         return K_SYS_ERR_COND;
568     }
569 
570 #endif
571     return iOK;
572 
573 }
574 
575 
576 /*---------------------------------------------------------------------------
577  * Function: K_WaitConditionalVariable
578  *
579  * Description:
580  *  This function is used to block on a condition variable.
581  *  They are called with mutex locked by the calling thread or undefined
582  *  behaviour will result.
583  *
584  * Input
585  * -----
586  *    i_pCond        the pointer to the conditional variable
587  *    i_handle       the companion mutex handle
588  *
589  * Output
590  * ------
591  *    (none)
592  *
593  * Return value      Error Code
594  *
595  *--------------------------------------------------------------------------*/
596 
K_WaitConditionalVariable(K_ConditionalVariable * i_pCond,K_MUTEX_HANDLE i_handle)597 int  K_WaitConditionalVariable(K_ConditionalVariable * i_pCond,
598                                K_MUTEX_HANDLE i_handle)
599 {
600 
601     int iOK = K_SYS_OK;
602 #ifdef WIN32
603     DWORD res;
604 
605     while (1)
606     {
607         iOK = WaitForSingleObject(i_pCond->m_hMutex, INFINITE);
608         if (iOK != WAIT_OBJECT_0)
609         {
610             return K_SYS_ERR_COND;
611         }
612         i_pCond->m_iNumWaiting++;
613         ReleaseMutex(i_pCond->m_hMutex);
614 
615         K_UnlockMutex(i_handle);
616         res = WaitForSingleObject(i_pCond->m_hEvent, INFINITE);
617         i_pCond->m_iNumWaiting--;
618 
619         if (res != WAIT_OBJECT_0)
620         {
621             ReleaseMutex(i_pCond->m_hMutex);
622             return K_SYS_ERR_COND;
623         }
624 
625         if (i_pCond->m_iSignalAll)
626         {
627             if (i_pCond->m_iNumWaiting == 0)
628             {
629                 ResetEvent(i_pCond->m_hEvent);
630             }
631             break;
632         }
633 
634         if (i_pCond->m_iSignalled)
635         {
636             i_pCond->m_iSignalled = 0;
637             ResetEvent(i_pCond->m_hEvent);
638             break;
639         }
640         ReleaseMutex(i_pCond->m_hMutex);
641     }
642 
643     K_LockMutex(i_handle);
644 
645     return K_SYS_OK;
646 #else
647 
648     if ( pthread_cond_wait(i_pCond, i_handle) )
649     {
650         return K_SYS_ERR_COND;
651     }
652 
653 #endif
654     return iOK; // TODO: better error handling
655 }
656 
657 
658 /*---------------------------------------------------------------------------
659  * Function: K_SignalConditionalVariable
660  *
661  * Description:
662  *  This function is used to restart one of the threads that are waiting on
663  *  the condition variable.  If no threads are waiting on it, nothing happens.
664  *  If several threads are waiting on it, exactly one is restarted.
665  *
666  * Input
667  * -----
668  *    i_pCond        the pointer to the conditional variable
669  *
670  * Output
671  * ------
672  *    (none)
673  *
674  * Return value      Error Code
675  *
676  *--------------------------------------------------------------------------*/
677 
K_SignalConditionalVariable(K_ConditionalVariable * i_pCond)678 int K_SignalConditionalVariable(K_ConditionalVariable * i_pCond)
679 {
680     int iOK = K_SYS_OK;
681 #ifdef WIN32
682 
683     int iReturn;
684 
685     iReturn = WaitForSingleObject(i_pCond->m_hMutex, INFINITE);
686     if (iReturn != WAIT_OBJECT_0)
687     {
688         return K_SYS_ERR_COND;
689     }
690 
691     i_pCond->m_iSignalled = 1;
692 
693     iReturn = SetEvent(i_pCond->m_hEvent);
694     if (iReturn == 0)
695     {
696         iOK = K_SYS_ERR_COND;
697     }
698     ReleaseMutex(i_pCond->m_hMutex);
699 
700     return iOK;
701 #else
702 
703     if ( pthread_cond_signal(i_pCond) )
704     {
705         return K_SYS_ERR_COND;
706     }
707 
708 #endif
709     return iOK;
710 }
711 
712 
713 /*---------------------------------------------------------------------------
714  * Function: K_BroadcastConditionalVariable
715  *
716  * Description:
717  *  This function is used to restart all threads that are waiting on
718  *  the condition variable.
719  *
720  * Input
721  * -----
722  *    i_pCond        the pointer to the conditional variable
723  *
724  * Output
725  * ------
726  *    (none)
727  *
728  * Return value      Error Code
729  *
730  *--------------------------------------------------------------------------*/
731 
K_BroadcastConditionalVariable(K_ConditionalVariable * i_pCond)732 int K_BroadcastConditionalVariable(K_ConditionalVariable * i_pCond)
733 {
734 
735     int iOK = K_SYS_OK;
736 
737 #ifdef WIN32
738 
739     int iReturn;
740 
741     iReturn = WaitForSingleObject(i_pCond->m_hMutex, INFINITE);
742     if (iReturn != WAIT_OBJECT_0)
743     {
744         return K_SYS_ERR_COND;
745     }
746     i_pCond->m_iSignalled = 1;
747     i_pCond->m_iSignalAll = 1;
748 
749     iReturn = SetEvent(i_pCond->m_hEvent);
750 
751     if (iReturn == 0)
752     {
753         iOK = K_SYS_ERR_COND;
754     }
755 
756     ReleaseMutex(i_pCond->m_hMutex);
757 
758     return iOK;
759 
760 #else
761 
762     if ( pthread_cond_broadcast(i_pCond) )
763     {
764         return K_SYS_ERR_COND;
765     }
766 
767 #endif
768     return iOK;
769 }
770 
771 
772 /*---------------------------------------------------------------------------
773  * Function: K_Sleep
774  *
775  * Description:
776  *  Sleep for a given period in given milliseconds.
777  *
778  * Input
779  * -----
780  *    i_ms        milliseconds
781  *
782  * Output
783  * ------
784  *    (none)
785  *
786  * Return value   (none)
787  *
788  *--------------------------------------------------------------------------*/
789 
K_Sleep(int i_ms)790 void K_Sleep(int i_ms)
791 {
792 #ifdef WIN32
793     Sleep(i_ms);
794 #else
795     usleep(i_ms * 1000);
796 #endif
797 }
798 
799 
800 /*---------------------------------------------------------------------------
801  * Function: K_GetTickCount
802  *
803  * Description:
804  *  The K_GetTickCount function retrieves the number of
805  *  milliseconds that have elapsed since the system was started.
806  *
807  * Input
808  * -----
809  *    (none)
810  *
811  * Output
812  * ------
813  *    (none)
814  *
815  * Return value        the elasped milliseconds since the system was started
816  *
817  *--------------------------------------------------------------------------*/
818 
K_GetTickCount()819 unsigned int K_GetTickCount()
820 {
821 #ifdef WIN32
822     return (unsigned int)GetTickCount();
823 #else
824     {
825         struct timeval tv;
826         gettimeofday( &tv, NULL );
827         /* this will rollover ~ every 49.7 days
828            dont surprise when it returns negative values, since we are only interested
829           in using  sth like "tickCount2 - tickCount1" to get the time interval
830         */
831         return ( tv.tv_sec * 1000 ) + ( tv.tv_usec / 1000 );
832     }
833 #endif
834 }
835 
836 
837 /*---------------------------------------------------------------------------
838  * Function: K_AdjustClock
839  *
840  * Description:
841  *  The K_AdjustClock function immediately adjusts the system clock by
842  *  the given number of seconds.  A positive number adjusts the system
843  *  clock forward; a negative number adjusts the system clock backward.
844  *
845  * Input
846  * -----
847  *    i_iAdjustmentInSeconds   Number of seconds by which to adjust the
848  *                             system clock
849  * Output
850  * ------
851  *    (none)
852  *
853  * Return value        1 if successful, 0 on error
854  *
855  *--------------------------------------------------------------------------*/
856 
K_AdjustClock(long i_iAdjustmentInSeconds)857 int K_AdjustClock( long i_iAdjustmentInSeconds )
858 {
859 #ifndef WIN32
860     struct timeval stDateTime;
861     if ( 0 != gettimeofday(&stDateTime, NULL) )
862     {
863         return FALSE;
864     }
865 
866     stDateTime.tv_sec += i_iAdjustmentInSeconds;
867 
868     if ( 0 != settimeofday(&stDateTime, NULL) )
869     {
870         return FALSE;
871     }
872 #else
873     // TODO: implement for Windows
874     return FALSE;
875 #endif
876 
877     return TRUE;
878 }
879 
880 
881 /*---------------------------------------------------------------------------
882  * Function: K_IsLittleEndian
883  *
884  * Description:
885  *  Checks to see whether this platform uses little endian integer
886  *  representation.
887  *
888  * Input
889  * -----
890  *    (none)
891  *
892  * Output
893  * ------
894  *    (none)
895  *
896  * Return value        1 for little endian
897  *
898  *--------------------------------------------------------------------------*/
899 
K_IsLittleEndian()900 int K_IsLittleEndian()
901 {
902     short iWord = 0x4321;
903     return ((*(unsigned char*)&iWord) == 0x21);
904 }
905 
906 
907 /*---------------------------------------------------------------------------
908  * Function: K_FileLength32
909  *
910  * Description:
911  *  Gets the size in bytes of the file associated with the given FILE pointer.
912  *
913  * Input
914  * -----
915  *    i_fpFile         File handle
916  *
917  * Output
918  * ------
919  *    (none)
920  *
921  * Return value        File size in bytes, or -1L on error
922  *
923  *--------------------------------------------------------------------------*/
924 
K_FileLength32(FILE * i_fpFile)925 long K_FileLength32( FILE* i_fpFile )
926 {
927 #ifdef WIN32
928     int iFileDescriptor = _fileno( i_fpFile );
929     struct _stat stStat;
930 
931     if ( _fstat(iFileDescriptor, &stStat) != 0)
932     {
933         // error
934         return -1L;
935     }
936 
937 #else
938     int iFileDescriptor = fileno( i_fpFile );
939     struct stat stStat;
940 
941     if ( fstat(iFileDescriptor, &stStat) != 0)
942     {
943         // error
944         return -1L;
945     }
946 
947 #endif
948 
949     return stStat.st_size;
950 }
951 
952 
953 /*---------------------------------------------------------------------------
954  * Function: K_StringCompareNoCase
955  *
956  * Description:
957  *  Compares the two given strings insensitive to case.
958  *
959  * Input
960  * -----
961  *    i_sString1       First string
962  *    i_sString2       Second string
963  *
964  * Output
965  * ------
966  *    (none)
967  *
968  * Return value        0 if identical, -1 if first string is less than second
969  *                     string, or 1 if first string is greater than second
970  *
971  *--------------------------------------------------------------------------*/
972 
K_StringCompareNoCase(const char * i_sString1,const char * i_sString2)973 int K_StringCompareNoCase( const char* i_sString1, const char* i_sString2 )
974 {
975 #ifdef WIN32
976     return _stricmp( i_sString1, i_sString2 );
977 #else
978     return strcasecmp( i_sString1, i_sString2 );
979 #endif
980 }
981 
982 
983 /*---------------------------------------------------------------------------
984  * Function: K_StringCompareNoCaseWide
985  *
986  * Description:
987  *  Compares the two given wide strings insensitive to case.
988  *
989  * Input
990  * -----
991  *    i_wsString1      First wide string
992  *    i_wsString2      Second wide string
993  *
994  * Output
995  * ------
996  *    (none)
997  *
998  * Return value        0 if identical, -1 if first string is less than second
999  *                     string, or 1 if first string is greater than second
1000  *
1001  *--------------------------------------------------------------------------*/
1002 
K_StringCompareNoCaseWide(const wchar_t * i_wsString1,const wchar_t * i_wsString2)1003 int K_StringCompareNoCaseWide( const wchar_t* i_wsString1, const wchar_t* i_wsString2 )
1004 {
1005 #ifdef WIN32
1006     return _wcsicmp( i_wsString1, i_wsString2 );
1007 #elif defined K_SOLARIS_PLATFORM
1008     return wscasecmp( i_wsString1, i_wsString2 );
1009 #else
1010     return wcscasecmp( i_wsString1, i_wsString2 );
1011 #endif
1012 }
1013 
1014 
1015 /*---------------------------------------------------------------------------
1016  * Function: K_CreateDirectory
1017  *
1018  * Description:
1019  *  Creates a directory with the given path name.
1020  *
1021  * Input
1022  * -----
1023  *    i_sDirectoryName  Directory name
1024  *
1025  * Output
1026  * ------
1027  *    (none)
1028  *
1029  * Return value        0 on success, -1 on failure
1030  *
1031  *--------------------------------------------------------------------------*/
1032 
K_CreateDirectory(const char * i_sDirectoryName)1033 int K_CreateDirectory( const char* i_sDirectoryName )
1034 {
1035     // TODO: make this build all parent directories as well.
1036 
1037 #ifdef WIN32
1038     if ( CreateDirectoryA( i_sDirectoryName, NULL ) )
1039     {
1040         return 0;
1041     }
1042     else
1043     {
1044         DWORD dwError = GetLastError();
1045         return ( dwError == ERROR_ALREADY_EXISTS ) ? 0 : (dwError ? dwError : -1);
1046     }
1047 #else
1048     if ( mkdir( i_sDirectoryName, S_IRWXU ) == 0 )
1049     {
1050         return 0;
1051     }
1052     else
1053     {
1054         return ( errno == EEXIST ) ? 0 : (errno ? errno : -1);
1055     }
1056 #endif
1057 }
1058 
1059 
1060 /*---------------------------------------------------------------------------
1061  * Function: K_DeleteFile
1062  *
1063  * Description:
1064  *  Deletes the given file.
1065  *
1066  * Input
1067  * -----
1068  *    i_sFilename      Name of file to delete
1069  *
1070  * Output
1071  * ------
1072  *    (none)
1073  *
1074  * Return value        0 on success, errno on failure
1075  *
1076  *--------------------------------------------------------------------------*/
1077 
K_DeleteFile(const char * i_sFilename)1078 int K_DeleteFile( const char* i_sFilename )
1079 {
1080     int bSuccess = 0;
1081 
1082     bSuccess =
1083 #ifdef WIN32
1084         _unlink(
1085 #else
1086         unlink(
1087 #endif
1088             i_sFilename ) == 0;
1089 
1090     return bSuccess ? 0 : errno;
1091 }
1092 
1093 
1094 /*---------------------------------------------------------------------------
1095  * Function: K_ReadFile
1096  *
1097  * Description:
1098  *  Reads from the given file and passes the bytes read back to the output
1099  *  parameter.  The caller must deallocate o_ppFileData using free().
1100  *
1101  * Input
1102  * -----
1103  *    i_sFilename      Name of file from which to read
1104  *
1105  * Output
1106  * ------
1107  *    o_ppFileData     Pointer to bytes read
1108  *
1109  * Return value        Number of bytes read on success, -1 on failure
1110  *
1111  *--------------------------------------------------------------------------*/
1112 
K_ReadFile(const char * i_sFilename,unsigned char ** o_ppFileData)1113 int K_ReadFile( const char* i_sFilename, unsigned char** o_ppFileData )
1114 {
1115     FILE* pFile = 0;
1116     long iFileSize = 0;
1117 
1118     if ( !i_sFilename || (strlen(i_sFilename) <= 0) || !o_ppFileData )
1119     {
1120         return -1;
1121     }
1122 
1123     *o_ppFileData = 0;
1124 
1125     // Open the file
1126 
1127     pFile = fopen( i_sFilename, "rb" );
1128     if ( !pFile )
1129     {
1130         return -1;
1131     }
1132 
1133     // Determine the file size
1134 
1135     if ( fseek( pFile, 0, SEEK_END ) )
1136     {
1137         (void) fclose( pFile );
1138         return -1;
1139     }
1140 
1141     iFileSize = ftell( pFile );
1142     if ( iFileSize < 0 )
1143     {
1144         (void) fclose( pFile );
1145         return -1;
1146     }
1147     else if ( iFileSize == 0 )
1148     {
1149         (void) fclose( pFile );
1150         return 0;
1151     }
1152 
1153     if ( fseek( pFile, 0, SEEK_SET ) )
1154     {
1155         (void) fclose( pFile );
1156         return -1;
1157     }
1158 
1159     *o_ppFileData = (unsigned char*)malloc( iFileSize );
1160     if ( !*o_ppFileData )
1161     {
1162         // Out of memory.
1163         (void) fclose( pFile );
1164         return -1;
1165     }
1166 
1167     if ( iFileSize != (long)fread( *o_ppFileData, 1, iFileSize, pFile ) )
1168     {
1169         free( *o_ppFileData );
1170         *o_ppFileData = 0;
1171         (void) fclose( pFile );
1172         return -1;
1173     }
1174 
1175     (void) fclose( pFile );
1176 
1177     return iFileSize;
1178 }
1179 
1180 
1181 /*---------------------------------------------------------------------------
1182  * Function: K_ReadFileString
1183  *
1184  * Description:
1185  *  Reads from the given file and passes the bytes read back to the output
1186  *  parameter, appending these bytes with a null terminator.  There is no
1187  *  guarantee that there are no non-text characters in the returned "string".
1188  *  The caller must deallocate o_ppFileData using free().
1189  *
1190  * Input
1191  * -----
1192  *    i_sFilename      Name of file from which to read
1193  *
1194  * Output
1195  * ------
1196  *    o_psFileDataString     Pointer to bytes read
1197  *
1198  * Return value        Number of bytes read (including null terminator) on
1199  *                     success (0 if file is empty), -1 on failure
1200  *
1201  *--------------------------------------------------------------------------*/
1202 
K_ReadFileString(const char * i_sFilename,char ** o_psFileDataString)1203 int K_ReadFileString( const char* i_sFilename, char** o_psFileDataString )
1204 {
1205     unsigned char* pFileData = 0;
1206     int iFileSize = 0;
1207 
1208     *o_psFileDataString = 0;
1209 
1210     iFileSize = K_ReadFile( i_sFilename, &pFileData );
1211 
1212     if ( iFileSize <= 0 )
1213     {
1214         return iFileSize;
1215     }
1216 
1217     *o_psFileDataString = (char*)malloc( iFileSize+1 );
1218 
1219     if ( !*o_psFileDataString )
1220     {
1221         // Out of memory.
1222         if ( pFileData )
1223         {
1224             free( pFileData );
1225         }
1226         return -1;
1227     }
1228 
1229     memcpy( *o_psFileDataString, pFileData, iFileSize );
1230 
1231     (*o_psFileDataString)[iFileSize] = '\0';
1232 
1233     if ( pFileData )
1234     {
1235         free( pFileData );
1236     }
1237 
1238     return iFileSize+1;
1239 }
1240 
1241 
1242 /*---------------------------------------------------------------------------
1243  * Function: K_WriteFile
1244  *
1245  * Description:
1246  *  Writes the given bytes to the given file.
1247  *
1248  * Input
1249  * -----
1250  *    i_sFilename      Name of file to which to write
1251  *    i_pFileData      Bytes to write
1252  *    i_iFileDataSize  Number of bytes to write
1253  *
1254  * Output
1255  * ------
1256  *    (none)
1257  *
1258  * Return value        0 on success, errno or -1 (generic error) on failure
1259  *
1260  *--------------------------------------------------------------------------*/
1261 
K_WriteFile(const char * i_sFilename,const unsigned char * i_pFileData,int i_iFileDataSize)1262 int K_WriteFile( const char* i_sFilename, const unsigned char* i_pFileData, int i_iFileDataSize )
1263 {
1264     FILE* pFile = 0;
1265 
1266     if ( !i_sFilename || (strlen(i_sFilename) <= 0) || (!i_pFileData && (i_iFileDataSize > 0)) || (i_iFileDataSize < 0) )
1267     {
1268         return -1;
1269     }
1270 
1271     pFile = fopen( i_sFilename, "wb" );
1272     if ( !pFile )
1273     {
1274         int iError = errno;
1275         return (iError != 0) ? iError : -1;
1276     }
1277 
1278     if ( i_iFileDataSize > 0 )
1279     {
1280         if ( i_iFileDataSize != (int)fwrite( i_pFileData, 1, i_iFileDataSize, pFile ) )
1281         {
1282             int iError = ferror( pFile );
1283             (void) fclose( pFile );
1284             return (iError != 0) ? iError : -1;
1285         }
1286     }
1287 
1288     (void) fclose( pFile );
1289 
1290     return 0;
1291 }
1292 
1293 
1294 /*---------------------------------------------------------------------------
1295  * Function: K_WriteFileString
1296  *
1297  * Description:
1298  *  Writes the given null-terminated bytes to the given file.  The null
1299  *  terminator itself is not written to the file.
1300  *
1301  * Input
1302  * -----
1303  *    i_sFilename      Name of file to which to write
1304  *    i_sFileData      Bytes to write
1305  *
1306  * Output
1307  * ------
1308  *    (none)
1309  *
1310  * Return value        0 on success, errno or -1 (generic error) on failure
1311  *
1312  *--------------------------------------------------------------------------*/
1313 
K_WriteFileString(const char * i_sFilename,const char * i_sFileData)1314 int K_WriteFileString( const char* i_sFilename, const char* i_sFileData )
1315 {
1316     if ( !i_sFilename || (strlen(i_sFilename) <= 0) || !i_sFileData || (strlen(i_sFileData) <= 0) )
1317     {
1318         return -1;
1319     }
1320 
1321     return K_WriteFile( i_sFilename, (const unsigned char*)i_sFileData, strlen(i_sFileData) );
1322 }
1323 
1324 
1325 /*---------------------------------------------------------------------------
1326  * Function: K_FileExists
1327  *
1328  * Description:
1329  *  Checks to see whehter the given file exists.
1330  *
1331  * Input
1332  * -----
1333  *    i_sFilename      Name of file to check
1334  *
1335  * Output
1336  * ------
1337  *    (none)
1338  *
1339  * Return value        1 if file exists, 0 if not, -1 on failure
1340  *
1341  *--------------------------------------------------------------------------*/
1342 
K_FileExists(const char * i_sFilename)1343 int K_FileExists( const char* i_sFilename )
1344 {
1345     FILE* pFile = 0;
1346 
1347     if ( !i_sFilename || (strlen(i_sFilename) <= 0) )
1348     {
1349         return -1;
1350     }
1351 
1352     pFile = fopen( i_sFilename, "r+" );
1353 
1354     if ( !pFile )
1355     {
1356         if ( errno == ENOENT )
1357         {
1358             return 0;
1359         }
1360 
1361         return -1;
1362     }
1363 
1364     (void) fclose( pFile );
1365 
1366     return 1;
1367 }
1368 
1369 
1370 /*---------------------------------------------------------------------------
1371  * Function: K_CopyFile
1372  *
1373  * Description:
1374  *  Reads from the given source file and writes these bytes to the given
1375  *  destination file.
1376  *
1377  * Input
1378  * -----
1379  *    i_sSrcFilename   Name of file from which to read
1380  *    i_sDestFilename  Name of file to which to write
1381  *
1382  * Output
1383  * ------
1384  *    o_pbFileExists   Non-zero if the destination file already exists
1385  *
1386  * Return value        0 on success, errno or -1 (generic error) on failure
1387  *
1388  *--------------------------------------------------------------------------*/
1389 
K_CopyFile(const char * i_sSrcFilename,const char * i_sDestFilename,int * o_pbFileExists)1390 int K_CopyFile( const char* i_sSrcFilename, const char* i_sDestFilename, int* o_pbFileExists )
1391 {
1392     unsigned char* pFileData = 0;
1393     int iFileSize = 0;
1394     int iError, iFileExists;
1395 
1396     if ( !i_sSrcFilename || (strlen(i_sSrcFilename) <= 0)
1397          || !i_sDestFilename || (strlen(i_sDestFilename) <= 0)
1398          || !o_pbFileExists )
1399     {
1400         return -1;
1401     }
1402 
1403     *o_pbFileExists = 0;
1404 
1405     iFileExists = K_FileExists( i_sDestFilename );
1406 
1407     if ( iFileExists < 0 )
1408     {
1409         iError = errno;
1410         return (iError == 0) ? -1 : iError;
1411     }
1412     else if ( iFileExists > 0 )
1413     {
1414         *o_pbFileExists = 1;
1415         return -1;
1416     }
1417 
1418     iFileSize = K_ReadFile( i_sSrcFilename, &pFileData );
1419     if ( iFileSize < 0 )
1420     {
1421         iError = errno;
1422         return (iError == 0) ? -1 : iError;
1423     }
1424 
1425     iError = K_WriteFile( i_sDestFilename, pFileData, iFileSize );
1426 
1427     if ( pFileData )
1428     {
1429         free( pFileData );
1430     }
1431 
1432     return iError;
1433 }
1434 
1435 
1436 #ifdef K_LINUX_PLATFORM
fts_compare(const FTSENT ** i_ppF1,const FTSENT ** i_ppF2)1437 static int fts_compare( const FTSENT** i_ppF1, const FTSENT** i_ppF2 )
1438 {
1439     return strcmp( (*i_ppF1)->fts_name, (*i_ppF2)->fts_name );
1440 }
1441 #else
1442 /*
1443  * Directory traversal code is not yet available for Solaris.
1444  * If such code will need to be written, then it will probably use ftw.h.
1445  */
1446 #endif
1447 
1448 
1449 /*
1450  *  TODO:  Set up functions for platform-specific find-file operations to
1451  *  help clean up the code below.
1452  */
1453 
1454 typedef struct K_FindInfo
1455 {
1456 #ifdef WIN32
1457     struct _finddata_t m_stFindData;
1458     long m_hFile;
1459 #elif defined K_LINUX_PLATFORM
1460     FTS* m_pFTS;
1461     FTSENT* m_pFTSENT;
1462 #else
1463 /*
1464  * Directory traversal code is not yet available for Solaris.
1465  * If such code will need to be written, then it will probably use ftw.h.
1466  */
1467     int unused;
1468 #endif
1469 } K_FindInfo;
1470 
1471 // Memory for filename is held in i_pFindInfo.
K_GetFilenameFromInfo(const K_FindInfo * i_pFindInfo)1472 const char* K_GetFilenameFromInfo( const K_FindInfo* i_pFindInfo )
1473 {
1474     if( !i_pFindInfo )
1475     {
1476         return 0;
1477     }
1478 
1479 #ifdef WIN32
1480     return i_pFindInfo->m_stFindData.name;
1481 #elif defined K_LINUX_PLATFORM
1482     return i_pFindInfo->m_pFTSENT->fts_name;
1483 #else
1484 /*
1485  * Directory traversal code is not yet available for Solaris.
1486  * If such code will need to be written, then it will probably use ftw.h.
1487  */
1488     FATAL_ASSERT( 0 );
1489     return 0;
1490 #endif
1491 }
1492 
1493 // Forward declarations
1494 int K_FindFileNext( K_FindInfo* io_pFindInfo );
1495 void K_FindFileClose( K_FindInfo* io_pFindInfo );
1496 
1497 // Returns 0 if successful, 1 if not found, -1 if error.
1498 // If not error, K_FindFileClose must be called.
1499 // o_pFindInfo must not be null.
K_FindFileFirst(const char * i_sDirectoryName,K_FindInfo * o_pFindInfo)1500 int K_FindFileFirst( const char* i_sDirectoryName, K_FindInfo* o_pFindInfo )
1501 {
1502 #ifdef WIN32
1503     char* sSearchString = 0;
1504     int iSearchStringIndex = 0;
1505 #endif
1506 
1507     if ( !i_sDirectoryName || (strlen(i_sDirectoryName) <= 0) || !o_pFindInfo )
1508     {
1509         return -1;
1510     }
1511 
1512 #ifdef WIN32
1513     memset( o_pFindInfo, 0, sizeof(K_FindInfo) );
1514 
1515     iSearchStringIndex = strlen(i_sDirectoryName);
1516     if ( i_sDirectoryName[iSearchStringIndex-1] == PATH_SEPARATOR )
1517     {
1518         iSearchStringIndex += 2;
1519     }
1520     else
1521     {
1522         iSearchStringIndex += 3;
1523     }
1524 
1525     sSearchString = (char*)calloc( iSearchStringIndex, 1 );
1526     if ( !sSearchString )
1527     {
1528         return -1;
1529     }
1530 
1531     strcpy( sSearchString, i_sDirectoryName );
1532     iSearchStringIndex--;
1533     sSearchString[iSearchStringIndex] = '\0';
1534     iSearchStringIndex--;
1535     sSearchString[iSearchStringIndex] = '*';
1536     iSearchStringIndex--;
1537     sSearchString[iSearchStringIndex] = PATH_SEPARATOR;
1538 
1539     o_pFindInfo->m_hFile = _findfirst( sSearchString, &o_pFindInfo->m_stFindData );
1540     free( sSearchString );
1541     if ( o_pFindInfo->m_hFile == -1 )
1542     {
1543         if ( errno == ENOENT )
1544         {
1545             return 1;
1546         }
1547         else
1548         {
1549             return -1;
1550         }
1551     }
1552 #elif defined K_LINUX_PLATFORM
1553     memset( o_pFindInfo, 0, sizeof(K_FindInfo) );
1554 
1555     o_pFindInfo->m_pFTS = fts_open( aPath, FTS_PHYSICAL | FTS_NOSTAT, fts_compare );
1556     if ( !o_pFindInfo->m_pFTS )
1557     {
1558         return -1;
1559     }
1560 
1561     o_pFindInfo->m_pFTSENT = fts_read( o_pFindInfo->m_pFTS );
1562     if ( !o_pFindInfo->m_pFTSENT )
1563     {
1564         if ( errno == 0 )
1565         {
1566             return 1;
1567         }
1568         else
1569         {
1570             fts_close( o_pFindInfo->m_pFTS );
1571             return -1;
1572         }
1573     }
1574 #else
1575 /*
1576  * Directory traversal code is not yet available for Solaris.
1577  * If such code will need to be written, then it will probably use ftw.h.
1578  */
1579 #endif
1580 
1581     // If what we found is not actually a file, get the next hit.
1582 #ifdef WIN32
1583     if ( (o_pFindInfo->m_stFindData.attrib & _A_SUBDIR) )
1584 #elif defined K_LINUX_PLATFORM
1585     if ( !(o_pFindInfo->m_pFTSENT->fts_info & FTS_F) )
1586 #else
1587 /*
1588  * Directory traversal code is not yet available for Solaris.
1589  * If such code will need to be written, then it will probably use ftw.h.
1590  */
1591 #endif
1592     {
1593         int iNextReturn = K_FindFileNext( o_pFindInfo );
1594         if ( iNextReturn < 0 )
1595         {
1596             K_FindFileClose( o_pFindInfo );
1597             return -1;
1598         }
1599         else
1600         {
1601             return iNextReturn;
1602         }
1603     }
1604 
1605 #if defined(WIN32) || defined(K_LINUX_PLATFORM)
1606     return 0;
1607 #endif
1608 }
1609 
1610 // Returns 0 if successful, 1 if not found, -1 if error.
K_FindFileNext(K_FindInfo * io_pFindInfo)1611 int K_FindFileNext( K_FindInfo* io_pFindInfo )
1612 {
1613     if ( !io_pFindInfo )
1614     {
1615         return -1;
1616     }
1617 
1618 #ifdef WIN32
1619     if ( _findnext( io_pFindInfo->m_hFile, &io_pFindInfo->m_stFindData ) != 0 )
1620     {
1621         return (errno == ENOENT) ? 1 : -1;
1622     }
1623 #elif defined K_LINUX_PLATFORM
1624     io_pFindInfo->m_pFTSENT = fts_read( io_pFindInfo->m_pFTS );
1625     if ( !io_pFindInfo->m_pFTSENT )
1626     {
1627         return (errno == 0) ? 1 : -1;
1628     }
1629 #else
1630 /*
1631  * Directory traversal code is not yet available for Solaris.
1632  * If such code will need to be written, then it will probably use ftw.h.
1633  */
1634 #endif
1635 
1636     // If what we found is not actually a file, get the next hit.
1637 #ifdef WIN32
1638     if ( (io_pFindInfo->m_stFindData.attrib & _A_SUBDIR) )
1639 #elif defined K_LINUX_PLATFORM
1640     if ( !(io_pFindInfo->m_pFTSENT->fts_info & FTS_F) )
1641 #else
1642 /*
1643  * Directory traversal code is not yet available for Solaris.
1644  * If such code will need to be written, then it will probably use ftw.h.
1645  */
1646 #endif
1647     {
1648         return K_FindFileNext( io_pFindInfo );
1649     }
1650 
1651 #if defined(WIN32) || defined(K_LINUX_PLATFORM)
1652     return 0;
1653 #endif
1654 }
1655 
K_FindFileClose(K_FindInfo * io_pFindInfo)1656 void K_FindFileClose( K_FindInfo* io_pFindInfo )
1657 {
1658     if ( !io_pFindInfo )
1659     {
1660         return;
1661     }
1662 
1663 #ifdef WIN32
1664     _findclose( io_pFindInfo->m_hFile );
1665 #elif defined K_LINUX_PLATFORM
1666     fts_close( io_pFindInfo->m_pFTS );
1667 #else
1668 /*
1669  * Directory traversal code is not yet available for Solaris.
1670  * If such code will need to be written, then it will probably use ftw.h.
1671  */
1672 #endif
1673 }
1674 
1675 
1676 /*---------------------------------------------------------------------------
1677  * Function: K_GetFilenamesInDirectoryCount
1678  *
1679  * Description:
1680  *  Reads the given directory and returns the number of files that it contains.
1681  *
1682  * Input
1683  * -----
1684  *    i_sDirectoryName  Name of directory
1685  *
1686  * Output
1687  * ------
1688  *    (none)
1689  *
1690  * Return value        Number of files on success, -1 on failure
1691  *
1692  *--------------------------------------------------------------------------*/
1693 
K_GetFilenamesInDirectoryCount(const char * i_sDirectoryName)1694 int K_GetFilenamesInDirectoryCount( const char* i_sDirectoryName )
1695 {
1696     K_FindInfo stFindInfo;
1697     int iCurrentFile = 0;
1698     int iError = 0;
1699 
1700     if ( !i_sDirectoryName || (strlen(i_sDirectoryName) <= 0) )
1701     {
1702         return -1;
1703     }
1704 
1705     iError = K_FindFileFirst( i_sDirectoryName, &stFindInfo );
1706     if ( iError < 0 )
1707     {
1708         // error
1709         return -1;
1710     }
1711     else if ( iError > 0 )
1712     {
1713         // no files found
1714         K_FindFileClose( &stFindInfo );
1715         return 0;
1716     }
1717 
1718     while ( 1 )
1719     {
1720         iCurrentFile++;
1721 
1722         iError = K_FindFileNext( &stFindInfo );
1723         if ( iError < 0 )
1724         {
1725             // error
1726             K_FindFileClose( &stFindInfo );
1727             return -1;
1728         }
1729         else if ( iError > 0 )
1730         {
1731             // no more files found
1732             break;
1733         }
1734     }
1735 
1736     K_FindFileClose( &stFindInfo );
1737 
1738     return iCurrentFile;
1739 }
1740 
1741 
1742 /*---------------------------------------------------------------------------
1743  * Function: K_GetFilenamesInDirectory
1744  *
1745  * Description:
1746  *  Reads the given directory and returns an array of names of files that it
1747  *  contains.  A null pointer appears at the last item in the array.  The
1748  *  caller must deallocate o_pasFilenames by using K_FreeFilenames or by
1749  *  calling free() for each file name and then calling free() on the array
1750  *  itself.
1751  *
1752  * Input
1753  * -----
1754  *    i_sDirectoryName  Name of directory
1755  *
1756  * Output
1757  * ------
1758  *    o_pasFilenames   Array of names of files found in this directory
1759  *
1760  * Return value        Number of files on success, -1 on failure
1761  *
1762  *--------------------------------------------------------------------------*/
1763 
K_GetFilenamesInDirectory(const char * i_sDirectoryName,char *** o_pasFilenames)1764 int K_GetFilenamesInDirectory(
1765         const char* i_sDirectoryName,
1766         char*** o_pasFilenames )
1767 {
1768     // Note that we iterate through the filenames twice -- once to get the count
1769     // (K_GetFilenamesInDirectoryCount) and then once to get all the names. But
1770     // it may happen that the count changes between these calls.  So we'll retrieve
1771     // at most the number of files that's returned in the first pass.
1772 
1773     K_FindInfo stFindInfo;
1774     int iFilenameCount = 0, iCurrentFile = 0;
1775     int iError = 0;
1776 
1777     if ( !i_sDirectoryName || (strlen(i_sDirectoryName) <= 0) || !o_pasFilenames )
1778     {
1779         return -1;
1780     }
1781 
1782     *o_pasFilenames = 0;
1783 
1784     iFilenameCount = K_GetFilenamesInDirectoryCount( i_sDirectoryName );
1785 
1786     if ( iFilenameCount < 0 )
1787     {
1788         return -1;
1789     }
1790 
1791     iError = K_FindFileFirst( i_sDirectoryName, &stFindInfo );
1792     if ( iError < 0 )
1793     {
1794         // error
1795         return -1;
1796     }
1797     else if ( iError > 0 )
1798     {
1799         // No files found
1800         K_FindFileClose( &stFindInfo );
1801         return 0;
1802     }
1803 
1804     *o_pasFilenames = (char**)calloc( (iFilenameCount+1), sizeof(char*) );    // +1 for the null last one
1805     if ( !*o_pasFilenames )
1806     {
1807         // Out of memory
1808         K_FindFileClose( &stFindInfo );
1809         return -1;
1810     }
1811 
1812     while ( 1 )
1813     {
1814         const char* sFilename = K_GetFilenameFromInfo( &stFindInfo );
1815 
1816         size_t iFilenameLength = sFilename ? strlen( sFilename ) : 0;
1817 
1818         if ( iFilenameLength <= 0 )
1819         {
1820             K_FreeFilenames( *o_pasFilenames );
1821             K_FindFileClose( &stFindInfo );
1822             return -1;
1823         }
1824 
1825         (*o_pasFilenames)[iCurrentFile] = (char*)calloc( (iFilenameLength+1), sizeof(char) );
1826         if ( !(*o_pasFilenames)[iCurrentFile] )
1827         {
1828             K_FreeFilenames( *o_pasFilenames );
1829             K_FindFileClose( &stFindInfo );
1830             return -1;
1831         }
1832 
1833         strncpy( (*o_pasFilenames)[iCurrentFile], sFilename, iFilenameLength );
1834         (*o_pasFilenames)[iCurrentFile][iFilenameLength] = '\0';
1835 
1836         iCurrentFile++;
1837 
1838         if ( iCurrentFile >= iFilenameCount )
1839         {
1840             break;
1841         }
1842 
1843         iError = K_FindFileNext( &stFindInfo );
1844         if ( iError < 0 )
1845         {
1846             // error
1847             K_FindFileClose( &stFindInfo );
1848             return -1;
1849         }
1850         else if ( iError > 0 )
1851         {
1852             // no more files found
1853             break;
1854         }
1855     }
1856 
1857     K_FindFileClose( &stFindInfo );
1858 
1859     return iCurrentFile;
1860 }
1861 
1862 
1863 /*---------------------------------------------------------------------------
1864  * Function: K_FreeFilenames
1865  *
1866  * Description:
1867  *  Deallocates the memory allocated in a successful call to
1868  *  K_GetFilenamesInDirectory.
1869  *
1870  * Input
1871  * -----
1872  *    i_asFilenames    Array of names of files
1873  *
1874  * Output
1875  * ------
1876  *    (none)
1877  *
1878  * Return value        (none)
1879  *
1880  *--------------------------------------------------------------------------*/
1881 
K_FreeFilenames(char ** i_asFilenames)1882 void K_FreeFilenames( char** i_asFilenames )
1883 {
1884     int i;
1885 
1886     if ( !i_asFilenames )
1887     {
1888         return;
1889     }
1890 
1891     for ( i = 0; (i_asFilenames[i] != 0); i++ )
1892     {
1893         free( i_asFilenames[i] );
1894         i_asFilenames[i] = 0;
1895     }
1896 
1897     free( i_asFilenames );
1898 }
1899 
1900 
1901 /*---------------------------------------------------------------------------
1902  * Function: K_AdjustLocalClock
1903  *
1904  * Description:
1905  *  The K_AdjustLocalClock function gradually adjusts the system clock by
1906  *  the given number of seconds.  A positive number adjusts the system
1907  *  clock forward; a negative number adjusts the system clock backward.
1908  *
1909  * Input
1910  * -----
1911  *    i_iAdjustmentInSeconds   Number of seconds by which to adjust the
1912  *                             system clock
1913  * Output
1914  * ------
1915  *    (none)
1916  *
1917  * Return value        1 if successful, 0 on error
1918  *
1919  *--------------------------------------------------------------------------*/
1920 
K_AdjustLocalClock(int i_iNumberOfSeconds)1921 int K_AdjustLocalClock( int i_iNumberOfSeconds )
1922 {
1923     struct timeval delta, lastchange;
1924 
1925 #ifndef K_SOLARIS_PLATFORM
1926     /* Only supported/tested on Solaris at the moment */
1927 
1928     return -1;
1929 #else
1930     /* WARNING: uses standard C time functions with Year 2038 limitations */
1931     time_t now;
1932 
1933     if ( (now = time(NULL)) == ((time_t)-1) )
1934     {
1935         return -1;
1936     }
1937 
1938     delta.tv_sec = i_iNumberOfSeconds;
1939     delta.tv_usec = 0;
1940 
1941     return adjtime(&delta, &lastchange);
1942 #endif
1943 }
1944 
1945 
1946 #ifdef K_SOLARIS_PLATFORM
pam_tty_conv(int num_msg,struct pam_message ** mess,struct pam_response ** resp,void * my_data)1947 static int pam_tty_conv(
1948     int num_msg,
1949     struct pam_message** mess,
1950     struct pam_response** resp,
1951     void* my_data)
1952 {
1953     // Following code implements a console-based PAM "conversation" function
1954     // (based sample code from Solaris 10 Software Developer Collection >>
1955     // Solaris Security for Developers Guide >>
1956     // 3.  Writing PAM Applications and Services)
1957 
1958     struct pam_message* m = *mess;
1959     struct pam_response* r;
1960     int i, j;
1961     const char* sPassword = (const char*)my_data;
1962     int error = PAM_CONV_ERR;
1963 
1964     if (num_msg <= 0 || num_msg >= PAM_MAX_NUM_MSG)
1965     {
1966         (void) fprintf(stderr, "PAM error: bad number of messages");
1967         *resp = NULL;
1968         return (PAM_CONV_ERR);
1969     }
1970 
1971     if ((*resp = r = calloc(num_msg, sizeof (struct pam_response))) == NULL)
1972     {
1973         return (PAM_BUF_ERR);
1974     }
1975 
1976     // Loop through messages
1977     for (i = 0; i < num_msg; i++) {
1978 
1979         // bad message from service module
1980         if (m->msg == NULL)
1981         {
1982             (void) fprintf(stderr, "PAM error: bad message");
1983             goto err;
1984         }
1985 
1986         // fix up final newline: removed for prompts, added back for messages
1987         if (m->msg[strlen(m->msg)] == '\n')
1988         {
1989             m->msg[strlen(m->msg)] = '\0';
1990         }
1991 
1992         // Since the KMA has its own password prompts and enforces its own rule checks, we already have the
1993         // new password in memory.  So instead of displaying PAM prompts and collecting user responses, we
1994         // "automate" by assuming that the prompts correspond to the standard sequence of "New password:"
1995         // followed by "Confirm password:" and so in each case we immediately return the password we already
1996         // have in memory.  This violates the PAM "conversation" function instructions (which say, basically,
1997         // not to assume any particular sequence of prompts since there could be any number of underlying
1998         // password managers), but since the KMA is running on an appliance with a fixed password manager,
1999         // our assumptions should hold.
2000 
2001         r->resp = NULL;
2002         r->resp_retcode = 0;
2003         switch (m->msg_style)
2004         {
2005         case PAM_PROMPT_ECHO_OFF:
2006         case PAM_PROMPT_ECHO_ON:
2007             // Assume the prompt asked for New/Confirm password, so return password.
2008             if ( (r->resp = strdup(sPassword)) == NULL )
2009             {
2010                 error = PAM_BUF_ERR;
2011                 goto err;
2012             }
2013             break;
2014 
2015         case PAM_ERROR_MSG:
2016             // Assuming the system is configured properly and the KMA password prompts enforce password strength rules,
2017             // there should not be errors because of weak passwords, etc.  Still, print errors so users/support can
2018             // diagnose problems.
2019             (void) fputs(m->msg, stderr);
2020             (void) fputc('\n', stderr);
2021             break;
2022 
2023         case PAM_TEXT_INFO:
2024             // Supress prompts (again, making assumptions).
2025             break;
2026 
2027         default:
2028             (void) fprintf(stderr, "PAM error: unknown message");
2029             goto err;
2030         }
2031         if (errno == EINTR)
2032         {
2033             goto err;
2034         }
2035 
2036         // next message/response
2037         m++;
2038         r++;
2039     }
2040     return (PAM_SUCCESS);
2041 
2042 err:
2043     // Service modules do not clean up responses if an error is returned.
2044     // Free responses here.
2045     for (j = 0; j < i; j++, r++)
2046     {
2047         if (r->resp)
2048         {
2049             // clear before freeing -- may be a password
2050             bzero(r->resp, strlen(r->resp));
2051             free(r->resp);
2052             r->resp = NULL;
2053         }
2054     }
2055     free(r);
2056     *resp = NULL;
2057     return error;
2058 }
2059 #endif
2060 
2061 
2062 /*---------------------------------------------------------------------------
2063  * Function: K_SetRootPassword
2064  *
2065  * Description:
2066  *  The K_SetRootPassword function sets the password for the root user via
2067  *  Pluggable Authentication Module (PAM).  This function is interactive.
2068  *
2069  * Input
2070  * -----
2071  *    i_sPassword      Password to set
2072  *
2073  * Output
2074  * ------
2075  *    (none)
2076  *
2077  * Return value        0 if successful, -1 on error
2078  *
2079  *--------------------------------------------------------------------------*/
2080 
K_SetRootPassword(const char * i_sPassword)2081 int K_SetRootPassword( const char* i_sPassword )
2082 {
2083     // Only supported/tested on Solaris at the moment
2084 #ifndef K_SOLARIS_PLATFORM
2085     return -1;
2086 #else
2087     // Based on sample code from Solaris 10 Software Developer Collection >>
2088     // Solaris Security for Developers Guide >>
2089     // 3. Writing PAM Applications and Services
2090 
2091     // TODO: Return PAM error codes (to be logged) instead of emitting
2092     // messages to screen?
2093 
2094     struct pam_conv conv;
2095     pam_handle_t *pamh;
2096     int err;
2097 
2098     conv.conv = pam_tty_conv;
2099     conv.appdata_ptr = (void*)i_sPassword;
2100 
2101     // Initialize PAM framework
2102     err = pam_start("KeyMgr", "root", &conv, &pamh);
2103     if (err != PAM_SUCCESS)
2104     {
2105         fprintf(stderr, "PAM error: %s\n", pam_strerror(pamh, err));
2106         return -1;
2107     }
2108 
2109     // Change password
2110     err = pam_chauthtok(pamh, 0);
2111     if (err != PAM_SUCCESS)
2112     {
2113         fprintf(stderr, "PAM error: %s\n", pam_strerror(pamh, err));
2114         // fall through to cleanup
2115     }
2116 
2117     // Cleanup session
2118     pam_end(pamh, 0);
2119 
2120     return (err == PAM_SUCCESS) ? 0 : -1;
2121 #endif
2122 }
2123 
2124 
2125 /*---------------------------------------------------------------------------
2126  * Function: K_Alarm
2127  *
2128  * Description:
2129  *  Calls alarm(2) on Unix in order to cause the operating system to generate
2130  *  a SIGALRM signal for this process after the given number of real-time
2131  *  seconds.  Does nothing on Windows.
2132  *
2133  * Input
2134  * -----
2135  *    i_iSeconds       Number of seconds after which to generate a SIGALRM
2136  *                     signal
2137  *
2138  * Output
2139  * ------
2140  *    (none)
2141  *
2142  * Return value        If a previous alarm request is pending, then it returns
2143  *                     the number of seconds until this previous request would
2144  *                     have generated a SIGALRM signal.  Otherwise, returns 0.
2145  *
2146  *--------------------------------------------------------------------------*/
2147 
K_Alarm(unsigned int i_iSeconds)2148 unsigned int K_Alarm( unsigned int i_iSeconds )
2149 {
2150 #ifndef WIN32
2151     return alarm( i_iSeconds );
2152 #else
2153     return 0;
2154 #endif
2155 }
2156 
2157 
2158 /*---------------------------------------------------------------------------
2159  * Function: K_GetExtendedVersionFromBase
2160  *
2161  * Description:
2162  *  This KMS-specific function prepends the timestamp value to the specified
2163  *  base replication schema version and returns this value as an extended
2164  *  replication schema version.
2165  *
2166  * Input
2167  * -----
2168  *    i_iBaseSchemaVersion  Base replication schema version
2169  *
2170  * Output
2171  * ------
2172  *    (none)
2173  *
2174  * Return value        Extended replication schema version
2175  *
2176  *--------------------------------------------------------------------------*/
2177 
K_GetExtendedVersionFromBase(unsigned int i_iBaseSchemaVersion)2178 unsigned int K_GetExtendedVersionFromBase( unsigned int i_iBaseSchemaVersion )
2179 {
2180     // seconds since 1970, force to 32-bit
2181 #ifdef WIN32
2182     INT32 iTimeStamp = (INT32) time(NULL);
2183 #else
2184     int32_t iTimeStamp = (int32_t) time(NULL);
2185 #endif
2186     // minutes since 1970
2187     iTimeStamp = iTimeStamp / 60;
2188     // minutes since 2000 (approximately)
2189     iTimeStamp -= (30*365*24*60);
2190     // shift 8 bits to clear out room for schema version #
2191     iTimeStamp = iTimeStamp << 8;
2192     // add schema version # to lower end
2193     iTimeStamp |= i_iBaseSchemaVersion;
2194 
2195     return (unsigned int) iTimeStamp;
2196 
2197 }
2198 
2199 
2200 /*---------------------------------------------------------------------------
2201  * Function: K_ParseTimestampFromExtendedVersion
2202  *
2203  * Description:
2204  *  This KMS-specific function parses the timestamp value from the given
2205  *  extended replication schema version and returns this timestamp value.
2206  *
2207  * Input
2208  * -----
2209  *    i_iExtendedSchemaVersion  Extended replication schema version
2210  *
2211  * Output
2212  * ------
2213  *    (none)
2214  *
2215  * Return value        Timestamp value
2216  *
2217  *--------------------------------------------------------------------------*/
2218 
K_ParseTimestampFromExtendedVersion(unsigned int i_iExtendedSchemaVersion)2219 unsigned int K_ParseTimestampFromExtendedVersion(
2220     unsigned int i_iExtendedSchemaVersion )
2221 {
2222     unsigned int iTimeStamp = i_iExtendedSchemaVersion >> 8;
2223 
2224     return iTimeStamp;
2225 }
2226 
2227 
2228 /*---------------------------------------------------------------------------
2229  * Function: K_ParseBaseFromExtendedVersion
2230  *
2231  * Description:
2232  *  This KMS-specific function parses the base replication schema value from
2233  *  the given extended replication schema version and returns this base value.
2234  *
2235  * Input
2236  * -----
2237  *    i_iExtendedSchemaVersion  Extended replication schema version
2238  *
2239  * Output
2240  * ------
2241  *    (none)
2242  *
2243  * Return value        Base replication schema value
2244  *
2245  *--------------------------------------------------------------------------*/
2246 
K_ParseBaseFromExtendedVersion(unsigned int i_iExtendedSchemaVersion)2247 unsigned int K_ParseBaseFromExtendedVersion(
2248     unsigned int i_iExtendedSchemaVersion )
2249 {
2250     unsigned int iBaseSchemaVersion = i_iExtendedSchemaVersion & 0x000000FF;
2251 
2252     return iBaseSchemaVersion;
2253 }
2254 
2255 
2256 /*---------------------------------------------------------------------------
2257  * Function: K_System
2258  *
2259  * Description:
2260  *  This function is a thread-safe replacement for the unsafe system(3C) call.
2261  *  See the popen(3C) man page for more information.
2262  *
2263  * Input
2264  * -----
2265  *    i_sCmd           Command to execute
2266  *
2267  * Output
2268  * ------
2269  *    (none)
2270  *
2271  * Return value        Termination status of the command language interpreter
2272  *                     if successful, -1 on failure
2273  *
2274  *--------------------------------------------------------------------------*/
2275 
K_System(const char * i_sCmd)2276 int K_System( const char *i_sCmd )
2277 {
2278 #ifndef WIN32
2279         FILE *p;
2280         int rc;
2281         struct sigaction sOldAction;
2282 
2283         // Save signal handler
2284         sigaction( SIGCHLD, NULL, &sOldAction );
2285 
2286         // Use default child signal handler
2287         sigset( SIGCHLD, SIG_DFL );
2288 
2289         p = popen( i_sCmd, "w" );
2290         if ( p == NULL )
2291         {
2292             rc = -1;
2293         }
2294         else
2295         {
2296             rc = pclose( p );
2297         }
2298 
2299         // Reset signal handler
2300         sigset( SIGCHLD, sOldAction.sa_handler );
2301 
2302         return rc;
2303 #else
2304         return system( i_sCmd );
2305 #endif
2306 }
2307 
2308