1 /*********************************************************************
2  * Universal NetWare library stub.                                   *
3  * written by Ulrich Neuman and given to OpenSource copyright-free.  *
4  * Extended for CLIB support by Guenter Knauf.                       *
5  *********************************************************************/
6 
7 #ifdef NETWARE /* Novell NetWare */
8 
9 #include <stdlib.h>
10 
11 #ifdef __NOVELL_LIBC__
12 /* For native LibC-based NLM we need to register as a real lib. */
13 #include <errno.h>
14 #include <string.h>
15 #include <library.h>
16 #include <netware.h>
17 #include <screen.h>
18 #include <nks/thread.h>
19 #include <nks/synch.h>
20 
21 typedef struct
22 {
23   int     _errno;
24   void    *twentybytes;
25 } libthreaddata_t;
26 
27 typedef struct
28 {
29   int         x;
30   int         y;
31   int         z;
32   void        *tenbytes;
33   NXKey_t     perthreadkey;   /* if -1, no key obtained... */
34   NXMutex_t   *lock;
35 } libdata_t;
36 
37 int         gLibId      = -1;
38 void        *gLibHandle = (void *) NULL;
39 rtag_t      gAllocTag   = (rtag_t) NULL;
40 NXMutex_t   *gLibLock   = (NXMutex_t *) NULL;
41 
42 /* internal library function prototypes... */
43 int     DisposeLibraryData ( void * );
44 void    DisposeThreadData ( void * );
45 int     GetOrSetUpData ( int id, libdata_t **data, libthreaddata_t **threaddata );
46 
47 
_NonAppStart(void * NLMHandle,void * errorScreen,const char * cmdLine,const char * loadDirPath,size_t uninitializedDataLength,void * NLMFileHandle,int (* readRoutineP)(int conn,void * fileHandle,size_t offset,size_t nbytes,size_t * bytesRead,void * buffer),size_t customDataOffset,size_t customDataSize,int messageCount,const char ** messages)48 int _NonAppStart( void        *NLMHandle,
49                   void        *errorScreen,
50                   const char  *cmdLine,
51                   const char  *loadDirPath,
52                   size_t      uninitializedDataLength,
53                   void        *NLMFileHandle,
54                   int         (*readRoutineP)( int conn,
55                                                void *fileHandle, size_t offset,
56                                                size_t nbytes,
57                                                size_t *bytesRead,
58                                                void *buffer ),
59                   size_t      customDataOffset,
60                   size_t      customDataSize,
61                   int         messageCount,
62                   const char  **messages )
63 {
64   NX_LOCK_INFO_ALLOC(liblock, "Per-Application Data Lock", 0);
65 
66 #ifndef __GNUC__
67 #pragma unused(cmdLine)
68 #pragma unused(loadDirPath)
69 #pragma unused(uninitializedDataLength)
70 #pragma unused(NLMFileHandle)
71 #pragma unused(readRoutineP)
72 #pragma unused(customDataOffset)
73 #pragma unused(customDataSize)
74 #pragma unused(messageCount)
75 #pragma unused(messages)
76 #endif
77 
78 /*
79 ** Here we process our command line, post errors (to the error screen),
80 ** perform initializations and anything else we need to do before being able
81 ** to accept calls into us. If we succeed, we return non-zero and the NetWare
82 ** Loader will leave us up, otherwise we fail to load and get dumped.
83 */
84   gAllocTag = AllocateResourceTag(NLMHandle,
85                    "<library-name> memory allocations", AllocSignature);
86 
87   if (!gAllocTag) {
88     OutputToScreen(errorScreen, "Unable to allocate resource tag for "
89                      "library memory allocations.\n");
90     return -1;
91   }
92 
93   gLibId = register_library(DisposeLibraryData);
94 
95   if (gLibId < -1) {
96     OutputToScreen(errorScreen, "Unable to register library with kernel.\n");
97     return -1;
98   }
99 
100   gLibHandle = NLMHandle;
101 
102   gLibLock = NXMutexAlloc(0, 0, &liblock);
103 
104   if (!gLibLock) {
105     OutputToScreen(errorScreen, "Unable to allocate library data lock.\n");
106     return -1;
107   }
108 
109   return 0;
110 }
111 
112 /*
113 ** Here we clean up any resources we allocated. Resource tags is a big part
114 ** of what we created, but NetWare doesn't ask us to free those.
115 */
_NonAppStop(void)116 void _NonAppStop( void )
117 {
118   (void) unregister_library(gLibId);
119   NXMutexFree(gLibLock);
120 }
121 
122 /*
123 ** This function cannot be the first in the file for if the file is linked
124 ** first, then the check-unload function's offset will be nlmname.nlm+0
125 ** which is how to tell that there isn't one. When the check function is
126 ** first in the linked objects, it is ambiguous. For this reason, we will
127 ** put it inside this file after the stop function.
128 **
129 ** Here we check to see if it's alright to ourselves to be unloaded. If not,
130 ** we return a non-zero value. Right now, there isn't any reason not to allow
131 ** it.
132 */
_NonAppCheckUnload(void)133 int _NonAppCheckUnload( void )
134 {
135   return 0;
136 }
137 
GetOrSetUpData(int id,libdata_t ** appData,libthreaddata_t ** threadData)138 int GetOrSetUpData(int id, libdata_t **appData, libthreaddata_t **threadData)
139 {
140   int              err;
141   libdata_t        *app_data;
142   libthreaddata_t  *thread_data;
143   NXKey_t          key;
144   NX_LOCK_INFO_ALLOC(liblock, "Application Data Lock", 0);
145 
146   err         = 0;
147   thread_data = (libthreaddata_t *) NULL;
148 
149 /*
150 ** Attempt to get our data for the application calling us. This is where we
151 ** store whatever application-specific information we need to carry in support
152 ** of calling applications.
153 */
154   app_data = (libdata_t *) get_app_data(id);
155 
156   if (!app_data) {
157 /*
158 ** This application hasn't called us before; set up application AND per-thread
159 ** data. Of course, just in case a thread from this same application is calling
160 ** us simultaneously, we better lock our application data-creation mutex. We
161 ** also need to recheck for data after we acquire the lock because WE might be
162 ** that other thread that was too late to create the data and the first thread
163 ** in will have created it.
164 */
165     NXLock(gLibLock);
166 
167     if (!(app_data = (libdata_t *) get_app_data(id))) {
168       app_data = (libdata_t *) malloc(sizeof(libdata_t));
169 
170       if (app_data) {
171         memset(app_data, 0, sizeof(libdata_t));
172 
173         app_data->tenbytes = malloc(10);
174         app_data->lock     = NXMutexAlloc(0, 0, &liblock);
175 
176         if (!app_data->tenbytes || !app_data->lock) {
177           if (app_data->lock)
178             NXMutexFree(app_data->lock);
179 
180           free(app_data);
181           app_data = (libdata_t *) NULL;
182           err      = ENOMEM;
183         }
184 
185         if (app_data) {
186 /*
187 ** Here we burn in the application data that we were trying to get by calling
188 ** get_app_data(). Next time we call the first function, we'll get this data
189 ** we're just now setting. We also go on here to establish the per-thread data
190 ** for the calling thread, something we'll have to do on each application
191 ** thread the first time it calls us.
192 */
193           err = set_app_data(gLibId, app_data);
194 
195           if (err) {
196             free(app_data);
197             app_data = (libdata_t *) NULL;
198             err      = ENOMEM;
199           }
200           else {
201             /* create key for thread-specific data... */
202             err = NXKeyCreate(DisposeThreadData, (void *) NULL, &key);
203 
204             if (err)                /* (no more keys left?) */
205               key = -1;
206 
207             app_data->perthreadkey = key;
208           }
209         }
210       }
211     }
212 
213     NXUnlock(gLibLock);
214   }
215 
216   if (app_data) {
217     key = app_data->perthreadkey;
218 
219     if (key != -1 /* couldn't create a key? no thread data */
220         && !(err = NXKeyGetValue(key, (void **) &thread_data))
221         && !thread_data) {
222 /*
223 ** Allocate the per-thread data for the calling thread. Regardless of whether
224 ** there was already application data or not, this may be the first call by a
225 ** a new thread. The fact that we allocation 20 bytes on a pointer is not very
226 ** important, this just helps to demonstrate that we can have arbitrarily
227 ** complex per-thread data.
228 */
229       thread_data = (libthreaddata_t *) malloc(sizeof(libthreaddata_t));
230 
231       if (thread_data) {
232         thread_data->_errno      = 0;
233         thread_data->twentybytes = malloc(20);
234 
235         if (!thread_data->twentybytes) {
236           free(thread_data);
237           thread_data = (libthreaddata_t *) NULL;
238           err         = ENOMEM;
239         }
240 
241         if ((err = NXKeySetValue(key, thread_data))) {
242           free(thread_data->twentybytes);
243           free(thread_data);
244           thread_data = (libthreaddata_t *) NULL;
245         }
246       }
247     }
248   }
249 
250   if (appData)
251     *appData = app_data;
252 
253   if (threadData)
254     *threadData = thread_data;
255 
256   return err;
257 }
258 
DisposeLibraryData(void * data)259 int DisposeLibraryData( void *data )
260 {
261   if (data) {
262     void *tenbytes = ((libdata_t *) data)->tenbytes;
263 
264     if (tenbytes)
265       free(tenbytes);
266 
267     free(data);
268   }
269 
270   return 0;
271 }
272 
DisposeThreadData(void * data)273 void DisposeThreadData( void *data )
274 {
275   if (data) {
276     void *twentybytes = ((libthreaddata_t *) data)->twentybytes;
277 
278     if (twentybytes)
279       free(twentybytes);
280 
281     free(data);
282   }
283 }
284 
285 #else /* __NOVELL_LIBC__ */
286 /* For native CLib-based NLM seems we can do a bit more simple. */
287 #include <nwthread.h>
288 
main(void)289 int main ( void )
290 {
291   /* initialize any globals here... */
292 
293   /* do this if any global initializing was done
294   SynchronizeStart();
295   */
296   ExitThread (TSR_THREAD, 0);
297   return 0;
298 }
299 
300 #endif /* __NOVELL_LIBC__ */
301 
302 #endif /* NETWARE */
303 
304 
305