- Resident packet handlers can now be used.
[cake.git] / rom / devs / filesys / packet / init.c
blob5917315df6d6b2c10e10a89894f1ecf061ace71e
1 /*
2 * packet.handler - Proxy filesystem for DOS packet handlers
4 * Copyright © 2007-2008 The AROS Development Team
6 * This program is free software; you can redistribute it and/or modify it
7 * under the same terms as AROS itself.
9 * $Id$
12 #include "packet.h"
14 /* places we might find handlers */
15 const char *search_path[] = {
16 "%s",
17 "DEVS:%s",
18 "DEVS:Filesystems/%s",
19 "DEVS:Handlers/%s",
20 NULL
23 static int GM_UNIQUENAME(init)(struct PacketBase *pb) {
24 D(bug("[packet] in init\n"));
26 NEWLIST(&(pb->mounts));
28 return TRUE;
31 static int GM_UNIQUENAME(expunge)(struct PacketBase *pb) {
32 D(bug("[packet] in expunge\n"));
34 return TRUE;
37 AROS_UFH3(void, packet_startup,
38 AROS_UFHA(STRPTR, argPtr, A0),
39 AROS_UFHA(ULONG, argSize, D0),
40 AROS_UFHA(struct ExecBase *, SysBase, A6)) {
41 AROS_USERFUNC_INIT
43 struct Process *me = (struct Process *) FindTask(NULL);
44 BPTR seglist = (BPTR) me->pr_Task.tc_UserData;
46 D(bug("[packet] in packet_startup\n"));
48 WaitPort(&(me->pr_MsgPort));
49 ReplyMsg(GetMsg(&(me->pr_MsgPort)));
51 D(bug("[packet] calling handler\n"));
53 AROS_UFC1(void, (LONG_FUNC) ((BPTR *) BADDR(seglist) + 1),
54 AROS_UFCA(struct ExecBase *, SysBase, A6));
56 D(bug("[packet] handler returned\n"));
58 AROS_USERFUNC_EXIT
61 void packet_reply(struct ph_mount *, APTR, struct ExecBase *);
63 static int GM_UNIQUENAME(open)(struct PacketBase *pb, struct IOFileSys *iofs, ULONG unitnum, ULONG flags) {
64 struct ph_mount *scan, *mount;
65 struct DeviceNode *dn;
66 char filename[MAXFILENAMELENGTH];
67 int i;
68 BPTR seglist;
69 BOOL loaded = FALSE;
70 char pr_name[256];
71 struct Message *msg;
72 struct MsgPort *reply_port;
73 struct DosPacket *dp;
75 D(bug("[packet] in open\n"));
77 dn = iofs->io_Union.io_OpenDevice.io_DeviceNode;
79 D(bug("[packet] devicename '%s' unit %d dosname '%s' handler '%s'\n",
80 iofs->io_Union.io_OpenDevice.io_DeviceName,
81 iofs->io_Union.io_OpenDevice.io_Unit,
82 iofs->io_Union.io_OpenDevice.io_DosName,
83 dn->dn_Handler));
85 /* find this mount */
86 mount = NULL;
87 ForeachNode(&(pb->mounts), scan) {
88 /* XXX what happens if the mount point matches but the handler doesn't? */
89 if (strcmp(scan->handler_name, dn->dn_Handler) == 0 &&
90 strcmp(scan->mount_point, iofs->io_Union.io_OpenDevice.io_DosName) == 0) {
91 mount = scan;
92 break;
96 /* if we didn't find it then we have to set it up */
97 if (mount == NULL) {
99 /* try to load the named handler from each dir in the search path if
100 * not already loaded */
101 seglist = dn->dn_SegList;
102 for (i = 0; seglist == NULL && search_path[i] != NULL; i++) {
103 snprintf(filename, MAXFILENAMELENGTH, search_path[i], dn->dn_Handler);
104 seglist = LoadSeg(filename);
105 if (seglist != NULL) {
106 loaded = TRUE;
107 D(bug("[packet] loaded %s\n", filename));
109 else
110 D(bug("[packet] couldn't load %s\n", filename));
113 if (seglist == NULL) {
114 kprintf("[packet] couldn't open %s\n", dn->dn_Handler);
115 iofs->IOFS.io_Error = IOERR_OPENFAIL;
116 return FALSE;
119 /* got it, create our mount struct */
120 mount = (struct ph_mount *) AllocVec(sizeof(struct ph_mount), MEMF_PUBLIC | MEMF_CLEAR);
122 strncpy(mount->handler_name, dn->dn_Handler, MAXFILENAMELENGTH);
123 strncpy(mount->mount_point, iofs->io_Union.io_OpenDevice.io_DosName, MAXFILENAMELENGTH);
125 /* only store seg list for later unloading if we loaded it ourselves */
126 if (loaded)
127 mount->seglist = seglist;
129 D(bug("[packet] starting handler process\n"));
131 /* start it up */
132 snprintf(pr_name, sizeof(pr_name), "filesys process for %s", mount->mount_point);
133 mount->process = CreateNewProcTags(NP_Entry, (IPTR) packet_startup,
134 NP_Name, pr_name,
135 NP_StackSize, dn->dn_StackSize,
136 NP_Priority, dn->dn_Priority,
137 NP_UserData, (IPTR) seglist,
138 TAG_DONE);
140 reply_port = CreateMsgPort();
142 msg = (struct Message *) AllocVec(sizeof(struct Message), MEMF_PUBLIC | MEMF_CLEAR);
143 msg->mn_ReplyPort = reply_port;
144 msg->mn_Length = sizeof(struct Message);
146 PutMsg(&(mount->process->pr_MsgPort), msg);
147 WaitPort(reply_port);
148 GetMsg(reply_port);
150 FreeVec(msg);
152 /* something went horribly wrong? */
153 if (mount->process == NULL) {
154 kprintf("[packet] couldn't start filesys process for %s\n", mount->mount_point);
156 if (loaded)
157 UnLoadSeg(seglist);
158 FreeVec(mount);
160 iofs->IOFS.io_Error = IOERR_OPENFAIL;
161 return FALSE;
164 D(bug("[packet] started, process structure is 0x%08x\n", mount->process));
166 /* build the startup packet */
167 /* XXX gurubook p645 suggests dp_Arg1 may be "BPTR TO BSTR (file name)",
168 * but I can't confirm this */
169 dp = (struct DosPacket *) AllocDosObject(DOS_STDPKT, NULL);
170 dp->dp_Arg2 = (SIPTR)MKBADDR(dn->dn_Startup);
171 dp->dp_Arg3 = (SIPTR)MKBADDR(dn);
172 dp->dp_Port = reply_port;
174 /* Set up device and unit in device node so handler can add volume
175 * node during start-up */
176 dn->dn_Ext.dn_AROS.dn_Device = iofs->IOFS.io_Device;
177 dn->dn_Ext.dn_AROS.dn_Unit = (struct Unit *) &(mount->root_handle);
178 D(bug("[packet] sending startup packet\n"));
180 PutMsg(&(mount->process->pr_MsgPort), dp->dp_Link);
181 WaitPort(reply_port);
182 GetMsg(reply_port);
184 DeleteMsgPort(reply_port);
186 if (dp->dp_Res1 == DOSFALSE) {
187 D(bug("[packet] handler failed startup [%d]\n", dp->dp_Res2));
189 iofs->IOFS.io_Error = dp->dp_Res2;
190 dn->dn_Ext.dn_AROS.dn_Device = NULL;
191 dn->dn_Ext.dn_AROS.dn_Unit = NULL;
194 else {
195 /* hook the process up to the device node */
196 dn->dn_Task = &(mount->process->pr_MsgPort);
198 /* setup a handler function and port for replies */
199 mount->reply_int.is_Code = packet_reply;
200 mount->reply_int.is_Data = mount;
202 NEWLIST(&(mount->reply_port.mp_MsgList));
203 mount->reply_port.mp_Flags = PA_SOFTINT;
204 mount->reply_port.mp_SigTask = &(mount->reply_int);
206 /* remember this mount */
207 Disable();
208 AddTail((struct List *) &(pb->mounts), (struct Node *) mount);
209 Enable();
211 /* setup the root "handle" to hand back to the caller */
212 mount->root_handle.mount = mount;
213 iofs->IOFS.io_Unit = (struct Unit *) &(mount->root_handle);
215 iofs->IOFS.io_Error = 0;
217 D(bug("[packet] handler %s for mount %s now online\n", mount->handler_name, mount->mount_point));
220 FreeDosObject(DOS_STDPKT, dp);
223 return iofs->IOFS.io_Error != 0 ? FALSE : TRUE;
226 static int GM_UNIQUENAME(close)(struct PacketBase *pb, struct IOFileSys *iofs) {
227 D(bug("[packet] in close\n"));
229 return TRUE;
232 ADD2INITLIB(GM_UNIQUENAME(init),0)
233 ADD2EXPUNGELIB(GM_UNIQUENAME(expunge),0)
234 ADD2OPENDEV(GM_UNIQUENAME(open),0)
235 ADD2CLOSEDEV(GM_UNIQUENAME(close),0)
237 void packet_handle_request(struct IOFileSys *, struct PacketBase *);
239 AROS_LH1(void, beginio, AROS_LHA(struct IOFileSys *, iofs, A1), struct PacketBase *, pb, 5, Packet) {
240 AROS_LIBFUNC_INIT
242 D(bug("[packet] in begin_io\n"));
244 packet_handle_request(iofs, pb);
246 AROS_LIBFUNC_EXIT
249 AROS_LH1(long, abortio, AROS_LHA(struct IOFileSys *, iofs, A1), struct PacketBase *, pb, 6, Packet) {
250 AROS_LIBFUNC_INIT
252 D(bug("[packet] in abort_io\n"));
254 return 0;
256 AROS_LIBFUNC_EXIT