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

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