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

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