int OutputReadPos;
char OutputData[OUTPUT_RINGBUFFER_LEN];
+ tVFS_Node *ServerNode;
tVFS_Node ClientNode;
- tVFS_Node ServerNode;
tVFS_ACL OwnerRW;
// TODO: Maintain list of client PIDs
int PTY_Install(char **Arguments);
int PTY_ReadDir(tVFS_Node *Node, int Pos, char Name[FILENAME_MAX]);
tVFS_Node *PTY_FindDir(tVFS_Node *Node, const char *Name, Uint Flags);
-tVFS_Node *PTY_MkNod(tVFS_Node *Node, const char *Name, Uint Mode);
size_t _rb_write(void *buf, size_t buflen, int *rd, int *wr, const void *data, size_t len);
size_t _rb_read(void *buf, size_t buflen, int *rd, int *wr, void *data, size_t len);
// PTY_SendInput
size_t PTY_ReadClient(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer, Uint Flags);
size_t PTY_WriteClient(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer, Uint Flags);
- int PTY_IOCtlClient(tVFS_Node *Node, int ID, void *Arg);
void PTY_ReferenceClient(tVFS_Node *Node);
void PTY_CloseClient(tVFS_Node *Node);
size_t PTY_ReadServer(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer, Uint Flags);
size_t PTY_WriteServer(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer, Uint Flags);
- int PTY_IOCtlServer(tVFS_Node *Node, int ID, void *Arg);
void PTY_CloseServer(tVFS_Node *Node);
+ int PTY_IOCtl(tVFS_Node *Node, int ID, void *Arg);
// === GLOBALS ===
MODULE_DEFINE(0, 0x100, PTY, PTY_Install, NULL, NULL);
.TypeName = "PTY-Root",
.ReadDir = PTY_ReadDir,
.FindDir = PTY_FindDir,
- .MkNod = PTY_MkNod
};
tVFS_NodeType gPTY_NodeType_Client = {
.TypeName = "PTY-Client",
.Read = PTY_ReadClient,
.Write = PTY_WriteClient,
- .IOCtl = PTY_IOCtlClient,
+ .IOCtl = PTY_IOCtl,
.Reference = PTY_ReferenceClient,
.Close = PTY_CloseClient
};
.TypeName = "PTY-Server",
.Read = PTY_ReadServer,
.Write = PTY_WriteServer,
- .IOCtl = PTY_IOCtlServer,
+ .IOCtl = PTY_IOCtl,
.Close = PTY_CloseServer
};
tDevFS_Driver gPTY_Driver = {
break;
idx ++;
}
- namelen = 0;
+ namelen = snprintf(NULL,0, "%u", idx);
}
tPTY *ret = calloc(sizeof(tPTY) + namelen + 1, 1);
if(Name)
strcpy(ret->Name, Name);
else
- ret->Name[0] = 0;
+ sprintf(ret->Name, "%u", idx);
ret->NumericName = idx;
// - Output function and handle (same again)
ret->OutputHandle = Handle;
ret->OutputFcn = Output;
ret->ReqResize = ReqResize;
ret->ModeSet = ModeSet;
- // - Server node
- ret->ServerNode.ImplPtr = ret;
- ret->ServerNode.Type = &gPTY_NodeType_Server;
- ret->ServerNode.UID = Threads_GetUID();
- ret->ServerNode.GID = Threads_GetGID();
- ret->ServerNode.NumACLs = 1;
- ret->ServerNode.ACLs = &ret->OwnerRW;
- ret->ServerNode.ReferenceCount = (Output ? 1 : 0); // Prevent a userland close killing a kernel pty
// - Client node
ret->ClientNode.ImplPtr = ret;
ret->ClientNode.Type = &gPTY_NodeType_Client;
VFS_MarkAvaliable(&PTY->ClientNode, 1);
if(ret < Length)
- VFS_MarkFull(&PTY->ServerNode, 1);
+ VFS_MarkFull(PTY->ServerNode, 1);
return ret;
}
{
tPTY *pty = NULL;
int idx = Pos;
- if( idx < giPTY_NumCount * 2 )
+ if( idx < giPTY_NumCount )
{
RWLock_AcquireRead(&glPTY_NumPTYs);
- for( pty = gpPTY_FirstNumPTY; pty; pty = pty->Next )
- {
- if( idx < 2 )
- break;
- idx -= 2;
- }
+ for( pty = gpPTY_FirstNumPTY; pty && idx; pty = pty->Next )
+ idx --;
RWLock_Release(&glPTY_NumPTYs);
}
- else if( idx < (giPTY_NumCount + giPTY_NamedCount) * 2 )
+ else if( idx < (giPTY_NumCount + giPTY_NamedCount) )
{
- idx -= giPTY_NumCount*2;
+ idx -= giPTY_NumCount;
RWLock_AcquireRead(&glPTY_NamedPTYs);
- for( pty = gpPTY_FirstNamedPTY; pty; pty = pty->Next )
- {
- if( idx < 2 )
- break;
- idx -= 2;
- }
+ for( pty = gpPTY_FirstNamedPTY; pty && idx; pty = pty->Next )
+ idx --;
RWLock_Release(&glPTY_NamedPTYs);
}
-
if( !pty ) {
LOG("%i out of range", Pos);
return -1;
}
-
- if( pty->Name[0] )
- snprintf(Name, FILENAME_MAX, "%s%c", pty->Name, (idx == 0 ? 'c' : 's'));
- else
- snprintf(Name, FILENAME_MAX, "%i%c", pty->NumericName, (idx == 0 ? 'c' : 's'));
+
+ strncpy(Name, pty->Name, FILENAME_MAX)
LOG("Return '%s'", Name);
return 0;
}
{
char *end;
int num = strtol(Name, &end, 10);
+
+ if( strcmp(Name, "ptmx") == 0 ) {
+ tVFS_Node *ret = calloc(sizeof(tVFS_Node), 1);
+ ret->Size = -1;
+ ret->Type = &gPTY_NodeType_Server;
+ return ret;
+ }
- if( Name[0] == '\0' || Name[1] == '\0' )
- return NULL;
-
- size_t len = strlen(Name);
- if( Name[len-1] != 'c' && Name[len-1] != 's' )
+ if( Name[0] == '\0' )
return NULL;
- int isServer = (Name[len-1] != 'c');
tPTY *ret = NULL;
- if( num && (end[0] == 'c' || end[0] == 's') && end[1] == '\0' )
+ if( num && end[0] == '\0' )
{
// Numeric name
RWLock_AcquireRead(&glPTY_NumPTYs);
RWLock_AcquireRead(&glPTY_NamedPTYs);
for( tPTY *pty = gpPTY_FirstNamedPTY; pty; pty = pty->Next )
{
- int cmp = strncmp(pty->Name, Name, len-1);
+ int cmp = strcmp(pty->Name, Name);
if(cmp > 0)
break;
- if(cmp == 0 && pty->Name[len-1] == '\0' ) {
+ if(cmp == 0 ) {
ret = pty;
break;
}
RWLock_Release(&glPTY_NamedPTYs);
}
if( ret ) {
- tVFS_Node *retnode = (isServer ? &ret->ServerNode : &ret->ClientNode);
+ tVFS_Node *retnode = &ret->ClientNode;
retnode->ReferenceCount ++;
return retnode;
}
return NULL;
}
-tVFS_Node *PTY_MkNod(tVFS_Node *Node, const char *Name, Uint Mode)
-{
- // zero-length name means a numbered pty has been requested
- if( Name[0] == '\0' || (Name[0] == '#' && Name[1] == '\0') )
- {
- tPTY *ret = PTY_Create(NULL, NULL, NULL, NULL, NULL);
- if( !ret )
- return NULL;
- return &ret->ServerNode;
- }
-
- // Otherwise return a named PTY
- // TODO: Should the request be for '<name>s' or just '<name>'
-
- tPTY *ret = PTY_Create(Name, NULL, NULL, NULL, NULL);
- if(!ret)
- return NULL;
- return &ret->ServerNode;
-}
-
//\! Read from the client's input
size_t PTY_ReadClient(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer, Uint Flags)
{
int rv;
_select:
// If server has disconnected, return EIO
- if( pty->ServerNode.ReferenceCount == 0 ) {
+ if( pty->ServerNode && pty->ServerNode->ReferenceCount == 0 ) {
//Threads_PostSignal(SIGPIPE);
errno = EIO;
return -1;
tPTY *pty = Node->ImplPtr;
// If the server has terminated, send SIGPIPE
- if( pty->ServerNode.ReferenceCount == 0 )
+ if( pty->ServerNode && pty->ServerNode->ReferenceCount == 0 )
{
//Threads_PostSignal(SIGPIPE);
errno = EIO;
Length = _rb_write(pty->OutputData, OUTPUT_RINGBUFFER_LEN,
&pty->OutputReadPos, &pty->OutputWritePos,
Buffer, Length);
- VFS_MarkAvaliable(&pty->ServerNode, 1);
+ VFS_MarkAvaliable(pty->ServerNode, 1);
}
return Length;
}
-int PTY_IOCtlClient(tVFS_Node *Node, int ID, void *Data)
-{
- tPTY *pty = Node->ImplPtr;
- struct ptymode *mode = Data;
- struct ptydims *dims = Data;
- switch(ID)
- {
- case DRV_IOCTL_TYPE: return DRV_TYPE_TERMINAL;
- case DRV_IOCTL_IDENT: memcpy(Data, "PTY\0", 4); return 0;
- case DRV_IOCTL_VERSION: return 0x100;
- case DRV_IOCTL_LOOKUP: return 0;
-
- case PTY_IOCTL_GETMODE:
- if( !CheckMem(Data, sizeof(*mode)) ) { errno = EINVAL; return -1; }
- *mode = pty->Mode;
- return 0;
- case PTY_IOCTL_SETMODE:
- if( !CheckMem(Data, sizeof(*mode)) ) { errno = EINVAL; return -1; }
- return PTY_SetAttrib(pty, NULL, mode, 1);
- case PTY_IOCTL_GETDIMS:
- if( !CheckMem(Data, sizeof(*dims)) ) { errno = EINVAL; return -1; }
- *dims = pty->Dims;
- return 0;
- case PTY_IOCTL_SETDIMS:
- if( !CheckMem(Data, sizeof(*dims)) ) { errno = EINVAL; return -1; }
- return PTY_SetAttrib(pty, dims, NULL, 1);
- }
- errno = ENOSYS;
- return -1;
-}
-
void PTY_ReferenceClient(tVFS_Node *Node)
{
Node->ReferenceCount ++;
// TODO: Maintain list of client processes
// Free structure if this was the last open handle
- if( Node->ReferenceCount == 0 && pty->ServerNode.ReferenceCount == 0 )
+ if( Node->ReferenceCount > 0 )
+ return ;
+ if( pty->ServerNode && pty->ServerNode->ReferenceCount == 0 )
{
// Free the structure! (Should be off the PTY list now)
+ free(pty->ServerNode);
free(pty);
}
}
return PTY_SendInput(Node->ImplPtr, Buffer, Length);
}
-int PTY_IOCtlServer(tVFS_Node *Node, int ID, void *Data)
-{
- tPTY *pty = Node->ImplPtr;
- struct ptymode *mode = Data;
- struct ptydims *dims = Data;
- switch(ID)
- {
- case DRV_IOCTL_TYPE: return DRV_TYPE_TERMINAL;
- case DRV_IOCTL_IDENT: memcpy(Data, "PTY\0", 4); return 0;
- case DRV_IOCTL_VERSION: return 0x100;
- case DRV_IOCTL_LOOKUP: return 0;
-
- case PTY_IOCTL_GETMODE:
- if( !CheckMem(Data, sizeof(*mode)) ) { errno = EINVAL; return -1; }
- *mode = pty->Mode;
- // ACK client's SETMODE
- return 0;
- case PTY_IOCTL_SETMODE:
- if( !CheckMem(Data, sizeof(*mode)) ) { errno = EINVAL; return -1; }
- PTY_SetAttrib(pty, NULL, mode, 0);
- return 0;
- case PTY_IOCTL_GETDIMS:
- if( !CheckMem(Data, sizeof(*dims)) ) { errno = EINVAL; return -1; }
- *dims = pty->Dims;
- return 0;
- case PTY_IOCTL_SETDIMS:
- if( !CheckMem(Data, sizeof(*dims)) ) { errno = EINVAL; return -1; }
- PTY_SetAttrib(pty, dims, NULL, 0);
- break;
- case PTY_IOCTL_GETID:
- return pty->NumericName;
- }
- errno = ENOSYS;
- return -1;
-}
-
void PTY_CloseServer(tVFS_Node *Node)
{
tPTY *pty = Node->ImplPtr;
// Locate on list and remove
tPTY **prev_np;
- if( pty->Name[0] ) {
+ if( pty->NumericName == 0 ) {
RWLock_AcquireWrite(&glPTY_NamedPTYs);
prev_np = &gpPTY_FirstNamedPTY;
}
}
// Clean up lock
- if( pty->Name[0] ) {
+ if( pty->NumericName == 0 ) {
RWLock_Release(&glPTY_NamedPTYs);
giPTY_NamedCount --;
}
}
// If there are no open children, we can safely free this PTY
- if( pty->ClientNode.ReferenceCount == 0 )
+ if( pty->ClientNode.ReferenceCount == 0 ) {
+ free(Node);
free(pty);
+ }
+}
+
+int PTY_IOCtl(tVFS_Node *Node, int ID, void *Data)
+{
+ tPTY *pty = Node->ImplPtr;
+ struct ptymode *mode = Data;
+ struct ptydims *dims = Data;
+
+ int is_server = !pty || Node == pty->ServerNode;
+
+ switch(ID)
+ {
+ case DRV_IOCTL_TYPE: return DRV_TYPE_TERMINAL;
+ case DRV_IOCTL_IDENT: memcpy(Data, "PTY\0", 4); return 0;
+ case DRV_IOCTL_VERSION: return 0x100;
+ case DRV_IOCTL_LOOKUP: return 0;
+
+ case PTY_IOCTL_GETMODE:
+ if( !pty ) return 0;
+ if( !CheckMem(Data, sizeof(*mode)) ) { errno = EINVAL; return -1; }
+ *mode = pty->Mode;
+ // TODO: ACK client's SETMODE
+ return 0;
+ case PTY_IOCTL_SETMODE:
+ if( !pty ) return 0;
+ if( !CheckMem(Data, sizeof(*mode)) ) { errno = EINVAL; return -1; }
+ PTY_SetAttrib(pty, NULL, mode, !is_server);
+ return 0;
+ case PTY_IOCTL_GETDIMS:
+ if( !pty ) return 0;
+ if( !CheckMem(Data, sizeof(*dims)) ) { errno = EINVAL; return -1; }
+ *dims = pty->Dims;
+ return 0;
+ case PTY_IOCTL_SETDIMS:
+ if( !pty ) return 0;
+ if( !CheckMem(Data, sizeof(*dims)) ) { errno = EINVAL; return -1; }
+ PTY_SetAttrib(pty, dims, NULL, !is_server);
+ return 0;
+ case PTY_IOCTL_GETID:
+ if( pty )
+ {
+ size_t len = strlen(pty->Name)+1;
+ if( Data )
+ {
+ if( !CheckMem(Data, len) ) { errno = EINVAL; return -1; }
+ strcpy(Data, pty->Name);
+ }
+ return len;
+ }
+ return 0;
+ case PTY_IOCTL_SETID:
+ if( Data && !CheckString(Data) ) { errno = EINVAL; return -1; }
+ if( pty ) return EALREADY;
+ pty = PTY_Create(Data, NULL, NULL,NULL, NULL);
+ if(pty == NULL)
+ return 1;
+ Node->ImplPtr = pty;
+ pty->ServerNode = Node;
+ return 0;
+ }
+ errno = ENOSYS;
+ return -1;
}