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

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