Nativelib - Fix clang compilation issues
[tpg/acess2.git] / KernelLand / Kernel / drv / proc.c
1 /*
2  * Acess2
3  * - Kernel Status Driver
4  */
5 #define DEBUG   1
6 #include <acess.h>
7 #include <modules.h>
8 #include <fs_devfs.h>
9 #include <fs_sysfs.h>
10
11 // === CONSTANTS ===
12 #define VERSION ((0 << 8) | (1))        // 0.01
13
14 // === TYPES ===
15 typedef struct sSysFS_Ent
16 {
17         struct sSysFS_Ent       *Next;
18         struct sSysFS_Ent       *ListNext;
19         struct sSysFS_Ent       *Parent;
20         tVFS_Node       Node;
21         char    Name[];
22 } tSysFS_Ent;
23
24 // === PROTOTYPES ===
25  int    SysFS_Install(char **Arguments);
26  int    SysFS_IOCtl(tVFS_Node *Node, int Id, void *Data);
27
28 #if 0
29  int    SysFS_RegisterFile(const char *Path, const char *Data, int Length);
30  int    SysFS_UpdateFile(int ID, const char *Data, int Length);
31  int    SysFS_RemoveFile(int ID);
32 #endif
33
34  int    SysFS_Comm_ReadDir(tVFS_Node *Node, int Id, char Dest[FILENAME_MAX]);
35 tVFS_Node       *SysFS_Comm_FindDir(tVFS_Node *Node, const char *Filename, Uint Flags);
36 size_t  SysFS_Comm_ReadFile(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer, Uint Flags);
37 void    SysFS_Comm_CloseFile(tVFS_Node *Node);
38
39 // === GLOBALS ===
40 extern tSysFS_Ent       gSysFS_Version; // Defined Later
41 extern tSysFS_Ent       gSysFS_Root;    // Defined Later
42 MODULE_DEFINE(0, VERSION, SysFS, SysFS_Install, NULL, NULL);
43 tVFS_NodeType   gSysFS_FileNodeType = {
44         .TypeName = "SysFS File",
45         .Read = SysFS_Comm_ReadFile
46         };
47 tVFS_NodeType   gSysFS_DirNodeType = {
48         .TypeName = "SysFS Dir",
49         .ReadDir = SysFS_Comm_ReadDir,
50         .FindDir = SysFS_Comm_FindDir
51         };
52 tSysFS_Ent      gSysFS_Version_Kernel = {
53         .Parent = &gSysFS_Version,      // Parent
54         .Node = {
55                 .Inode = 1,     // File #1
56                 .ImplPtr = NULL,
57                 .ImplInt = (Uint)&gSysFS_Version_Kernel,        // Self-Link
58                 .Size = 0,
59                 .NumACLs = 1,
60                 .ACLs = &gVFS_ACL_EveryoneRO,
61                 .Type = &gSysFS_FileNodeType
62         },
63         .Name = {"Kernel"}
64 };
65 tSysFS_Ent      gSysFS_Version = {
66         .Parent = &gSysFS_Root,
67         .Node = {
68                 .Size = 1,
69                 .ImplPtr = &gSysFS_Version_Kernel,
70                 .ImplInt = (Uint)&gSysFS_Version,       // Self-Link
71                 .NumACLs = 1,
72                 .ACLs = &gVFS_ACL_EveryoneRX,
73                 .Flags = VFS_FFLAG_DIRECTORY,
74                 .Type = &gSysFS_DirNodeType
75         },
76         .Name = {"Version"}
77 };
78 // Root of the SysFS tree (just used to keep the code clean)
79 tSysFS_Ent      gSysFS_Root = {
80         NULL, NULL,
81         NULL,
82         {
83                 .Size = 1,
84                 .ImplPtr = &gSysFS_Version,
85                 .ImplInt = (Uint)&gSysFS_Root   // Self-Link
86         },
87         {"/"}
88 };
89 tDevFS_Driver   gSysFS_DriverInfo = {
90         NULL, "system",
91         {
92         .NumACLs = 1,
93         .ACLs = &gVFS_ACL_EveryoneRX,
94         .Flags = VFS_FFLAG_DIRECTORY,
95         .ImplPtr = &gSysFS_Version,
96         .Size = sizeof(gSysFS_Root)/sizeof(tSysFS_Ent),
97         .Type = &gSysFS_DirNodeType
98         }
99 };
100  int    giSysFS_NextFileID = 2;
101 tSysFS_Ent      *gSysFS_FileList;
102
103 // === CODE ===
104 /**
105  * \fn int SysFS_Install(char **Options)
106  * \brief Installs the SysFS Driver
107  */
108 int SysFS_Install(char **Options)
109 {
110         gSysFS_Version_Kernel.Node.Size = strlen(gsBuildInfo);
111         gSysFS_Version_Kernel.Node.ImplPtr = (void*)gsBuildInfo;
112
113         DevFS_AddDevice( &gSysFS_DriverInfo );
114         return MODULE_ERR_OK;
115 }
116
117 /**
118  * \fn int SysFS_RegisterFile(char *Path, char *Data, int Length)
119  * \brief Registers a file (buffer) for the user to be able to read from
120  * \param Path  Path for the file to be accessable from (relative to SysFS root)
121  * \param Data  Pointer to the data buffer (must be non-volatile)
122  * \param Length        Length of the data buffer
123  * \return The file's identifier
124  */
125 int SysFS_RegisterFile(const char *Path, const char *Data, int Length)
126 {
127          int    start = 0;
128          int    tmp;
129         tSysFS_Ent      *ent = NULL;
130         tSysFS_Ent      *child, *prev;
131         
132         // Find parent directory
133         while( (tmp = strpos(&Path[start], '/')) != -1 )
134         {
135                 prev = NULL;
136                 
137                 if(ent)
138                         child = ent->Node.ImplPtr;
139                 else
140                         child = gSysFS_DriverInfo.RootNode.ImplPtr;
141                 for( ; child; prev = child, child = child->Next )
142                 {
143                         if( strncmp( &Path[start], child->Name, tmp+1 ) == '/' )
144                                 break;
145                 }
146                 
147                 // Need a new directory?
148                 if( !child )
149                 {
150                         child = calloc( 1, sizeof(tSysFS_Ent)+tmp+1 );
151                         if( !child ) {
152                                 Log_Error("SysFS", "calloc(%i) failure", sizeof(tSysFS_Ent)+tmp+1);
153                                 return -1;
154                         }
155                         child->Next = NULL;
156                         memcpy(child->Name, &Path[start], tmp);
157                         child->Name[tmp] = '\0';
158                         child->Parent = ent;
159                         child->Node.Inode = 0;
160                         child->Node.ImplPtr = NULL;
161                         child->Node.ImplInt = (Uint)child;      // Uplink
162                         child->Node.NumACLs = 1;
163                         child->Node.ACLs = &gVFS_ACL_EveryoneRX;
164                         child->Node.Flags = VFS_FFLAG_DIRECTORY;
165                         child->Node.Type = &gSysFS_DirNodeType;
166                         if( !prev ) {
167                                 if(ent)
168                                         ent->Node.ImplPtr = child;
169                                 else
170                                         gSysFS_DriverInfo.RootNode.ImplPtr = child;
171                                 // ^^^ Impossible (There is already /Version)
172                         }
173                         else
174                                 prev->Next = child;
175                         if(ent)
176                                 ent->Node.Size ++;
177                         else
178                                 gSysFS_DriverInfo.RootNode.Size ++;
179                         Log_Log("SysFS", "Added directory '%.*s'", tmp, &Path[start]);
180                         Log_Log("SysFS", "Added directory '%.*s'", tmp, child->Name);
181                 }
182                 
183                 ent = child;
184                 
185                 start = tmp+1;
186         }
187         
188         // ent: Parent tSysFS_Ent or NULL
189         // start: beginning of last path element
190         
191         // Check if the name is taken
192         prev = NULL;
193         if(ent)
194                 child = ent->Node.ImplPtr;
195         else
196                 child = gSysFS_DriverInfo.RootNode.ImplPtr;
197         for( ; child; child = child->Next )
198         {
199                 if( strcmp( &Path[start], child->Name ) == 0 )
200                         break;
201         }
202         if( child ) {
203                 Log_Warning("SysFS", "'%s' is taken (in '%s')", &Path[start], Path);
204                 return 0;
205         }
206         
207         // Create new node
208         child = calloc( 1, sizeof(tSysFS_Ent)+strlen(&Path[start])+1 );
209         child->Next = NULL;
210         strcpy(child->Name, &Path[start]);
211         child->Parent = ent;
212         
213         child->Node.Inode = giSysFS_NextFileID++;
214         child->Node.ImplPtr = (void*)Data;
215         child->Node.ImplInt = (Uint)child;      // Uplink
216         child->Node.Size = Length;
217         child->Node.NumACLs = 1;
218         child->Node.ACLs = &gVFS_ACL_EveryoneRO;
219         child->Node.Type = &gSysFS_FileNodeType;
220         
221         // Add to parent's child list
222         if(ent) {
223                 ent->Node.Size ++;
224                 child->Next = ent->Node.ImplPtr;
225                 ent->Node.ImplPtr = child;
226         }
227         else {
228                 gSysFS_DriverInfo.RootNode.Size ++;
229                 child->Next = gSysFS_DriverInfo.RootNode.ImplPtr;
230                 gSysFS_DriverInfo.RootNode.ImplPtr = child;
231         }
232         // Add to global file list
233         child->ListNext = gSysFS_FileList;
234         gSysFS_FileList = child;
235         
236         Log_Log("SysFS", "Added '%s' (%p)", Path, Data);
237         
238         return child->Node.Inode;
239 }
240
241 /**
242  * \fn int SysFS_UpdateFile(int ID, char *Data, int Length)
243  * \brief Updates a file
244  * \param ID    Identifier returned by ::SysFS_RegisterFile
245  * \param Data  Pointer to the data buffer
246  * \param Length        Length of the data buffer
247  * \return Boolean Success
248  */
249 int SysFS_UpdateFile(int ID, const char *Data, int Length)
250 {
251         tSysFS_Ent      *ent;
252         
253         for( ent = gSysFS_FileList; ent; ent = ent->Next )
254         {
255                 // It's a reverse sorted list
256                 if(ent->Node.Inode < (Uint64)ID)
257                         return 0;
258                 if(ent->Node.Inode == (Uint64)ID)
259                 {
260                         ent->Node.ImplPtr = (void*)Data;
261                         ent->Node.Size = Length;
262                         return 1;
263                 }
264         }
265         
266         return 0;
267 }
268
269 /**
270  * \fn int SysFS_RemoveFile(int ID)
271  * \brief Removes a file from user access
272  * \param ID    Identifier returned by ::SysFS_RegisterFile
273  * \return Boolean Success
274  * \note If a handle is still open to the file, it will be invalidated
275  */
276 int SysFS_RemoveFile(int ID)
277 {
278         tSysFS_Ent      *file;
279         tSysFS_Ent      *ent, *parent, *prev;
280         
281         prev = NULL;
282         for( ent = gSysFS_FileList; ent; prev = ent, ent = ent->ListNext )
283         {
284                 // It's a reverse sorted list
285                 if(ent->Node.Inode <= (Uint64)ID)       break;
286         }
287         if( !ent || ent->Node.Inode != (Uint64)ID) {
288                 Log_Notice("SysFS", "ID %i not present", ID);
289                 return 0;
290         }
291         
292         // Set up for next part
293         file = ent;
294         parent = file->Parent;
295         
296         // Remove from file list
297         if(prev)
298                 prev->ListNext = file->ListNext;
299         else
300                 gSysFS_FileList = file->ListNext;
301         file->Node.Size = 0;
302         file->Node.ImplPtr = NULL;
303         
304         // Clean out of parent directory
305         while(parent)
306         {
307                 for( ent = parent->Node.ImplPtr; ent; prev = ent, ent = ent->Next )
308                 {
309                         if( ent == file )       break;
310                 }
311                 if(!ent) {
312                         Log_Warning("SysFS", "Bookkeeping Error: File in list, but not in directory");
313                         return 0;
314                 }
315                 
316                 // Remove from parent directory
317                 if(prev)
318                         prev->Next = ent->Next;
319                 else
320                         parent->Node.ImplPtr = ent->Next;
321
322                 // Free if not in use
323                 if(file->Node.ReferenceCount == 0) {
324                         free(file);
325                 }
326
327                 if( parent->Node.ImplPtr )
328                         break;
329
330                 // Remove parent from the tree
331                 file = parent;
332                 parent = parent->Parent;
333         }
334         
335         return 1;
336 }
337
338 /**
339  * \fn char *SysFS_Comm_ReadDir(tVFS_Node *Node, int Pos)
340  * \brief Reads from a SysFS directory
341  */
342 int SysFS_Comm_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX])
343 {
344         tSysFS_Ent      *child = (tSysFS_Ent*)Node->ImplPtr;
345         if(Pos < 0 || (Uint64)Pos >= Node->Size)
346                 return -EINVAL;
347         
348         for( ; child; child = child->Next, Pos-- )
349         {
350                 if( Pos == 0 ) {
351                         strncpy(Dest, child->Name, FILENAME_MAX);
352                         return 0;
353                 }
354         }
355         return -ENOENT;
356 }
357
358 /**
359  * \fn tVFS_Node *SysFS_Comm_FindDir(tVFS_Node *Node, const char *Filename)
360  * \brief Find a file in a SysFS directory
361  */
362 tVFS_Node *SysFS_Comm_FindDir(tVFS_Node *Node, const char *Filename, Uint Flags)
363 {
364         tSysFS_Ent      *child = (tSysFS_Ent*)Node->ImplPtr;
365         
366         for( ; child; child = child->Next )
367         {
368                 if( strcmp(child->Name, Filename) == 0 )
369                         return &child->Node;
370         }
371         
372         return NULL;
373 }
374
375 /**
376  * \brief Read from an exposed buffer
377  */
378 size_t SysFS_Comm_ReadFile(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer, Uint Flags)
379 {
380         if( Offset > Node->Size )       return -1;
381         if( Length > Node->Size )       Length = Node->Size;
382         if( Offset + Length > Node->Size)       Length = Node->Size - Offset;
383         
384         if( Node->ImplPtr )
385                 memcpy(Buffer, (void*)((Uint)Node->ImplPtr+(Uint)Offset), Length);
386         else
387                 return -1;
388         
389         return Length;
390 }
391
392 /**
393  * \fn void SysFS_Comm_CloseFile(tVFS_Node *Node)
394  * \brief Closes an open file
395  * \param Node  Node to close
396  */
397 void SysFS_Comm_CloseFile(tVFS_Node *Node)
398 {
399         // Dereference
400         Node->ReferenceCount --;
401         if( Node->ReferenceCount > 0 )  return;
402         
403         // Check if it is still valid
404         if( Node->ImplPtr )     return;
405         
406         // Delete
407         free( (void*)Node->ImplInt );
408 }

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