hurd: Add _write.
* include/gnu/syscall.h (SYS__io_write): Add enum field. (_hurd_dtable, _hurd_dtable_size): Declare variable. (fd_get, fd_write, __io_write, __syscall_put): Declare. * lib/gnu/hurd-start.c (_hurd_dtable, _hurd_dtable_size): Define variable. * lib/gnu/_write.c: New file. * lib/gnu/fd-get.c (fd_get): New file. * lib/gnu/fd-write.c (fd_write): New file. * lib/gnu/io-write.c: New file. * lib/gnu/syscall.c (__syscall_put): New function. * build-aux/cofnigure-lib.sh (libc_mini_SOURCES): Add write sources. * lib/tests/mes/30-oputs.c (main): Update. * lib/tests/mes/30-oputs.stdout: New file. * lib/tests/mes/30-eputs.c: New test. * lib/tests/mes/30-eputs.stderr: New file. * build-aux/check-mescc.sh (TESTS): Add it.
This commit is contained in:
parent
784838e368
commit
db4a202c6b
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -34,8 +34,6 @@
|
||||||
*.a
|
*.a
|
||||||
*.o
|
*.o
|
||||||
*.seed-out
|
*.seed-out
|
||||||
*.stderr
|
|
||||||
*.stdout
|
|
||||||
|
|
||||||
/lib/tests/*/[0-9a][0-9a-z]-*
|
/lib/tests/*/[0-9a][0-9a-z]-*
|
||||||
!/lib/tests/*/*.c
|
!/lib/tests/*/*.c
|
||||||
|
|
|
@ -75,6 +75,7 @@ lib/tests/scaffold/23-global-pointer-pointer-ref.c
|
||||||
lib/tests/scaffold/23-pointer-sub.c
|
lib/tests/scaffold/23-pointer-sub.c
|
||||||
lib/tests/scaffold/23-pointer.c
|
lib/tests/scaffold/23-pointer.c
|
||||||
lib/tests/mes/30-oputs.c
|
lib/tests/mes/30-oputs.c
|
||||||
|
lib/tests/mes/30-eputs.c
|
||||||
lib/tests/string/30-strlen.c
|
lib/tests/string/30-strlen.c
|
||||||
lib/tests/scaffold/30-exit-0.c
|
lib/tests/scaffold/30-exit-0.c
|
||||||
lib/tests/scaffold/30-exit-42.c
|
lib/tests/scaffold/30-exit-42.c
|
||||||
|
|
|
@ -46,6 +46,10 @@ lib/string/strlen.c
|
||||||
libc_mini_shared_SOURCES="$libc_mini_shared_SOURCES
|
libc_mini_shared_SOURCES="$libc_mini_shared_SOURCES
|
||||||
lib/gnu/_exit.c
|
lib/gnu/_exit.c
|
||||||
lib/gnu/exec-startup-get-data.c
|
lib/gnu/exec-startup-get-data.c
|
||||||
|
lib/gnu/fd-get.c
|
||||||
|
lib/gnu/fd-write.c
|
||||||
|
lib/gnu/io-write.c
|
||||||
|
lib/gnu/_write.c
|
||||||
lib/gnu/hurd-start.c
|
lib/gnu/hurd-start.c
|
||||||
lib/gnu/proc-mark-exit.c
|
lib/gnu/proc-mark-exit.c
|
||||||
lib/gnu/syscall.c
|
lib/gnu/syscall.c
|
||||||
|
|
|
@ -24,6 +24,16 @@
|
||||||
#define _GNU_SOURCE 1
|
#define _GNU_SOURCE 1
|
||||||
#define __USE_GNU 1
|
#define __USE_GNU 1
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#ifndef _BITS_TYPES_H
|
||||||
|
#ifndef _LOFF_T
|
||||||
|
#define _LOFF_T
|
||||||
|
typedef off64_t loff_t;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <mach/mach_types.h>
|
#include <mach/mach_types.h>
|
||||||
#include <mach/message.h>
|
#include <mach/message.h>
|
||||||
#include <mach/port.h>
|
#include <mach/port.h>
|
||||||
|
@ -44,8 +54,12 @@ struct hurd_startup_data
|
||||||
vm_address_t user_entry;
|
vm_address_t user_entry;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern mach_port_t *_hurd_init_dtable;
|
#define _HURD_DTABLE_MAX 1024
|
||||||
extern mach_msg_type_number_t _hurd_init_dtablesize;
|
extern mach_port_t _hurd_dtable[_HURD_DTABLE_MAX];
|
||||||
|
extern int _hurd_dtable_size;
|
||||||
extern struct hurd_startup_data _hurd_startup_data;
|
extern struct hurd_startup_data _hurd_startup_data;
|
||||||
|
|
||||||
|
mach_port_t fd_get (int filedes);
|
||||||
|
error_t fd_write (mach_port_t port, void const *buffer, size_t *size, loff_t offset);
|
||||||
|
|
||||||
#endif // __MES_GNU_HURD_H
|
#endif // __MES_GNU_HURD_H
|
||||||
|
|
|
@ -38,6 +38,12 @@ enum
|
||||||
SYS__task_get_special_port = 2058,
|
SYS__task_get_special_port = 2058,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// hurd/io.defs
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
SYS__io_write = 21000,
|
||||||
|
};
|
||||||
|
|
||||||
// hurd/process.defs
|
// hurd/process.defs
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
|
@ -51,6 +57,8 @@ enum
|
||||||
};
|
};
|
||||||
|
|
||||||
extern mach_msg_type_t mach_msg_type_int32;
|
extern mach_msg_type_t mach_msg_type_int32;
|
||||||
|
extern mach_msg_type_t mach_msg_type_int64;
|
||||||
|
extern mach_msg_type_long_t mach_msg_type_pointer;
|
||||||
|
|
||||||
struct mach_msg
|
struct mach_msg
|
||||||
{
|
{
|
||||||
|
@ -102,6 +110,7 @@ struct mach_msg_startup_info
|
||||||
kern_return_t __syscall (mach_port_t port, int sys_call);
|
kern_return_t __syscall (mach_port_t port, int sys_call);
|
||||||
kern_return_t __syscall2 (mach_port_t port, int sys_call, int one, int two);
|
kern_return_t __syscall2 (mach_port_t port, int sys_call, int one, int two);
|
||||||
kern_return_t __syscall_get (mach_port_t port, int sys_call, mach_msg_header_t *message, size_t size);
|
kern_return_t __syscall_get (mach_port_t port, int sys_call, mach_msg_header_t *message, size_t size);
|
||||||
|
kern_return_t __syscall_put (mach_port_t port, int sys_call, mach_msg_header_t *message, size_t size);
|
||||||
|
|
||||||
// mach.defs
|
// mach.defs
|
||||||
kern_return_t __task_terminate (mach_port_t task);
|
kern_return_t __task_terminate (mach_port_t task);
|
||||||
|
@ -112,4 +121,7 @@ kern_return_t __vm_statistics (mach_port_t task, vm_statistics_data_t *vm_stats)
|
||||||
kern_return_t __proc_mark_exit (mach_port_t process, int one, int two);
|
kern_return_t __proc_mark_exit (mach_port_t process, int one, int two);
|
||||||
kern_return_t __exec_startup_get_data (mach_port_t bootstrap, struct hurd_startup_data *data);
|
kern_return_t __exec_startup_get_data (mach_port_t bootstrap, struct hurd_startup_data *data);
|
||||||
|
|
||||||
|
// io.c
|
||||||
|
kern_return_t __io_write (io_t io_object, data_t data, mach_msg_type_number_t size, loff_t offset, vm_size_t *wrote);
|
||||||
|
|
||||||
#endif // __MES_GNU_SYSCALL_H
|
#endif // __MES_GNU_SYSCALL_H
|
||||||
|
|
34
lib/gnu/_write.c
Normal file
34
lib/gnu/_write.c
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
/* -*-comment-start: "//";comment-end:""-*-
|
||||||
|
* GNU Mes --- Maxwell Equations of Software
|
||||||
|
* Copyright © 2019 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
|
||||||
|
*
|
||||||
|
* This file is part of GNU Mes.
|
||||||
|
*
|
||||||
|
* GNU Mes is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or (at
|
||||||
|
* your option) any later version.
|
||||||
|
*
|
||||||
|
* GNU Mes is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with GNU Mes. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <gnu/hurd.h>
|
||||||
|
#include <gnu/hurd-types.h>
|
||||||
|
#include <gnu/syscall.h>
|
||||||
|
#include <mach/mach-init.h>
|
||||||
|
|
||||||
|
ssize_t
|
||||||
|
_write (int filedes, void const *buffer, size_t size)
|
||||||
|
{
|
||||||
|
mach_port_t p = fd_get (filedes);
|
||||||
|
error_t e = fd_write (p, buffer, &size, -1);
|
||||||
|
if (!e)
|
||||||
|
return size;
|
||||||
|
return -1;
|
||||||
|
}
|
|
@ -18,6 +18,7 @@
|
||||||
* along with GNU Mes. If not, see <http://www.gnu.org/licenses/>.
|
* along with GNU Mes. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
//#include <gnu/hurd.h>
|
||||||
#include <gnu/syscall.h>
|
#include <gnu/syscall.h>
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
37
lib/gnu/fd-get.c
Normal file
37
lib/gnu/fd-get.c
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
/* -*-comment-start: "//";comment-end:""-*-
|
||||||
|
* GNU Mes --- Maxwell Equations of Software
|
||||||
|
* Copyright © 2019 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
|
||||||
|
*
|
||||||
|
* This file is part of GNU Mes.
|
||||||
|
*
|
||||||
|
* GNU Mes is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or (at
|
||||||
|
* your option) any later version.
|
||||||
|
*
|
||||||
|
* GNU Mes is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with GNU Mes. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Commentary:
|
||||||
|
Inspired by implementation in GNU C Library:
|
||||||
|
_hurd_fd_get
|
||||||
|
Copyright (C) 1993-2016 Free Software Foundation, Inc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <gnu/hurd.h>
|
||||||
|
|
||||||
|
mach_port_t
|
||||||
|
fd_get (int filedes)
|
||||||
|
{
|
||||||
|
if (filedes >=0 && filedes <= _hurd_dtable_size)
|
||||||
|
return _hurd_dtable[filedes];
|
||||||
|
return 0;
|
||||||
|
}
|
41
lib/gnu/fd-write.c
Normal file
41
lib/gnu/fd-write.c
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
/* -*-comment-start: "//";comment-end:""-*-
|
||||||
|
* GNU Mes --- Maxwell Equations of Software
|
||||||
|
* Copyright © 2019 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
|
||||||
|
*
|
||||||
|
* This file is part of GNU Mes.
|
||||||
|
*
|
||||||
|
* GNU Mes is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or (at
|
||||||
|
* your option) any later version.
|
||||||
|
*
|
||||||
|
* GNU Mes is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with GNU Mes. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Commentary:
|
||||||
|
Inspired by implementation in GNU C Library:
|
||||||
|
_hurd_fd_write -- write to a file descriptor; handles job control et al.
|
||||||
|
Copyright (C) 1993-2016 Free Software Foundation, Inc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <gnu/hurd.h>
|
||||||
|
#include <gnu/syscall.h>
|
||||||
|
|
||||||
|
error_t
|
||||||
|
fd_write (mach_port_t port, void const *buffer, size_t *size, loff_t offset)
|
||||||
|
{
|
||||||
|
mach_msg_type_number_t wrote = 0;
|
||||||
|
error_t err = __io_write (port, buffer, *size, 0, &wrote);
|
||||||
|
if (! err)
|
||||||
|
*size = wrote;
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
|
@ -33,6 +33,8 @@
|
||||||
#include <mach/port.h>
|
#include <mach/port.h>
|
||||||
|
|
||||||
struct hurd_startup_data _hurd_startup_data;
|
struct hurd_startup_data _hurd_startup_data;
|
||||||
|
mach_port_t _hurd_dtable[_HURD_DTABLE_MAX];
|
||||||
|
int _hurd_dtable_size;
|
||||||
|
|
||||||
void __mach_init (void);
|
void __mach_init (void);
|
||||||
|
|
||||||
|
@ -44,4 +46,7 @@ _hurd_start ()
|
||||||
__task_get_special_port (__mach_task_self (), TASK_BOOTSTRAP_PORT,
|
__task_get_special_port (__mach_task_self (), TASK_BOOTSTRAP_PORT,
|
||||||
&bootstrap);
|
&bootstrap);
|
||||||
__exec_startup_get_data (bootstrap, &_hurd_startup_data);
|
__exec_startup_get_data (bootstrap, &_hurd_startup_data);
|
||||||
|
_hurd_dtable_size = _hurd_startup_data.dtablesize;
|
||||||
|
for (int i = 0; i < _hurd_dtable_size; i++)
|
||||||
|
_hurd_dtable[i] = _hurd_startup_data.dtable[i];
|
||||||
}
|
}
|
||||||
|
|
50
lib/gnu/io-write.c
Normal file
50
lib/gnu/io-write.c
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
/* -*-comment-start: "//";comment-end:""-*-
|
||||||
|
* GNU Mes --- Maxwell Equations of Software
|
||||||
|
* Copyright © 2019 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
|
||||||
|
*
|
||||||
|
* This file is part of GNU Mes.
|
||||||
|
*
|
||||||
|
* GNU Mes is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or (at
|
||||||
|
* your option) any later version.
|
||||||
|
*
|
||||||
|
* GNU Mes is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with GNU Mes. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <gnu/syscall.h>
|
||||||
|
|
||||||
|
struct mach_msg_pointer_int
|
||||||
|
{
|
||||||
|
mach_msg_header_t header;
|
||||||
|
mach_msg_type_long_t type_one; char *one;
|
||||||
|
mach_msg_type_t type_two; loff_t two;
|
||||||
|
};
|
||||||
|
|
||||||
|
kern_return_t
|
||||||
|
__io_write (io_t io, data_t data, mach_msg_type_number_t size, loff_t offset, vm_size_t *wrote)
|
||||||
|
{
|
||||||
|
struct mach_msg_pointer_int message = {0};
|
||||||
|
message.header.msgh_size = sizeof (struct mach_msg_pointer_int);
|
||||||
|
message.type_one = mach_msg_type_pointer;
|
||||||
|
message.one = data;
|
||||||
|
message.type_two = mach_msg_type_int64;
|
||||||
|
message.two = offset;
|
||||||
|
|
||||||
|
message.type_one.msgtl_number = size;
|
||||||
|
message.type_one.msgtl_header.msgt_inline = 0;
|
||||||
|
message.header.msgh_bits = MACH_MSGH_BITS_COMPLEX;
|
||||||
|
|
||||||
|
kern_return_t result = __syscall_put (io, SYS__io_write,
|
||||||
|
&message.header,
|
||||||
|
sizeof (struct mach_msg_2));
|
||||||
|
if (result == KERN_SUCCESS)
|
||||||
|
*wrote = message.two;
|
||||||
|
return result;
|
||||||
|
}
|
|
@ -33,6 +33,33 @@ mach_msg_type_t mach_msg_type_int32 =
|
||||||
.msgt_unused = 0 // msgt_unused
|
.msgt_unused = 0 // msgt_unused
|
||||||
};
|
};
|
||||||
|
|
||||||
|
mach_msg_type_long_t mach_msg_type_pointer =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
0, // msgt_name
|
||||||
|
0, // msgt_size
|
||||||
|
0, // msgt_number
|
||||||
|
1, // msgt_inline FIXME: we always outline...
|
||||||
|
1, // msgt_longform
|
||||||
|
0, // msgt_deallocate
|
||||||
|
0, // msgt_unused
|
||||||
|
},
|
||||||
|
MACH_MSG_TYPE_CHAR, // msgtl_name
|
||||||
|
8, // msgtl_size
|
||||||
|
2048, // msgtl_number
|
||||||
|
};
|
||||||
|
|
||||||
|
mach_msg_type_t mach_msg_type_int64 =
|
||||||
|
{
|
||||||
|
(unsigned char) MACH_MSG_TYPE_INTEGER_64, // msgt_name
|
||||||
|
64, // msgt_size
|
||||||
|
1, // msgt_number
|
||||||
|
1, // msgt_inline
|
||||||
|
0, // msgt_longform
|
||||||
|
0, // msgt_deallocate
|
||||||
|
0, // msgt_unused
|
||||||
|
};
|
||||||
|
|
||||||
kern_return_t
|
kern_return_t
|
||||||
__syscall (mach_port_t port, int sys_call)
|
__syscall (mach_port_t port, int sys_call)
|
||||||
{
|
{
|
||||||
|
@ -97,3 +124,20 @@ __syscall_get (mach_port_t port, int sys_call, mach_msg_header_t *message, size_
|
||||||
MACH_MSG_TIMEOUT_NONE,
|
MACH_MSG_TIMEOUT_NONE,
|
||||||
MACH_PORT_NULL);
|
MACH_PORT_NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kern_return_t
|
||||||
|
__syscall_put (mach_port_t port, int sys_call, mach_msg_header_t *message, size_t size)
|
||||||
|
{
|
||||||
|
message->msgh_bits |= MACH_MSGH_BITS (MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE);
|
||||||
|
message->msgh_remote_port = port;
|
||||||
|
message->msgh_local_port = __mach_reply_port ();
|
||||||
|
message->msgh_seqno = 0;
|
||||||
|
message->msgh_id = sys_call;
|
||||||
|
return __mach_msg (message,
|
||||||
|
MACH_SEND_MSG|MACH_RCV_MSG|MACH_MSG_OPTION_NONE,
|
||||||
|
message->msgh_size,
|
||||||
|
size,
|
||||||
|
message->msgh_local_port,
|
||||||
|
MACH_MSG_TIMEOUT_NONE,
|
||||||
|
MACH_PORT_NULL);
|
||||||
|
}
|
||||||
|
|
29
lib/tests/mes/30-eputs.c
Normal file
29
lib/tests/mes/30-eputs.c
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
/* -*-comment-start: "//";comment-end:""-*-
|
||||||
|
* GNU Mes --- Maxwell Equations of Software
|
||||||
|
* Copyright © 2017,2018,2019 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
|
||||||
|
*
|
||||||
|
* This file is part of GNU Mes.
|
||||||
|
*
|
||||||
|
* GNU Mes is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or (at
|
||||||
|
* your option) any later version.
|
||||||
|
*
|
||||||
|
* GNU Mes is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with GNU Mes. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <mes/lib-mini.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
main ()
|
||||||
|
{
|
||||||
|
eputs ("\n");
|
||||||
|
eputs ("Hello, GNU Mes\n");
|
||||||
|
return 0;
|
||||||
|
}
|
2
lib/tests/mes/30-eputs.stderr
Normal file
2
lib/tests/mes/30-eputs.stderr
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
|
||||||
|
Hello, GNU Mes
|
|
@ -24,6 +24,6 @@ int
|
||||||
main ()
|
main ()
|
||||||
{
|
{
|
||||||
oputs ("\n");
|
oputs ("\n");
|
||||||
oputs ("mes\n");
|
oputs ("Hello, GNU Mes\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
2
lib/tests/mes/30-oputs.stdout
Normal file
2
lib/tests/mes/30-oputs.stdout
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
|
||||||
|
Hello, GNU Mes
|
Loading…
Reference in a new issue