c007c32676d692788f00bf24b84cfb31e3da3d00
[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 to keep the code clean)
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         }
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) );
143                         child->Next = NULL;
144                         child->Name = malloc(tmp+1);
145                         memcpy(child->Name, &Path[start], tmp);
146                         child->Name[tmp] = '\0';
147                         child->Parent = ent;
148                         child->Node.Inode = 0;
149                         child->Node.ImplPtr = NULL;
150                         child->Node.ImplInt = (Uint)child;      // Uplink
151                         child->Node.NumACLs = 1;
152                         child->Node.ACLs = &gVFS_ACL_EveryoneRX;
153                         child->Node.Flags = VFS_FFLAG_DIRECTORY;
154                         child->Node.ReadDir = SysFS_Comm_ReadDir;
155                         child->Node.FindDir = SysFS_Comm_FindDir;
156                         if( !prev ) {
157                                 //if(ent)
158                                         ent->Node.ImplPtr = child;
159                                 //else
160                                 //      gSysFS_DriverInfo.RootNode.ImplPtr = child;
161                                 // ^^^ Impossible (There is already /Version)
162                         }
163                         else
164                                 prev->Next = child;
165                         if(ent)
166                                 ent->Node.Size ++;
167                         else
168                                 gSysFS_DriverInfo.RootNode.Size ++;
169                         Log_Log("SysFS", "Added directory '%s'", child->Name);
170                 }
171                 
172                 ent = child;
173                 
174                 start = tmp+1;
175         }
176         
177         // ent: Parent tSysFS_Ent or NULL
178         // start: beginning of last path element
179         
180         // Check if the name is taken
181         prev = NULL;
182         if(ent)
183                 child = ent->Node.ImplPtr;
184         else
185                 child = gSysFS_DriverInfo.RootNode.ImplPtr;
186         for( child = ent->Node.ImplPtr; child; prev = child, child = child->Next )
187         {
188                 if( strcmp( &Path[start], child->Name ) == 0 )
189                         break;
190         }
191         if( child ) {
192                 Log_Warning("SysFS", "'%s' is taken (in '%s')\n", &Path[start], Path);
193                 return 0;
194         }
195         
196         // Create new node
197         child = calloc( 1, sizeof(tSysFS_Ent) );
198         child->Next = NULL;
199         child->Name = strdup(&Path[start]);
200         child->Parent = ent;
201         
202         child->Node.Inode = giSysFS_NextFileID++;
203         child->Node.ImplPtr = Data;
204         child->Node.ImplInt = (Uint)child;      // Uplink
205         child->Node.Size = Length;
206         child->Node.NumACLs = 1;
207         child->Node.ACLs = &gVFS_ACL_EveryoneRO;
208         child->Node.Read = SysFS_Comm_ReadFile;
209         child->Node.Close = SysFS_Comm_CloseFile;
210         
211         // Add to parent's child list
212         if(ent) {
213                 ent->Node.Size ++;
214                 child->Next = ent->Node.ImplPtr;
215                 ent->Node.ImplPtr = child;
216         }
217         else {
218                 gSysFS_DriverInfo.RootNode.Size ++;
219                 child->Next = gSysFS_DriverInfo.RootNode.ImplPtr;
220                 gSysFS_DriverInfo.RootNode.ImplPtr = child;
221         }
222         // Add to global file list
223         child->ListNext = gSysFS_FileList;
224         gSysFS_FileList = child;
225         
226         Log_Log("SysFS", "Added '%s' (%p)", Path, Data);
227         
228         return child->Node.Inode;
229 }
230
231 /**
232  * \fn int SysFS_UpdateFile(int ID, char *Data, int Length)
233  * \brief Updates a file
234  * \param ID    Identifier returned by ::SysFS_RegisterFile
235  * \param Data  Pointer to the data buffer
236  * \param Length        Length of the data buffer
237  * \return Boolean Success
238  */
239 int SysFS_UpdateFile(int ID, char *Data, int Length)
240 {
241         tSysFS_Ent      *ent;
242         
243         for( ent = gSysFS_FileList; ent; ent = ent->Next )
244         {
245                 // It's a reverse sorted list
246                 if(ent->Node.Inode < ID)        return 0;
247                 if(ent->Node.Inode == ID)
248                 {
249                         ent->Node.ImplPtr = Data;
250                         ent->Node.Size = Length;
251                         return 1;
252                 }
253         }
254         
255         return 0;
256 }
257
258 /**
259  * \fn int SysFS_RemoveFile(int ID)
260  * \brief Removes a file from user access
261  * \param ID    Identifier returned by ::SysFS_RegisterFile
262  * \return Boolean Success
263  * \note If a handle is still open to the file, it will be invalidated
264  */
265 int SysFS_RemoveFile(int ID)
266 {
267         tSysFS_Ent      *file;
268         tSysFS_Ent      *ent, *parent, *prev;
269         
270         prev = NULL;
271         for( ent = gSysFS_FileList; ent; prev = ent, ent = ent->Next )
272         {
273                 // It's a reverse sorted list
274                 if(ent->Node.Inode < ID)        return 0;
275                 if(ent->Node.Inode == ID)       break;
276         }
277         
278         if(!ent)        return 0;
279         
280         // Set up for next part
281         file = ent;
282         parent = file->Parent;
283         
284         // Remove from file list
285         prev->ListNext = file->ListNext;
286         file->Node.Size = 0;
287         file->Node.ImplPtr = NULL;
288         
289         // Search parent directory
290         for( ent = parent->Node.ImplPtr; ent; prev = ent, ent = ent->Next )
291         {
292                 if( ent == file )       break;
293         }
294         if(!ent) {
295                 Log_Warning("SysFS", "Bookkeeping Error: File in list, but not in directory");
296                 return 0;
297         }
298         
299         // Remove from parent directory
300         prev->Next = ent->Next;
301         
302         // Free if not in use
303         if(file->Node.ReferenceCount == 0)
304                 free(file);
305         
306         return 1;
307 }
308
309 /**
310  * \fn char *SysFS_Comm_ReadDir(tVFS_Node *Node, int Pos)
311  * \brief Reads from a SysFS directory
312  */
313 char *SysFS_Comm_ReadDir(tVFS_Node *Node, int Pos)
314 {
315         tSysFS_Ent      *child = (tSysFS_Ent*)Node->ImplPtr;
316         if(Pos < 0 || Pos >= Node->Size)        return NULL;
317         
318         for( ; child; child = child->Next, Pos-- )
319         {
320                 if( Pos == 0 )  return strdup(child->Name);
321         }
322         return NULL;
323 }
324
325 /**
326  * \fn tVFS_Node *SysFS_Comm_FindDir(tVFS_Node *Node, char *Filename)
327  * \brief Find a file in a SysFS directory
328  */
329 tVFS_Node *SysFS_Comm_FindDir(tVFS_Node *Node, char *Filename)
330 {
331         tSysFS_Ent      *child = (tSysFS_Ent*)Node->ImplPtr;
332         
333         for( ; child; child = child->Next )
334         {
335                 if( strcmp(child->Name, Filename) == 0 )
336                         return &child->Node;
337         }
338         
339         return NULL;
340 }
341
342 /**
343  * \fn Uint64 SysFS_Comm_ReadFile(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
344  * \brief Read from an exposed buffer
345  */
346 Uint64 SysFS_Comm_ReadFile(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
347 {
348         if( Offset > Node->Size )       return -1;
349         if( Length > Node->Size )       Length = Node->Size;
350         if( Offset + Length > Node->Size)       Length = Node->Size - Offset;
351         
352         if( Node->ImplPtr )
353                 memcpy(Buffer, (void*)((Uint)Node->ImplPtr+(Uint)Offset), Length);
354         else
355                 return -1;
356         
357         return Length;
358 }
359
360 /**
361  * \fn void SysFS_Comm_CloseFile(tVFS_Node *Node)
362  * \brief Closes an open file
363  * \param Node  Node to close
364  */
365 void SysFS_Comm_CloseFile(tVFS_Node *Node)
366 {
367         // Dereference
368         Node->ReferenceCount --;
369         if( Node->ReferenceCount > 0 )  return;
370         
371         // Check if it is still valid
372         if( Node->ImplPtr )     return;
373         
374         // Delete
375         free( (void*)Node->ImplInt );
376 }

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