3341a9568f32745f49b4273ba6f0f79f39ca36fb
[tpg/acess2.git] / AcessNative / ld-acess_src / syscalls.c
1 /*
2  */
3 #define DONT_INCLUDE_SYSCALL_NAMES 1
4 #include "common.h"
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <stdint.h>
8 #include <stdarg.h>
9 #include <string.h>
10 #include <stddef.h>
11 #include <unistd.h>
12 #ifndef __WIN32__
13 # include <spawn.h>     // posix_spawn
14 #endif
15 #include "request.h"
16 #include <sys/time.h>
17
18 #define assert(cnd) do{ \
19         if( !(cnd) ) { \
20                 fprintf(stderr, "%s:%i - assert failed - " #cnd"\n", __FILE__, __LINE__);\
21                 exit(-1); \
22         } \
23 }while(0)
24
25 #define MAX_FPS 16
26
27 // === Types ===
28
29 // === IMPORTS ===
30 extern int      gbSyscallDebugEnabled;
31
32 // === GLOBALS ===
33 FILE    *gaSyscall_LocalFPs[MAX_FPS];
34
35 // === CODE ===
36 const char *ReadEntry(tRequestValue *Dest, void *DataDest, void **PtrDest, const char *ArgTypes, va_list *Args)
37 {
38         uint64_t        val64;
39         uint32_t        val32;
40          int    direction = 0;  // 0: Invalid, 1: Out, 2: In, 3: Out
41         char    *str;
42          int    len;
43
44         // Eat whitespace
45         while(*ArgTypes && *ArgTypes == ' ')    ArgTypes ++;
46         if( *ArgTypes == '\0' ) return ArgTypes;
47         
48 //      DEBUG("ArgTypes = '%s'", ArgTypes);
49         
50         // Get direction
51         switch(*ArgTypes)
52         {
53         default:        // Defaults to output
54         case '>':       direction = 1;  break;
55         case '<':       direction = 2;  break;
56         case '?':       direction = 3;  break;
57         }
58         ArgTypes ++;
59         
60         // Eat whitespace
61         while(*ArgTypes && *ArgTypes == ' ')    ArgTypes ++;
62         if( *ArgTypes == '\0' ) return ArgTypes;
63         
64         // Get type
65         switch(*ArgTypes)
66         {
67         // 32-bit integer
68         case 'i':
69                 
70                 if( direction != 1 ) {
71                         Warning("ReadEntry: Recieving an integer is not defined");
72                         return NULL;
73                 }
74                 
75                 val32 = va_arg(*Args, uint32_t);
76                 
77                 Dest->Type = ARG_TYPE_INT32;
78                 Dest->Length = sizeof(uint32_t);
79                 Dest->Flags = 0;
80                 
81                 if( DataDest )
82                         *(uint32_t*)DataDest = val32;
83                 break;
84         // 64-bit integer
85         case 'I':
86                 
87                 if( direction != 1 ) {
88                         fprintf(stderr, "ReadEntry: Recieving an integer is not defined\n");
89                         return NULL;
90                 }
91                 
92                 val64 = va_arg(*Args, uint64_t);
93                 
94                 Dest->Type = ARG_TYPE_INT64;
95                 Dest->Length = sizeof(uint64_t);
96                 Dest->Flags = 0;
97                 if( DataDest )
98                         *(uint64_t*)DataDest = val64;
99                 break;
100         // String
101         case 's':
102                 // Input string makes no sense!
103                 if( direction != 1 ) {
104                         fprintf(stderr, "ReadEntry: Recieving a string is not defined\n");
105                         return NULL;
106                 }
107                 
108                 str = va_arg(*Args, char*);
109                 
110                 Dest->Type = ARG_TYPE_STRING;
111                 Dest->Length = strlen(str) + 1;
112                 Dest->Flags = 0;
113                 
114                 if( DataDest )
115                 {
116                         memcpy(DataDest, str, Dest->Length);
117                 }
118                 break;
119         // Data (special handling)
120         case 'd':
121                 len = va_arg(*Args, size_t);
122                 str = va_arg(*Args, char*);
123                 
124                 // Save the pointer for later
125                 if( PtrDest )   *PtrDest = str;
126                 
127                 // Create parameter block
128                 Dest->Type = ARG_TYPE_DATA;
129                 Dest->Length = str ? len : 0;
130                 Dest->Flags = 0;
131                 if( direction & 2 )
132                         Dest->Flags |= ARG_FLAG_RETURN;
133                 
134                 // Has data?
135                 if( direction & 1 )
136                 {
137                         if( DataDest && str )
138                                 memcpy(DataDest, str, len);
139                 }
140                 else
141                         Dest->Flags |= ARG_FLAG_ZEROED;
142                 break;
143         
144         default:
145                 return NULL;
146         }
147         ArgTypes ++;
148         
149         return ArgTypes;
150 }
151
152 /**
153  * \param ArgTypes
154  *
155  * Whitespace is ignored
156  * >i:  Input Integer (32-bits)
157  * >I:  Input Long Integer (64-bits)
158  * >s:  Input String
159  * >d:  Input Buffer (Preceded by valid size)
160  * <I:  Output long integer
161  * <d:  Output Buffer (Preceded by valid size)
162  * ?d:  Bi-directional buffer (Preceded by valid size), buffer contents
163  *      are returned
164  */
165 uint64_t _Syscall(int SyscallID, const char *ArgTypes, ...)
166 {
167         va_list args;
168          int    paramCount, dataLength;
169          int    retCount = 2, retLength = sizeof(uint64_t) + sizeof(uint32_t);
170         void    **retPtrs;      // Pointers to return buffers
171         const char      *str;
172         tRequestHeader  *req;
173         void    *dataPtr;
174         uint64_t        retValue;
175         
176         // DEBUG!
177 //      printf("&tRequestHeader->Params = %i\n", offsetof(tRequestHeader, Params));
178 //      printf("&tRequestValue->Flags = %i\n", offsetof(tRequestValue, Flags));
179 //      printf("&tRequestValue->Length = %i\n", offsetof(tRequestValue, Length));
180         
181         // Get data size
182         va_start(args, ArgTypes);
183         str = ArgTypes;
184         paramCount = 0;
185         dataLength = 0;
186         while(*str)
187         {
188                 tRequestValue   tmpVal;
189                 
190                 str = ReadEntry(&tmpVal, NULL, NULL, str, &args);
191                 if( !str ) {
192                         fprintf(stderr, "syscalls.c: ReadEntry failed (SyscallID = %i)\n", SyscallID);
193                         exit(127);
194                 }
195                 paramCount ++;
196                 if( !(tmpVal.Flags & ARG_FLAG_ZEROED) )
197                         dataLength += tmpVal.Length;
198                 
199                 if( tmpVal.Flags & ARG_FLAG_RETURN ) {
200                         retLength += tmpVal.Length;
201                         retCount ++;
202                 }
203         }
204         va_end(args);
205         
206         dataLength += sizeof(tRequestHeader) + paramCount*sizeof(tRequestValue);
207         retLength += sizeof(tRequestHeader) + retCount*sizeof(tRequestValue);
208         
209         // Allocate buffers
210         retPtrs = malloc( sizeof(void*) * (retCount+1) );
211         if( dataLength > retLength)
212                 req = malloc( dataLength );
213         else
214                 req = malloc( retLength );
215         req->ClientID = 0;      //< Filled later
216         req->CallID = SyscallID;
217         req->NParams = paramCount;
218         req->MessageLength = dataLength;
219         dataPtr = &req->Params[paramCount];
220         
221         // Fill `output` and `input`
222         va_start(args, ArgTypes);
223         str = ArgTypes;
224         // - re-zero so they can be used as indicies
225         paramCount = 0;
226         retCount = 0;
227         while(*str)
228         {               
229                 str = ReadEntry(&req->Params[paramCount], dataPtr, &retPtrs[retCount], str, &args);
230                 if( !str )      break;
231                 
232                 if( !(req->Params[paramCount].Flags & ARG_FLAG_ZEROED) )
233                         dataPtr += req->Params[paramCount].Length;
234                 if( req->Params[paramCount].Flags & ARG_FLAG_RETURN )
235                         retCount ++;
236                 
237                 paramCount ++;
238         }
239         va_end(args);
240         
241         // --- Send syscall request
242         if( SendRequest(req, dataLength, retLength) < 0 ) {
243                 fprintf(stderr, "syscalls.c: SendRequest failed (SyscallID = %i)\n", SyscallID);
244                 exit(127);
245         }
246         
247         if( !(req->NParams >= 2) ) {
248                 fprintf(stderr, "syscalls.c: Too few return params (%i)", req->NParams);
249                 exit(127);
250         }
251         dataPtr = (void*)&req->Params[req->NParams];
252         // return
253         assert(req->Params[0].Type == ARG_TYPE_INT64);
254         assert(req->Params[0].Length == sizeof(uint64_t));
255         retValue = *(uint64_t*)dataPtr;
256         dataPtr += sizeof(uint64_t);
257         // errno
258         assert(req->Params[1].Type == ARG_TYPE_INT32);
259         assert(req->Params[1].Length == sizeof(uint32_t));
260         acess__errno = *(uint32_t*)dataPtr;
261         dataPtr += sizeof(uint32_t);
262         
263         // Write changes to buffers
264         if( req->NParams - 2 != retCount ) {
265                 fprintf(stderr, "syscalls.c: Return count inbalance (%i - 1 != exp %i) [Call %i]\n",
266                         req->NParams, retCount, SyscallID);
267                 exit(127);
268         }
269         retCount = 0;
270         for( unsigned int i = 2; i < req->NParams; i ++ )
271         {
272                 #if 0
273                  int     j;
274                 printf("Return Data %i: (%i)", i, req->Params[i].Length);
275                 for( j = 0; j < req->Params[i].Length; j ++ )
276                         printf(" %02x", ((uint8_t*)dataPtr)[j]);
277                 printf("\n");
278                 #endif
279                 assert( req->Params[i].Type == ARG_TYPE_DATA );
280                 memcpy( retPtrs[retCount++], dataPtr, req->Params[i].Length );
281                 dataPtr += req->Params[i].Length;
282         }
283         
284         free( req );
285         free( retPtrs );
286         
287         if( gbSyscallDebugEnabled ) {
288                 SYSTRACE(": %i 0x%llx", SyscallID, retValue);
289         }
290         
291         return retValue;
292 }
293
294 int native_int_getfd(void)
295 {
296         for(int ret = 0; ret < MAX_FPS; ret ++ )
297                 if( gaSyscall_LocalFPs[ret] == NULL )
298                         return ret;
299         return -1;
300 }
301
302 int native_open(const char *Path, int Flags)
303 {
304         int     ret = native_int_getfd();
305         if(ret == -1)   return -1;
306        // TODO: Handle directories
307        gaSyscall_LocalFPs[ret] = fopen(Path, "r+");
308        if(!gaSyscall_LocalFPs[ret])     return -1;
309        return ret;
310 }
311
312 int native_shm(const char *Tag, int Flags)
313 {
314         // int ret = native_int_getfd();
315         //if(ret == -1) return -1;
316         //if( strcmp(Tag, "anon") == 0 )
317         //      path = "/AcessNative/anon/RAND";
318         //      FD = shm_open(path, O_RDWD);
319         //shm_unlink(path);
320         //else
321         //      path = "/Acessnative/named/<TAG>";
322         // int FD = shm_open(path, O_RDWD);
323         //shm_unlink(path);
324         //gaSyscall_LocalFPs[ret] = 
325         return -1;
326 }
327
328 void native_close(int FD)
329 {
330         fclose( gaSyscall_LocalFPs[FD] );
331         gaSyscall_LocalFPs[FD] = NULL;
332 }
333
334 size_t native_read(int FD, void *Dest, size_t Bytes)
335 {
336         return fread( Dest, Bytes, 1, gaSyscall_LocalFPs[FD] );
337 }
338
339 size_t native_write(int FD, const void *Src, size_t Bytes)
340 {
341         return fwrite( Src, Bytes, 1, gaSyscall_LocalFPs[FD] );
342 }
343
344 int native_seek(int FD, int64_t Ofs, int Dir)
345 {
346         if(Dir == 0)
347                 return fseek( gaSyscall_LocalFPs[FD], Ofs, SEEK_CUR );
348         else if(Dir > 0)
349                 return fseek( gaSyscall_LocalFPs[FD], Ofs, SEEK_SET );
350         else
351                 return fseek( gaSyscall_LocalFPs[FD], Ofs, SEEK_END );
352 }
353
354 uint64_t native_tell(int FD)
355 {
356         return ftell( gaSyscall_LocalFPs[FD] );
357 }
358
359 int native_execve(const char *filename, const char *const argv[], const char *const envp[])
360 {
361         int ret;
362         ret = execve(filename, (void*)argv, (void*)envp);
363         perror("native_execve");
364         return ret;
365 }
366
367 int native_spawn(const char *filename, const char *const argv[], const char *const envp[])
368 {
369         int rv;
370
371         fprintf(stderr, "native_spawn('%s')\n", filename);
372
373         #if __WIN32__
374         rv = _spawnve(_P_NOWAIT, filename, argv, envp);
375         #else
376         rv = posix_spawn(NULL, filename, NULL, NULL, (void*)argv, (void*)envp);
377         #endif
378         
379         if( rv == 0 ) {
380                 perror("native_spawn");
381         }
382         
383         return rv;
384 }
385
386 int64_t native_timestamp(void)
387 {
388         struct timeval tv;
389         gettimeofday(&tv, NULL);
390         return tv.tv_sec*1000 + tv.tv_usec / 1000;
391 }

UCC git Repository :: git.ucc.asn.au