File conf.mk changed (mode: 100644) (index 48e53b2..2b6b3bf) |
1 |
1 |
export |
export |
2 |
|
DEBUG?=1 |
|
|
2 |
|
QUIET?= |
3 |
3 |
SYSROOT?= |
SYSROOT?= |
4 |
4 |
KERNEL_VERSION?=$(shell uname -r) |
KERNEL_VERSION?=$(shell uname -r) |
5 |
5 |
ARCH?=$(shell uname -m | sed -e s/i.86/i386/ -e s/parisc64/parisc/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/ -e s/sh.*/sh/) |
ARCH?=$(shell uname -m | sed -e s/i.86/i386/ -e s/parisc64/parisc/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/ -e s/sh.*/sh/) |
|
... |
... |
CFLAGS?=-Wall -Wextra -std=gnu99 -O3 -march=native -fverbose-asm -S -I./ |
18 |
18 |
LDFLAGS?=-O -nostdlib -Bstatic --strip-all |
LDFLAGS?=-O -nostdlib -Bstatic --strip-all |
19 |
19 |
ASFLAGS?= |
ASFLAGS?= |
20 |
20 |
|
|
21 |
|
ifdef DEBUG |
|
22 |
|
CFLAGS+= -DDEBUG |
|
|
21 |
|
ifdef QUIET |
|
22 |
|
CFLAGS+= -DQUIET |
23 |
23 |
endif |
endif |
24 |
24 |
|
|
25 |
25 |
#******************************************************************************* |
#******************************************************************************* |
|
... |
... |
UEVENTS_TIMEOUT=1 |
34 |
34 |
ROOT=\"sdb3\" |
ROOT=\"sdb3\" |
35 |
35 |
ROOT_FS=\"ext4\" |
ROOT_FS=\"ext4\" |
36 |
36 |
ROOT_OPTIONS=\"discard\" |
ROOT_OPTIONS=\"discard\" |
37 |
|
ROOT_INIT=\"/sbin/init\" |
|
|
37 |
|
SYSINIT=\"/init.sh\" |
38 |
38 |
#******************************************************************************* |
#******************************************************************************* |
39 |
39 |
|
|
40 |
40 |
ifdef SCSI_WAIT |
ifdef SCSI_WAIT |
|
... |
... |
CFLAGS+= -DSCSI_WAIT_SCAN |
43 |
43 |
endif |
endif |
44 |
44 |
|
|
45 |
45 |
CFLAGS+= -DROOT=$(ROOT) -DROOT_FS=$(ROOT_FS) -DROOT_OPTIONS=$(ROOT_OPTIONS) |
CFLAGS+= -DROOT=$(ROOT) -DROOT_FS=$(ROOT_FS) -DROOT_OPTIONS=$(ROOT_OPTIONS) |
46 |
|
CFLAGS+= -DUEVENTS_TIMEOUT=$(UEVENTS_TIMEOUT) -DROOT_INIT=$(ROOT_INIT) |
|
|
46 |
|
CFLAGS+= -DUEVENTS_TIMEOUT=$(UEVENTS_TIMEOUT) -DSYSINIT=$(SYSINIT) |
File globals.h changed (mode: 100644) (index e33a5e2..736621e) |
5 |
5 |
//*author:Sylvain BERTRAND <sylvain.bertrand AT gmail dot com> |
//*author:Sylvain BERTRAND <sylvain.bertrand AT gmail dot com> |
6 |
6 |
//* <digital.ragnarok AT gmail dot com> |
//* <digital.ragnarok AT gmail dot com> |
7 |
7 |
//****************************************************************************** |
//****************************************************************************** |
8 |
|
#ifdef DEBUG |
|
|
8 |
|
#ifndef QUIET |
9 |
9 |
#define PRE "initramfs:" |
#define PRE "initramfs:" |
10 |
|
extern k_i g_console; |
|
11 |
10 |
extern k_u8 *g_dprintf_buf; |
extern k_u8 *g_dprintf_buf; |
12 |
11 |
#define DPRINTF_BUF_SZ 1024 |
#define DPRINTF_BUF_SZ 1024 |
13 |
|
#define OUT(f,...) u_a_dprintf(g_console,g_dprintf_buf,DPRINTF_BUF_SZ,(k_u8*)f,\ |
|
|
12 |
|
#define OUT(f,...) u_a_dprintf(0,g_dprintf_buf,DPRINTF_BUF_SZ,(k_u8*)f,\ |
14 |
13 |
__VA_ARGS__) |
__VA_ARGS__) |
15 |
|
#define OUTC(s) sysc(write,3,g_console,s,sizeof(s)) |
|
|
14 |
|
#define OUTC(s) sysc(write,3,0,s,sizeof(s)) |
16 |
15 |
#else |
#else |
17 |
16 |
#define PRE |
#define PRE |
18 |
17 |
#define OUT(f,...) (void)0; |
#define OUT(f,...) (void)0; |
File init.c changed (mode: 100644) (index 5a1f1d1..b999a45) |
11 |
11 |
#include <ulinux/dirent.h> |
#include <ulinux/dirent.h> |
12 |
12 |
#include <ulinux/socket/socket.h> |
#include <ulinux/socket/socket.h> |
13 |
13 |
#include <ulinux/socket/netlink.h> |
#include <ulinux/socket/netlink.h> |
14 |
|
#ifdef DEBUG |
|
|
14 |
|
#include <ulinux/wait.h> |
|
15 |
|
#include <ulinux/signal/signal.h> |
|
16 |
|
#include <ulinux/signal/siginfo.h> |
|
17 |
|
|
|
18 |
|
#ifndef QUIET |
15 |
19 |
#include <ulinux/file.h> |
#include <ulinux/file.h> |
16 |
20 |
#include <ulinux/stat.h> |
#include <ulinux/stat.h> |
17 |
21 |
#include <ulinux/mmap.h> |
#include <ulinux/mmap.h> |
18 |
|
#include <ulinux/signal/signal.h> |
|
19 |
22 |
|
|
20 |
23 |
#include <stdarg.h> |
#include <stdarg.h> |
21 |
24 |
#include <ulinux/utils/ascii/string/vsprintf.h> |
#include <ulinux/utils/ascii/string/vsprintf.h> |
|
23 |
26 |
|
|
24 |
27 |
#include "modules.h" |
#include "modules.h" |
25 |
28 |
#include "uevents.h" |
#include "uevents.h" |
|
29 |
|
#include "ramfs.h" |
26 |
30 |
#include "globals.h" |
#include "globals.h" |
27 |
31 |
|
|
28 |
|
#ifdef DEBUG |
|
|
32 |
|
#ifndef QUIET |
29 |
33 |
k_u8 *g_dprintf_buf; |
k_u8 *g_dprintf_buf; |
30 |
|
k_i g_console; |
|
31 |
34 |
#endif |
#endif |
32 |
35 |
|
|
33 |
36 |
static void sigs_setup(void) |
static void sigs_setup(void) |
|
... |
... |
static void newroot_mount(void) |
55 |
58 |
|
|
56 |
59 |
} |
} |
57 |
60 |
|
|
58 |
|
static void ramfs_cleanup(void) |
|
59 |
|
{ |
|
60 |
|
//TODO:eraze everything except /newroot |
|
61 |
|
} |
|
62 |
|
|
|
63 |
61 |
static void newroot_chdir() |
static void newroot_chdir() |
64 |
62 |
{ |
{ |
65 |
63 |
OUTC(PRE "chdir to /newroot..."); |
OUTC(PRE "chdir to /newroot..."); |
|
... |
... |
static void newroot_chroot(void) |
93 |
91 |
OUTC("done\n"); |
OUTC("done\n"); |
94 |
92 |
} |
} |
95 |
93 |
|
|
96 |
|
static void init_execve(void) |
|
|
94 |
|
static k_i sysinit_clone(void) |
97 |
95 |
{ |
{ |
98 |
|
k_l r=sysc(execve,4,ROOT_INIT,0,0,0); |
|
|
96 |
|
OUTC(PRE "clone and execve " SYSINIT "...\n"); |
|
97 |
|
k_l r=sysc(clone,5,K_SIGCHLD,0,0,0,0); |
99 |
98 |
if(K_ISERR(r)){ |
if(K_ISERR(r)){ |
100 |
|
OUT("ERROR(%ld):unable to run /sbin/init\n",r); |
|
|
99 |
|
OUT("ERROR(%ld):unable to clone for sysinit\n",r); |
101 |
100 |
sysc(exit_group,1,-1); |
sysc(exit_group,1,-1); |
102 |
101 |
} |
} |
|
102 |
|
|
|
103 |
|
if(r) return (k_i)r; |
|
104 |
|
|
|
105 |
|
r=sysc(execve,4,SYSINIT,0,0,0); |
|
106 |
|
if(K_ISERR(r)) |
|
107 |
|
OUT("ERROR(%ld):unable to run " SYSINIT "\n",r); |
|
108 |
|
sysc(exit_group,1,-1); |
|
109 |
|
__builtin_unreachable(); |
103 |
110 |
} |
} |
104 |
111 |
|
|
105 |
|
void _start(void) |
|
|
112 |
|
static k_i getty_spawn(k_u8 *tty) |
106 |
113 |
{ |
{ |
107 |
|
# ifdef DEBUG |
|
108 |
|
//k_l r=sysc(open,3,"/dev/console",K_O_WRONLY|K_O_CLOEXEC,0); |
|
109 |
|
k_l r=sysc(open,3,"/dev/console",K_O_WRONLY,0); |
|
110 |
|
if(K_ISERR(r)) sysc(exit_group,1,-1); |
|
111 |
|
g_console=(k_i)r; |
|
|
114 |
|
OUT(PRE "getty %s...\n",tty); |
|
115 |
|
k_l r=sysc(clone,5,K_SIGCHLD,0,0,0,0); |
|
116 |
|
if(K_ISERR(r)){ |
|
117 |
|
OUT("ERROR(%ld):unable to clone for getty\n",r); |
|
118 |
|
sysc(exit_group,1,-1); |
|
119 |
|
} |
112 |
120 |
|
|
|
121 |
|
if(r) return r; |
|
122 |
|
|
|
123 |
|
r=sysc(setsid,0); |
|
124 |
|
if(K_ISERR(r)){ |
|
125 |
|
OUT("ERROR(%ld):unable to setsid the getty clone\n",r); |
|
126 |
|
sysc(exit_group,1,-1); |
|
127 |
|
} |
|
128 |
|
|
|
129 |
|
k_u8 *argv[]={(k_u8*)"/sbin/agetty",tty,0}; |
|
130 |
|
r=sysc(execve,4,"/sbin/agetty",argv,0,0); |
|
131 |
|
if(K_ISERR(r)){ |
|
132 |
|
OUT("ERROR(%ld):unable to run /sbin/agetty on %s\n",r,tty); |
|
133 |
|
sysc(exit_group,1,-1); |
|
134 |
|
} |
|
135 |
|
__builtin_unreachable(); |
|
136 |
|
} |
|
137 |
|
|
|
138 |
|
static void sysinit(void) |
|
139 |
|
{ |
|
140 |
|
k_i pid=sysinit_clone(); |
|
141 |
|
k_l r=sysc(waitid,5,K_P_PID,pid,0,K_WEXITED,0); |
|
142 |
|
if(K_ISERR(r)){ |
|
143 |
|
OUT("ERROR(%ld):unable to wait for " SYSINIT " to exit\n",r); |
|
144 |
|
sysc(exit_group,1,-1); |
|
145 |
|
} |
|
146 |
|
} |
|
147 |
|
|
|
148 |
|
static void loop(void) |
|
149 |
|
{ |
|
150 |
|
k_i tty1=getty_spawn((k_u8*)"tty1"); |
|
151 |
|
k_i tty2=getty_spawn((k_u8*)"tty2"); |
|
152 |
|
while(1){ |
|
153 |
|
struct k_siginfo siginfo; |
|
154 |
|
k_l r=sysc(waitid,5,K_P_ALL,0,&siginfo,K_WEXITED,0); |
|
155 |
|
if(K_ISERR(r)){ |
|
156 |
|
OUT("ERROR(%ld):unable to wait properly for getty clones to exit\n",r); |
|
157 |
|
sysc(exit_group,1,-1); |
|
158 |
|
} |
|
159 |
|
if(siginfo.fields.sigchld.pid==tty1) tty1=getty_spawn((k_u8*)"tty1"); |
|
160 |
|
else if(siginfo.fields.sigchld.pid==tty2) tty2=getty_spawn((k_u8*)"tty2"); |
|
161 |
|
else{ |
|
162 |
|
OUT("ERROR:dead init child(pid=%d) is unknown)\n", |
|
163 |
|
siginfo.fields.sigchld.pid); |
|
164 |
|
sysc(exit_group,1,-1); |
|
165 |
|
} |
|
166 |
|
} |
|
167 |
|
} |
|
168 |
|
|
|
169 |
|
//fds 0,1 and 2 are rw /dev/console, see linux/init/main.c |
|
170 |
|
void _start(void) |
|
171 |
|
{ |
|
172 |
|
#ifndef QUIET |
113 |
173 |
static k_u8 dprintf_buf[DPRINTF_BUF_SZ]; |
static k_u8 dprintf_buf[DPRINTF_BUF_SZ]; |
114 |
174 |
g_dprintf_buf=dprintf_buf; |
g_dprintf_buf=dprintf_buf; |
115 |
|
# endif |
|
|
175 |
|
#endif |
|
176 |
|
//---------------------------------------------------------------------------- |
|
177 |
|
//mount rootfs |
116 |
178 |
sigs_setup(); |
sigs_setup(); |
117 |
179 |
uevents_setup(); |
uevents_setup(); |
118 |
180 |
modules_load(); |
modules_load(); |
119 |
181 |
uevents_process(); |
uevents_process(); |
|
182 |
|
uevents_cleanup(); |
120 |
183 |
newroot_mount(); |
newroot_mount(); |
121 |
184 |
ramfs_cleanup(); |
ramfs_cleanup(); |
122 |
185 |
newroot_chdir(); |
newroot_chdir(); |
123 |
186 |
newroot_move(); |
newroot_move(); |
124 |
187 |
newroot_chroot(); |
newroot_chroot(); |
125 |
|
init_execve(); |
|
|
188 |
|
//---------------------------------------------------------------------------- |
|
189 |
|
sysinit(); |
|
190 |
|
loop(); |
126 |
191 |
} |
} |
File makefile changed (mode: 100644) (index 970faf7..2eebf4f) |
... |
... |
$(MODULES_DIR) \ |
9 |
9 |
$(CPIO_DIR)/dev \ |
$(CPIO_DIR)/dev \ |
10 |
10 |
$(CPIO_DIR)/newroot |
$(CPIO_DIR)/newroot |
11 |
11 |
|
|
12 |
|
|
|
13 |
12 |
OBJS=\ |
OBJS=\ |
14 |
13 |
$(OBJ_DIR)/init.o \ |
$(OBJ_DIR)/init.o \ |
15 |
14 |
$(OBJ_DIR)/modules.o \ |
$(OBJ_DIR)/modules.o \ |
16 |
15 |
$(OBJ_DIR)/uevents.o \ |
$(OBJ_DIR)/uevents.o \ |
17 |
|
$(OBJ_DIR)/uevent.o |
|
18 |
|
|
|
19 |
|
ULINUX_DEBUG_OBJS=\ |
|
20 |
|
$(OBJ_DIR)/decimal.o |
|
|
16 |
|
$(OBJ_DIR)/uevent.o \ |
|
17 |
|
$(OBJ_DIR)/ramfs.o |
21 |
18 |
|
|
22 |
|
ifdef DEBUG |
|
23 |
|
ULINUX_DEBUG_OBJS+= \ |
|
24 |
|
$(OBJ_DIR)/mem.o \ |
|
|
19 |
|
ULINUX_OBJS=\ |
|
20 |
|
$(OBJ_DIR)/decimal.o \ |
25 |
21 |
$(OBJ_DIR)/string.o \ |
$(OBJ_DIR)/string.o \ |
|
22 |
|
$(OBJ_DIR)/mem.o |
|
23 |
|
OBJS+= $(ULINUX_OBJS) |
|
24 |
|
|
|
25 |
|
ifndef QUIET |
|
26 |
|
ULINUX_NQUIET_OBJS+= \ |
26 |
27 |
$(OBJ_DIR)/vsprintf.o |
$(OBJ_DIR)/vsprintf.o |
|
28 |
|
OBJS+= $(ULINUX_NQUIET_OBJS) |
27 |
29 |
endif |
endif |
28 |
30 |
|
|
29 |
|
OBJS+= $(ULINUX_DEBUG_OBJS) |
|
30 |
|
|
|
|
31 |
|
#****************************************************************************** |
31 |
32 |
help: |
help: |
32 |
33 |
@echo "targets are 'all', 'help'(this output), 'clean'" |
@echo "targets are 'all', 'help'(this output), 'clean'" |
33 |
34 |
@echo -e "you can configure the build with the following variables:\\n\ |
@echo -e "you can configure the build with the following variables:\\n\ |
|
... |
... |
ulinux/arch: |
47 |
48 |
ln -s archs/$(ARCH) ulinux/arch |
ln -s archs/$(ARCH) ulinux/arch |
48 |
49 |
|
|
49 |
50 |
#=============================================================================== |
#=============================================================================== |
50 |
|
ifdef DEBUG |
|
51 |
|
$(S_DIR)/mem.s:ulinux/arch/utils/mem.c |
|
52 |
|
$(CC) $(CFLAGS) $< -o $@ |
|
53 |
|
$(OBJ_DIR)/mem.o:$(S_DIR)/mem.s |
|
54 |
|
$(AS) $(ASFLAGS) $< -o $@ |
|
55 |
|
|
|
56 |
|
$(S_DIR)/string.s:ulinux/utils/ascii/string/string.c |
|
57 |
|
$(CC) $(CFLAGS) $< -o $@ |
|
58 |
|
$(OBJ_DIR)/string.o:$(S_DIR)/string.s |
|
59 |
|
$(AS) $(ASFLAGS) $< -o $@ |
|
60 |
|
|
|
|
51 |
|
ifndef QUIET |
61 |
52 |
$(S_DIR)/vsprintf.s:ulinux/utils/ascii/string/vsprintf.c |
$(S_DIR)/vsprintf.s:ulinux/utils/ascii/string/vsprintf.c |
62 |
53 |
$(CC) $(CFLAGS) $< -o $@ |
$(CC) $(CFLAGS) $< -o $@ |
63 |
54 |
$(OBJ_DIR)/vsprintf.o:$(S_DIR)/vsprintf.s |
$(OBJ_DIR)/vsprintf.o:$(S_DIR)/vsprintf.s |
|
... |
... |
$(OBJ_DIR)/vsprintf.o:$(S_DIR)/vsprintf.s |
65 |
56 |
endif |
endif |
66 |
57 |
#=============================================================================== |
#=============================================================================== |
67 |
58 |
|
|
|
59 |
|
#=============================================================================== |
|
60 |
|
#ulinux objets |
|
61 |
|
$(S_DIR)/mem.s:ulinux/arch/utils/mem.c |
|
62 |
|
$(CC) $(CFLAGS) $< -o $@ |
|
63 |
|
$(OBJ_DIR)/mem.o:$(S_DIR)/mem.s |
|
64 |
|
$(AS) $(ASFLAGS) $< -o $@ |
|
65 |
|
|
68 |
66 |
$(S_DIR)/decimal.s:ulinux/utils/ascii/string/conv/decimal/decimal.c |
$(S_DIR)/decimal.s:ulinux/utils/ascii/string/conv/decimal/decimal.c |
69 |
67 |
$(CC) $(CFLAGS) $< -o $@ |
$(CC) $(CFLAGS) $< -o $@ |
70 |
68 |
$(OBJ_DIR)/decimal.o:$(S_DIR)/decimal.s |
$(OBJ_DIR)/decimal.o:$(S_DIR)/decimal.s |
71 |
69 |
$(AS) $(ASFLAGS) $< -o $@ |
$(AS) $(ASFLAGS) $< -o $@ |
72 |
70 |
|
|
|
71 |
|
$(S_DIR)/string.s:ulinux/utils/ascii/string/string.c |
|
72 |
|
$(CC) $(CFLAGS) $< -o $@ |
|
73 |
|
$(OBJ_DIR)/string.o:$(S_DIR)/string.s |
|
74 |
|
$(AS) $(ASFLAGS) $< -o $@ |
|
75 |
|
#=============================================================================== |
|
76 |
|
|
|
77 |
|
#the default kernel included initramfs has /dev/console and more |
|
78 |
|
#the external initramfs is an overlay of this internal default initramfs |
|
79 |
|
#see linux/usr |
73 |
80 |
$(CPIO_DIR)/dev/console: |
$(CPIO_DIR)/dev/console: |
74 |
81 |
mknod --mode=0600 $(CPIO_DIR)/dev/console c 5 1 |
mknod --mode=0600 $(CPIO_DIR)/dev/console c 5 1 |
75 |
82 |
|
|
|
... |
... |
$(BUILD_DIR)/initramfs.cpio:$(CPIO_DIR)/init $(CPIO_DIR)/dev/console |
82 |
89 |
$(BUILD_DIR)/initramfs.cpio.xz:$(BUILD_DIR)/initramfs.cpio |
$(BUILD_DIR)/initramfs.cpio.xz:$(BUILD_DIR)/initramfs.cpio |
83 |
90 |
xz --force --check=crc32 --extreme --stdout $< >$@ |
xz --force --check=crc32 --extreme --stdout $< >$@ |
84 |
91 |
|
|
85 |
|
$(S_DIR)/modules.s:modules.c modules_list.h |
|
|
92 |
|
$(S_DIR)/modules.s:modules.c modules_list.h globals.h |
86 |
93 |
$(CC) $(CFLAGS) $< -o $@ |
$(CC) $(CFLAGS) $< -o $@ |
87 |
94 |
$(OBJ_DIR)/modules.o:$(S_DIR)/modules.s |
$(OBJ_DIR)/modules.o:$(S_DIR)/modules.s |
88 |
95 |
$(AS) $(ASFLAGS) $< -o $@ |
$(AS) $(ASFLAGS) $< -o $@ |
89 |
96 |
|
|
90 |
|
$(S_DIR)/uevent.s:uevent.c |
|
|
97 |
|
$(S_DIR)/uevent.s:uevent.c globals.h |
91 |
98 |
$(CC) $(CFLAGS) $< -o $@ |
$(CC) $(CFLAGS) $< -o $@ |
92 |
99 |
$(OBJ_DIR)/uevent.o:$(S_DIR)/uevent.s |
$(OBJ_DIR)/uevent.o:$(S_DIR)/uevent.s |
93 |
100 |
$(AS) $(ASFLAGS) $< -o $@ |
$(AS) $(ASFLAGS) $< -o $@ |
94 |
101 |
|
|
95 |
|
$(S_DIR)/uevents.s:uevents.c |
|
|
102 |
|
$(S_DIR)/uevents.s:uevents.c globals.h |
96 |
103 |
$(CC) $(CFLAGS) $< -o $@ |
$(CC) $(CFLAGS) $< -o $@ |
97 |
104 |
$(OBJ_DIR)/uevents.o:$(S_DIR)/uevents.s |
$(OBJ_DIR)/uevents.o:$(S_DIR)/uevents.s |
98 |
105 |
$(AS) $(ASFLAGS) $< -o $@ |
$(AS) $(ASFLAGS) $< -o $@ |
|
106 |
|
|
|
107 |
|
$(S_DIR)/ramfs.s:ramfs.c globals.h |
|
108 |
|
$(CC) $(CFLAGS) $< -o $@ |
|
109 |
|
$(OBJ_DIR)/ramfs.o:$(S_DIR)/ramfs.s |
|
110 |
|
$(AS) $(ASFLAGS) $< -o $@ |
99 |
111 |
|
|
100 |
|
$(S_DIR)/init.s:init.c modules.h |
|
|
112 |
|
$(S_DIR)/init.s:init.c modules.h uevents.h ramfs.h globals.h |
101 |
113 |
$(CC) $(CFLAGS) $< -o $@ |
$(CC) $(CFLAGS) $< -o $@ |
102 |
114 |
$(OBJ_DIR)/init.o:$(S_DIR)/init.s |
$(OBJ_DIR)/init.o:$(S_DIR)/init.s |
103 |
115 |
$(AS) $(ASFLAGS) $< -o $@ |
$(AS) $(ASFLAGS) $< -o $@ |
File modules.c changed (mode: 100644) (index 25c6426..899930b) |
12 |
12 |
#include <ulinux/error.h> |
#include <ulinux/error.h> |
13 |
13 |
#include <ulinux/file.h> |
#include <ulinux/file.h> |
14 |
14 |
|
|
15 |
|
#ifdef DEBUG |
|
|
15 |
|
#ifndef QUIET |
16 |
16 |
#include <stdarg.h> |
#include <stdarg.h> |
17 |
17 |
#include <ulinux/utils/ascii/string/vsprintf.h> |
#include <ulinux/utils/ascii/string/vsprintf.h> |
18 |
18 |
#endif |
#endif |
|
22 |
22 |
|
|
23 |
23 |
static void module_load(k_u8 *m) |
static void module_load(k_u8 *m) |
24 |
24 |
{ |
{ |
25 |
|
k_i fd=(k_i)sysc(open,3,m,K_O_RDONLY|K_O_CLOEXEC,0); |
|
|
25 |
|
k_i fd=(k_i)sysc(open,3,m,K_O_RDONLY,0); |
26 |
26 |
if(K_ISERR(fd)){ |
if(K_ISERR(fd)){ |
27 |
|
OUT("unable to open module(%ld)\n",fd); |
|
28 |
|
goto err; |
|
|
27 |
|
OUT("ERROR(%d):unable to open module file\n",fd); |
|
28 |
|
sysc(exit_group,1,-1); |
29 |
29 |
} |
} |
30 |
30 |
|
|
31 |
31 |
struct k_stat m_stat; |
struct k_stat m_stat; |
32 |
32 |
k_l r=sysc(fstat,2,fd,&m_stat); |
k_l r=sysc(fstat,2,fd,&m_stat); |
33 |
33 |
if(K_ISERR(r)){ |
if(K_ISERR(r)){ |
34 |
|
OUT("unable to stat module(%ld)\n",r); |
|
35 |
|
goto err; |
|
|
34 |
|
OUT("ERROR(%ld):unable to stat module file\n",r); |
|
35 |
|
sysc(exit_group,1,-1); |
36 |
36 |
} |
} |
37 |
|
OUT("size=%lu...",m_stat.st_size); |
|
|
37 |
|
OUT("size=%lu...",m_stat.sz); |
38 |
38 |
|
|
39 |
|
k_l addr=sysc(mmap,6,0,m_stat.st_size,K_PROT_READ, |
|
|
39 |
|
k_l addr=sysc(mmap,6,0,m_stat.sz,K_PROT_READ, |
40 |
40 |
K_MAP_PRIVATE|K_MAP_POPULATE,fd,0); |
K_MAP_PRIVATE|K_MAP_POPULATE,fd,0); |
41 |
41 |
if(K_ISERR(addr)){ |
if(K_ISERR(addr)){ |
42 |
|
OUT("unable to mmap module(%ld)\n",addr); |
|
43 |
|
goto err; |
|
|
42 |
|
OUT("ERROR(%ld):unable to mmap module file\n",addr); |
|
43 |
|
sysc(exit_group,1,-1); |
44 |
44 |
} |
} |
45 |
45 |
|
|
46 |
|
r=sysc(init_module,3,addr,m_stat.st_size,""); |
|
|
46 |
|
r=sysc(init_module,3,addr,m_stat.sz,""); |
47 |
47 |
if(K_ISERR(r)){ |
if(K_ISERR(r)){ |
48 |
|
OUT("unable init module(%ld)\n",r); |
|
49 |
|
goto err; |
|
|
48 |
|
OUT("ERROR(%ld):unable init module\n",r); |
|
49 |
|
sysc(exit_group,1,-1); |
|
50 |
|
} |
|
51 |
|
|
|
52 |
|
do r=sysc(close,1,fd); while(r==-K_EINTR); |
|
53 |
|
if(K_ISERR(r)){ |
|
54 |
|
OUT("ERROR(%ld):unable to close module file\n",r); |
|
55 |
|
sysc(exit_group,1,-1); |
50 |
56 |
} |
} |
51 |
57 |
return; |
return; |
52 |
|
err: |
|
53 |
|
sysc(exit_group,1,-1); |
|
54 |
58 |
} |
} |
55 |
59 |
|
|
56 |
60 |
void modules_load(void) |
void modules_load(void) |
|
... |
... |
void modules_load(void) |
63 |
67 |
OUTC("done\n"); |
OUTC("done\n"); |
64 |
68 |
++m; |
++m; |
65 |
69 |
} |
} |
|
70 |
|
|
|
71 |
|
#ifdef SCSI_WAIT_SCAN |
|
72 |
|
k_l r=sysc(delete_module,1,"scsi_wait_scan"); |
|
73 |
|
if(K_ISERR(r)){ |
|
74 |
|
OUT(PRE "ERROR(%ld):unable to delete the scsi_wait_scan module\n",r); |
|
75 |
|
sysc(exit_group,1,-1); |
|
76 |
|
} |
|
77 |
|
#endif |
66 |
78 |
} |
} |
File ramfs.c added (mode: 100644) (index 0000000..d0b3b3d) |
|
1 |
|
//****************************************************************************** |
|
2 |
|
//*this code is protected by the GNU affero GPLv3 |
|
3 |
|
//*author:Sylvain BERTRAND <sylvain.bertrand AT gmail dot com> |
|
4 |
|
//* <digital.ragnarok AT gmail dot com> |
|
5 |
|
//****************************************************************************** |
|
6 |
|
#include <ulinux/compiler_types.h> |
|
7 |
|
#include <ulinux/types.h> |
|
8 |
|
#include <ulinux/error.h> |
|
9 |
|
#include <ulinux/fs.h> |
|
10 |
|
#include <ulinux/file.h> |
|
11 |
|
#include <ulinux/dirent.h> |
|
12 |
|
#include <ulinux/utils/ascii/string/string.h> |
|
13 |
|
#include <ulinux/sysc.h> |
|
14 |
|
|
|
15 |
|
#ifndef QUIET |
|
16 |
|
#include <stdarg.h> |
|
17 |
|
#include <ulinux/utils/ascii/string/vsprintf.h> |
|
18 |
|
#endif |
|
19 |
|
|
|
20 |
|
#include "globals.h" |
|
21 |
|
|
|
22 |
|
#define DIRENTS_BUF_SZ 8192 |
|
23 |
|
|
|
24 |
|
static k_ut is_current(k_u8 *n) |
|
25 |
|
{ |
|
26 |
|
if(n[0]=='.'&&n[1]==0) return 1; |
|
27 |
|
return 0; |
|
28 |
|
} |
|
29 |
|
|
|
30 |
|
static k_ut is_parent(k_u8 *n) |
|
31 |
|
{ |
|
32 |
|
if(n[0]=='.'&&n[1]=='.'&&n[2]==0) return 1; |
|
33 |
|
return 0; |
|
34 |
|
} |
|
35 |
|
|
|
36 |
|
static k_ut is_newroot(k_u8 *n) |
|
37 |
|
{ |
|
38 |
|
#define NEWROOT (k_u8*)"newroot" |
|
39 |
|
return u_a_strncmp(n,NEWROOT,sizeof(NEWROOT)-1)?0:1; |
|
40 |
|
} |
|
41 |
|
|
|
42 |
|
static void unlink(k_i parent_fd,k_u8 *n,k_i flgs) |
|
43 |
|
{ |
|
44 |
|
k_l r=sysc(unlinkat,3,parent_fd,n,flgs); |
|
45 |
|
if(K_ISERR(r)){ |
|
46 |
|
OUT("ERROR(%ld):unable to remove dir entry:%s\n",r,n); |
|
47 |
|
sysc(exit_group,1,-1); |
|
48 |
|
} |
|
49 |
|
} |
|
50 |
|
|
|
51 |
|
static void dir_del(k_i parent_fd); |
|
52 |
|
static void dirent_del(k_i parent_fd,struct k_dirent64 *d) |
|
53 |
|
{ |
|
54 |
|
if(d->type==K_DT_DIR){ |
|
55 |
|
if(!is_current(d->name)&&!is_parent(d->name)){ |
|
56 |
|
k_i dir_fd; |
|
57 |
|
do |
|
58 |
|
dir_fd=(k_i)sysc(openat,4,parent_fd,d->name,K_O_RDONLY|K_O_NONBLOCK,0); |
|
59 |
|
while(dir_fd==-K_EINTR); |
|
60 |
|
if(K_ISERR(dir_fd)){ |
|
61 |
|
OUT("ERROR(%d):unable to open subdir:%s\n",dir_fd,d->name); |
|
62 |
|
sysc(exit_group,1,-1); |
|
63 |
|
}else{ |
|
64 |
|
dir_del(dir_fd); |
|
65 |
|
k_l r; |
|
66 |
|
do r=sysc(close,1,dir_fd); while(r==-K_EINTR); |
|
67 |
|
if(K_ISERR(r)){ |
|
68 |
|
OUT("ERROR(%ld):unable to close dir fd\n",r); |
|
69 |
|
sysc(exit_group,1,-1); |
|
70 |
|
} |
|
71 |
|
} |
|
72 |
|
unlink(parent_fd,d->name,K_AT_REMOVEDIR); |
|
73 |
|
} |
|
74 |
|
}else unlink(parent_fd,d->name,0); |
|
75 |
|
} |
|
76 |
|
|
|
77 |
|
static void dir_del(k_i parent_fd) |
|
78 |
|
{ |
|
79 |
|
k_u8 dirents[DIRENTS_BUF_SZ]; |
|
80 |
|
while(1){ |
|
81 |
|
k_l r=sysc(getdents64,3,parent_fd,dirents,DIRENTS_BUF_SZ); |
|
82 |
|
if(K_ISERR(r)){ |
|
83 |
|
OUT("ERROR(%ld):getdents error\n",r); |
|
84 |
|
sysc(exit_group,1,-1); |
|
85 |
|
} |
|
86 |
|
if(!r) break; |
|
87 |
|
k_l i=0; |
|
88 |
|
while(i<r){ |
|
89 |
|
struct k_dirent64 *d=(struct k_dirent64*)(dirents+i); |
|
90 |
|
dirent_del(parent_fd,d); |
|
91 |
|
i+=d->rec_len; |
|
92 |
|
} |
|
93 |
|
} |
|
94 |
|
} |
|
95 |
|
|
|
96 |
|
void ramfs_cleanup(void) |
|
97 |
|
{ |
|
98 |
|
OUTC(PRE "cleaning ramfs..."); |
|
99 |
|
k_i root_fd; |
|
100 |
|
do |
|
101 |
|
root_fd=(k_i)sysc(open,3,"/",K_O_RDONLY|K_O_NONBLOCK,0); |
|
102 |
|
while(root_fd==-K_EINTR); |
|
103 |
|
if(K_ISERR(root_fd)){ |
|
104 |
|
OUT("ERROR(%d):unable to open root dir\n",root_fd); |
|
105 |
|
sysc(exit_group,1,-1); |
|
106 |
|
} |
|
107 |
|
|
|
108 |
|
k_u8 dirents[DIRENTS_BUF_SZ]; |
|
109 |
|
while(1){ |
|
110 |
|
k_l r=sysc(getdents64,3,root_fd,dirents,DIRENTS_BUF_SZ); |
|
111 |
|
if(K_ISERR(r)){ |
|
112 |
|
OUT("ERROR(%ld):getdents error\n",r); |
|
113 |
|
sysc(exit_group,1,-1); |
|
114 |
|
} |
|
115 |
|
if(!r) break; |
|
116 |
|
k_l i=0; |
|
117 |
|
while(i<r){ |
|
118 |
|
struct k_dirent64 *d=(struct k_dirent64*)(dirents+i); |
|
119 |
|
if(!is_newroot(d->name)) dirent_del(root_fd,d); |
|
120 |
|
i+=d->rec_len; |
|
121 |
|
} |
|
122 |
|
} |
|
123 |
|
k_l r; |
|
124 |
|
do r=sysc(close,1,root_fd); while(r==-K_EINTR); |
|
125 |
|
if(K_ISERR(r)){ |
|
126 |
|
OUT("ERROR(%ld):unable to root dir fd\n",r); |
|
127 |
|
sysc(exit_group,1,-1); |
|
128 |
|
} |
|
129 |
|
OUTC("done\n"); |
|
130 |
|
} |
File uevents.c changed (mode: 100644) (index 32961ea..cef85f6) |
12 |
12 |
#include <ulinux/socket/netlink.h> |
#include <ulinux/socket/netlink.h> |
13 |
13 |
#include <ulinux/epoll.h> |
#include <ulinux/epoll.h> |
14 |
14 |
#include <ulinux/utils/mem.h> |
#include <ulinux/utils/mem.h> |
15 |
|
#ifdef DEBUG |
|
|
15 |
|
#ifndef QUIET |
16 |
16 |
#include <ulinux/file.h> |
#include <ulinux/file.h> |
17 |
17 |
#include <ulinux/stat.h> |
#include <ulinux/stat.h> |
18 |
18 |
#include <ulinux/mmap.h> |
#include <ulinux/mmap.h> |
|
27 |
27 |
static k_i ep_fd; |
static k_i ep_fd; |
28 |
28 |
static k_i s; |
static k_i s; |
29 |
29 |
|
|
|
30 |
|
void uevents_cleanup(void) |
|
31 |
|
{ |
|
32 |
|
k_l r; |
|
33 |
|
do r=sysc(close,1,ep_fd); while(r==-K_EINTR); |
|
34 |
|
if(K_ISERR(r)){ |
|
35 |
|
OUT("ERROR(%ld):unable to close epoll fd\n",r); |
|
36 |
|
sysc(exit_group,1,-1); |
|
37 |
|
} |
|
38 |
|
|
|
39 |
|
do r=sysc(close,1,s); while(r==-K_EINTR); |
|
40 |
|
if(K_ISERR(r)){ |
|
41 |
|
OUT("ERROR(%ld):unable to close netlink socket\n",r); |
|
42 |
|
sysc(exit_group,1,-1); |
|
43 |
|
} |
|
44 |
|
} |
|
45 |
|
|
30 |
46 |
void uevents_setup(void) |
void uevents_setup(void) |
31 |
47 |
{ |
{ |
32 |
48 |
OUTC(PRE "setting up uevent..."); |
OUTC(PRE "setting up uevent..."); |
33 |
|
ep_fd=(k_i)sysc(epoll_create1,1,K_EPOLL_CLOEXEC); |
|
|
49 |
|
ep_fd=(k_i)sysc(epoll_create1,1,0); |
34 |
50 |
if(K_ISERR(ep_fd)){ |
if(K_ISERR(ep_fd)){ |
35 |
51 |
OUT("ERROR(%d):unable to create epoll fd\n",ep_fd); |
OUT("ERROR(%d):unable to create epoll fd\n",ep_fd); |
36 |
52 |
sysc(exit_group,1,-1); |
sysc(exit_group,1,-1); |
|
... |
... |
void uevents_setup(void) |
39 |
55 |
//---------------------------------------------------------------------------- |
//---------------------------------------------------------------------------- |
40 |
56 |
|
|
41 |
57 |
//blocking socket |
//blocking socket |
42 |
|
s=(k_i)sysc(socket,3,K_PF_NETLINK,K_SOCK_RAW|K_SO_CLOEXEC, |
|
|
58 |
|
s=(k_i)sysc(socket,3,K_PF_NETLINK,K_SOCK_RAW, |
43 |
59 |
K_NETLINK_KOBJECT_UEVENT); |
K_NETLINK_KOBJECT_UEVENT); |
44 |
60 |
if(K_ISERR(s)){ |
if(K_ISERR(s)){ |
45 |
61 |
OUT("ERROR(%d):unable to create uevent netlink socket\n",s); |
OUT("ERROR(%d):unable to create uevent netlink socket\n",s); |
|
... |
... |
static void uevent_msg(void) |
95 |
111 |
msg.iov_len=1; |
msg.iov_len=1; |
96 |
112 |
|
|
97 |
113 |
k_l r; |
k_l r; |
98 |
|
do{ |
|
99 |
|
r=sysc(recvmsg,3,s,&msg,0); |
|
100 |
|
}while(r==-K_EINTR); |
|
|
114 |
|
do r=sysc(recvmsg,3,s,&msg,0); while(r==-K_EINTR); |
101 |
115 |
if(K_ISERR(r)){ |
if(K_ISERR(r)){ |
102 |
116 |
OUT("ERROR(%ld):unable to receive the uevent\n",r); |
OUT("ERROR(%ld):unable to receive the uevent\n",r); |
103 |
117 |
sysc(exit_group,1,-1); |
sysc(exit_group,1,-1); |
File ulinux/archs/x86_64/signal/siginfo.h added (mode: 100644) (index 0000000..ed710a7) |
|
1 |
|
#ifndef ULINUX_ARCH_SIGNAL_SIGINFO_H |
|
2 |
|
#define ULINUX_ARCH_SIGNAL_SIGINFO_H |
|
3 |
|
//****************************************************************************** |
|
4 |
|
//*this code is protected by the GNU affero GPLv3 |
|
5 |
|
//*author:Sylvain BERTRAND <sylvain.bertrand AT gmail dot com> |
|
6 |
|
//* <digital.ragnarok AT gmail dot com> |
|
7 |
|
//****************************************************************************** |
|
8 |
|
union k_sigval{ |
|
9 |
|
k_i i; |
|
10 |
|
void* ptr; |
|
11 |
|
}; |
|
12 |
|
|
|
13 |
|
#define SI_PREAMBLE_SIZE (4*sizeof(k_i)) |
|
14 |
|
#define SI_MAX_SIZE 128 |
|
15 |
|
#define SI_PAD_SIZE ((SI_MAX_SIZE-SI_PREAMBLE_SIZE)/sizeof(k_i)) |
|
16 |
|
|
|
17 |
|
struct k_siginfo{ |
|
18 |
|
k_i si_signo; |
|
19 |
|
k_i si_errno; |
|
20 |
|
k_i si_code; |
|
21 |
|
|
|
22 |
|
union{ |
|
23 |
|
k_i pad[SI_PAD_SIZE]; |
|
24 |
|
|
|
25 |
|
//kill() |
|
26 |
|
struct{ |
|
27 |
|
k_i pid;//sender's pid |
|
28 |
|
k_u uid;//sender's uid |
|
29 |
|
} kill; |
|
30 |
|
|
|
31 |
|
//posix.1b timers |
|
32 |
|
struct{ |
|
33 |
|
k_i tid;//timer id |
|
34 |
|
k_i overrun;//overrun count |
|
35 |
|
union k_sigval sigval;//same as below |
|
36 |
|
k_i sys_private;//not to be passed to user |
|
37 |
|
} timer; |
|
38 |
|
|
|
39 |
|
//posix.1b signals |
|
40 |
|
struct{ |
|
41 |
|
k_i pid;//sender's pid |
|
42 |
|
k_u uid;//sender's uid |
|
43 |
|
union k_sigval sigval; |
|
44 |
|
} rt; |
|
45 |
|
|
|
46 |
|
//SIGCHLD |
|
47 |
|
struct{ |
|
48 |
|
k_i pid;//which child |
|
49 |
|
k_u uid;//sender's uid |
|
50 |
|
k_i status;//exit code |
|
51 |
|
k_l utime; |
|
52 |
|
k_l stime; |
|
53 |
|
} sigchld; |
|
54 |
|
|
|
55 |
|
//SIGILL, SIGFPE, SIGSEGV, SIGBUS |
|
56 |
|
struct{ |
|
57 |
|
void* addr;//faulting insn/memory ref. |
|
58 |
|
k_s addr_lsb;//lsb of the reported address |
|
59 |
|
} sigfault; |
|
60 |
|
|
|
61 |
|
//SIGPOLL |
|
62 |
|
struct{ |
|
63 |
|
k_l band;//POLL_IN, POLL_OUT, POLL_MSG |
|
64 |
|
k_i fd; |
|
65 |
|
} sigpoll; |
|
66 |
|
} fields; |
|
67 |
|
}; |
|
68 |
|
#endif |
File ulinux/signal/signal.h changed (mode: 100644) (index 4712736..64a71ea) |
1 |
|
//********************************************************************************************** |
|
|
1 |
|
#ifndef ULINUX_SIGNAL_SIGNAL_H |
|
2 |
|
#define ULINUX_SIGNAL_SIGNAL_H |
|
3 |
|
//****************************************************************************** |
2 |
4 |
//*this code is protected by the GNU affero GPLv3 |
//*this code is protected by the GNU affero GPLv3 |
3 |
|
//*author:Sylvain BERTRAND (sylvain.bertrand AT gmail dot com) |
|
4 |
|
//********************************************************************************************** |
|
5 |
|
#ifndef ULINUX_SIGNAL_H |
|
6 |
|
#define ULINUX_SIGNAL_H |
|
|
5 |
|
//*author:Sylvain BERTRAND <sylvain.bertrand AT gmail dot com> |
|
6 |
|
//* <digital.ragnarok AT gmail dot com> |
|
7 |
|
//****************************************************************************** |
7 |
8 |
#include <ulinux/arch/signal/signal.h> |
#include <ulinux/arch/signal/signal.h> |
8 |
9 |
//In POSIX a signal is sent either to a specific thread (Linux task) |
//In POSIX a signal is sent either to a specific thread (Linux task) |
9 |
10 |
//or to the process as a whole (Linux thread group). How the signal |
//or to the process as a whole (Linux thread group). How the signal |
|
82 |
83 |
#define K_SIG_SETMASK 2//for setting the signal mask |
#define K_SIG_SETMASK 2//for setting the signal mask |
83 |
84 |
|
|
84 |
85 |
#define K_SFD_NONBLOCK K_O_NONBLOCK |
#define K_SFD_NONBLOCK K_O_NONBLOCK |
85 |
|
//---------------------------------------------------------------------------------------------- |
|
|
86 |
|
//------------------------------------------------------------------------------ |
86 |
87 |
//|user siginfo stuff |
//|user siginfo stuff |
87 |
|
//---------------------------------------------------------------------------------------------- |
|
|
88 |
|
//------------------------------------------------------------------------------ |
88 |
89 |
struct k_signalfd_siginfo{ |
struct k_signalfd_siginfo{ |
89 |
90 |
k_u32 ssi_signo; |
k_u32 ssi_signo; |
90 |
91 |
k_s32 ssi_errno; |
k_s32 ssi_errno; |
|
... |
... |
struct k_signalfd_siginfo{ |
112 |
113 |
//a compat on read(2). |
//a compat on read(2). |
113 |
114 |
k_u8 __pad[48]; |
k_u8 __pad[48]; |
114 |
115 |
}; |
}; |
115 |
|
//---------------------------------------------------------------------------------------------- |
|
|
116 |
|
//---------------------------------------------------------------------------- |
116 |
117 |
#endif |
#endif |
File ulinux/wait.h changed (mode: 100644) (index ea0e20a..c952c28) |
1 |
|
//********************************************************************************************** |
|
2 |
|
//*this code is protected by the GNU affero GPLv3 |
|
3 |
|
//*author:Sylvain BERTRAND (sylvain.bertrand AT gmail dot com) |
|
4 |
|
//********************************************************************************************** |
|
5 |
1 |
#ifndef ULINUX_WAIT_H |
#ifndef ULINUX_WAIT_H |
6 |
2 |
#define ULINUX_WAIT_H |
#define ULINUX_WAIT_H |
|
3 |
|
//****************************************************************************** |
|
4 |
|
//*this code is protected by the GNU affero GPLv3 |
|
5 |
|
//*author:Sylvain BERTRAND <sylvain.bertrand AT gmail dot com> |
|
6 |
|
//* <digital.ragnarok AT gmail dot com> |
|
7 |
|
//****************************************************************************** |
7 |
8 |
#define K_WNOHANG 0x00000001 |
#define K_WNOHANG 0x00000001 |
8 |
9 |
#define K_WUNTRACED 0x00000002 |
#define K_WUNTRACED 0x00000002 |
9 |
10 |
#define K_WSTOPPED K_WUNTRACED |
#define K_WSTOPPED K_WUNTRACED |
10 |
11 |
#define K_WEXITED 0x00000004 |
#define K_WEXITED 0x00000004 |
11 |
12 |
#define K_WCONTINUED 0x00000008 |
#define K_WCONTINUED 0x00000008 |
12 |
|
#define K_WNOWAIT 0x01000000//Don't reap, just poll status. |
|
|
13 |
|
#define K_WNOWAIT 0x01000000//don't reap, just poll status. |
|
14 |
|
|
|
15 |
|
#define K_WNOTHREAD 0x20000000//don't wait on children of other threads in this |
|
16 |
|
//group |
|
17 |
|
#define K_WALL 0x40000000//wait on all children, regardless of type |
|
18 |
|
#define K_WCLONE 0x80000000//wait only on non-SIGCHLD children |
13 |
19 |
|
|
14 |
|
#define K_WNOTHREAD 0x20000000//Don't wait on children of other threads in this group |
|
15 |
|
#define K_WALL 0x40000000//Wait on all children, regardless of type |
|
16 |
|
#define K_WCLONE 0x80000000//Wait only on non-SIGCHLD children |
|
|
20 |
|
//first argument to waitid |
|
21 |
|
#define K_P_ALL 0 |
|
22 |
|
#define K_P_PID 1 |
|
23 |
|
#define K_P_PGID 2 |
17 |
24 |
#endif |
#endif |