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

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