Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F2919898
process.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
43 KB
Referenced Files
None
Subscribers
None
process.c
View Options
#include
<compat.h>
// IWYU pragma: keep
#include
<stdlib.h>
#include
<stdio.h>
#include
<string.h>
#include
<signal.h>
#include
<time.h>
#include
<uthash.h>
#include
<uv.h>
#ifdef _WIN32
#include
<windows.h>
#include
<io.h>
#include
<psapi.h>
#define STDIN_FILENO 0
#define STDOUT_FILENO 1
#define STDERR_FILENO 2
#else
#include
<termios.h>
#include
<unistd.h>
#include
<sys/ioctl.h>
#include
<sys/time.h>
#include
<sys/resource.h>
#include
<sys/stat.h>
#include
<grp.h>
#include
<pwd.h>
#endif
#include
"ant.h"
#include
"config.h"
#include
"internal.h"
#include
"runtime.h"
#include
"modules/process.h"
#include
"modules/symbol.h"
#ifndef _WIN32
extern
char
**
environ
;
#else
#define environ _environ
#endif
#define DEFAULT_MAX_LISTENERS 10
#define INITIAL_LISTENER_CAPACITY 4
typedef
struct
{
jsval_t
listener
;
bool
once
;
}
ProcessEventListener
;
typedef
struct
{
char
*
event_type
;
ProcessEventListener
*
listeners
;
int
listener_count
;
int
listener_capacity
;
UT_hash_handle
hh
;
}
ProcessEventType
;
static
int
max_listeners
=
DEFAULT_MAX_LISTENERS
;
static
ProcessEventType
*
process_events
=
NULL
;
static
ProcessEventType
*
stdin_events
=
NULL
;
static
ProcessEventType
*
stdout_events
=
NULL
;
static
ProcessEventType
*
stderr_events
=
NULL
;
static
uv_tty_t
stdin_tty
;
static
bool
stdin_tty_initialized
=
false
;
static
bool
stdin_reading
=
false
;
static
uint64_t
process_start_time
=
0
;
#ifndef _WIN32
static
struct
termios
stdin_saved_termios
;
static
bool
stdin_raw_mode
=
false
;
static
uv_signal_t
sigwinch_handle
;
static
bool
sigwinch_initialized
=
false
;
#endif
typedef
struct
{
const
char
*
name
;
int
signum
;
UT_hash_handle
hh_name
;
UT_hash_handle
hh_num
;
}
SignalEntry
;
static
SignalEntry
*
signals_by_name
=
NULL
;
static
SignalEntry
*
signals_by_num
=
NULL
;
static
void
init_signal_map
(
void
)
{
static
bool
initialized
=
false
;
if
(
initialized
)
return
;
static
SignalEntry
entries
[]
=
{
#ifdef SIGHUP
{
"SIGHUP"
,
SIGHUP
,
{
0
},
{
0
}
},
#endif
#ifdef SIGINT
{
"SIGINT"
,
SIGINT
,
{
0
},
{
0
}
},
#endif
#ifdef SIGQUIT
{
"SIGQUIT"
,
SIGQUIT
,
{
0
},
{
0
}
},
#endif
#ifdef SIGILL
{
"SIGILL"
,
SIGILL
,
{
0
},
{
0
}
},
#endif
#ifdef SIGTRAP
{
"SIGTRAP"
,
SIGTRAP
,
{
0
},
{
0
}
},
#endif
#ifdef SIGABRT
{
"SIGABRT"
,
SIGABRT
,
{
0
},
{
0
}
},
#endif
#ifdef SIGBUS
{
"SIGBUS"
,
SIGBUS
,
{
0
},
{
0
}
},
#endif
#ifdef SIGFPE
{
"SIGFPE"
,
SIGFPE
,
{
0
},
{
0
}
},
#endif
#ifdef SIGUSR1
{
"SIGUSR1"
,
SIGUSR1
,
{
0
},
{
0
}
},
#endif
#ifdef SIGUSR2
{
"SIGUSR2"
,
SIGUSR2
,
{
0
},
{
0
}
},
#endif
#ifdef SIGSEGV
{
"SIGSEGV"
,
SIGSEGV
,
{
0
},
{
0
}
},
#endif
#ifdef SIGPIPE
{
"SIGPIPE"
,
SIGPIPE
,
{
0
},
{
0
}
},
#endif
#ifdef SIGALRM
{
"SIGALRM"
,
SIGALRM
,
{
0
},
{
0
}
},
#endif
#ifdef SIGTERM
{
"SIGTERM"
,
SIGTERM
,
{
0
},
{
0
}
},
#endif
#ifdef SIGCHLD
{
"SIGCHLD"
,
SIGCHLD
,
{
0
},
{
0
}
},
#endif
#ifdef SIGCONT
{
"SIGCONT"
,
SIGCONT
,
{
0
},
{
0
}
},
#endif
#ifdef SIGTSTP
{
"SIGTSTP"
,
SIGTSTP
,
{
0
},
{
0
}
},
#endif
#ifdef SIGTTIN
{
"SIGTTIN"
,
SIGTTIN
,
{
0
},
{
0
}
},
#endif
#ifdef SIGTTOU
{
"SIGTTOU"
,
SIGTTOU
,
{
0
},
{
0
}
},
#endif
#ifdef SIGURG
{
"SIGURG"
,
SIGURG
,
{
0
},
{
0
}
},
#endif
#ifdef SIGXCPU
{
"SIGXCPU"
,
SIGXCPU
,
{
0
},
{
0
}
},
#endif
#ifdef SIGXFSZ
{
"SIGXFSZ"
,
SIGXFSZ
,
{
0
},
{
0
}
},
#endif
#ifdef SIGVTALRM
{
"SIGVTALRM"
,
SIGVTALRM
,
{
0
},
{
0
}
},
#endif
#ifdef SIGPROF
{
"SIGPROF"
,
SIGPROF
,
{
0
},
{
0
}
},
#endif
#ifdef SIGWINCH
{
"SIGWINCH"
,
SIGWINCH
,
{
0
},
{
0
}
},
#endif
#ifdef SIGIO
{
"SIGIO"
,
SIGIO
,
{
0
},
{
0
}
},
#endif
#ifdef SIGSYS
{
"SIGSYS"
,
SIGSYS
,
{
0
},
{
0
}
},
#endif
};
for
(
size_t
i
=
0
;
i
<
sizeof
(
entries
)
/
sizeof
(
entries
[
0
]);
i
++
)
{
HASH_ADD_KEYPTR
(
hh_name
,
signals_by_name
,
entries
[
i
].
name
,
strlen
(
entries
[
i
].
name
),
&
entries
[
i
]);
HASH_ADD
(
hh_num
,
signals_by_num
,
signum
,
sizeof
(
int
),
&
entries
[
i
]);
}
initialized
=
true
;
}
static
int
get_signal_number
(
const
char
*
name
)
{
init_signal_map
();
SignalEntry
*
entry
=
NULL
;
HASH_FIND
(
hh_name
,
signals_by_name
,
name
,
strlen
(
name
),
entry
);
return
entry
?
entry
->
signum
:
-1
;
}
static
const
char
*
get_signal_name
(
int
signum
)
{
init_signal_map
();
SignalEntry
*
entry
=
NULL
;
HASH_FIND
(
hh_num
,
signals_by_num
,
&
signum
,
sizeof
(
int
),
entry
);
return
entry
?
entry
->
name
:
NULL
;
}
static
ProcessEventType
*
find_or_create_event_type
(
const
char
*
event_type
)
{
ProcessEventType
*
evt
=
NULL
;
HASH_FIND_STR
(
process_events
,
event_type
,
evt
);
if
(
evt
==
NULL
)
{
evt
=
malloc
(
sizeof
(
ProcessEventType
));
evt
->
event_type
=
strdup
(
event_type
);
evt
->
listener_count
=
0
;
evt
->
listener_capacity
=
INITIAL_LISTENER_CAPACITY
;
evt
->
listeners
=
malloc
(
sizeof
(
ProcessEventListener
)
*
evt
->
listener_capacity
);
HASH_ADD_KEYPTR
(
hh
,
process_events
,
evt
->
event_type
,
strlen
(
evt
->
event_type
),
evt
);
}
return
evt
;
}
static
bool
ensure_listener_capacity
(
ProcessEventType
*
evt
)
{
if
(
evt
->
listener_count
>=
evt
->
listener_capacity
)
{
int
new_capacity
=
evt
->
listener_capacity
*
2
;
ProcessEventListener
*
new_listeners
=
realloc
(
evt
->
listeners
,
sizeof
(
ProcessEventListener
)
*
new_capacity
);
if
(
!
new_listeners
)
return
false
;
evt
->
listeners
=
new_listeners
;
evt
->
listener_capacity
=
new_capacity
;
}
return
true
;
}
static
void
check_listener_warning
(
const
char
*
event
)
{
ProcessEventType
*
evt
=
NULL
;
HASH_FIND_STR
(
process_events
,
event
,
evt
);
if
(
evt
&&
evt
->
listener_count
==
max_listeners
)
fprintf
(
stderr
,
"Warning: Possible EventEmitter memory leak detected. "
"%d '%s' listeners added. Use process.setMaxListeners() to increase limit.
\n
"
,
evt
->
listener_count
,
event
);
}
static
void
emit_process_event
(
const
char
*
event_type
,
jsval_t
*
args
,
int
nargs
)
{
if
(
!
rt
->
js
)
return
;
ProcessEventType
*
evt
=
NULL
;
HASH_FIND_STR
(
process_events
,
event_type
,
evt
);
if
(
evt
==
NULL
||
evt
->
listener_count
==
0
)
return
;
int
i
=
0
;
while
(
i
<
evt
->
listener_count
)
{
ProcessEventListener
*
listener
=
&
evt
->
listeners
[
i
];
js_call
(
rt
->
js
,
listener
->
listener
,
args
,
nargs
);
if
(
listener
->
once
)
{
for
(
int
j
=
i
;
j
<
evt
->
listener_count
-
1
;
j
++
)
{
evt
->
listeners
[
j
]
=
evt
->
listeners
[
j
+
1
];
}
evt
->
listener_count
--
;
}
else
i
++
;
}
}
static
void
process_signal_handler
(
int
signum
)
{
const
char
*
name
=
get_signal_name
(
signum
);
if
(
name
)
{
jsval_t
sig_arg
=
js_mkstr
(
rt
->
js
,
name
,
strlen
(
name
));
emit_process_event
(
name
,
&
sig_arg
,
1
);
}
}
static
ProcessEventType
*
find_or_create_stdin_event
(
const
char
*
event_type
)
{
ProcessEventType
*
evt
=
NULL
;
HASH_FIND_STR
(
stdin_events
,
event_type
,
evt
);
if
(
evt
==
NULL
)
{
evt
=
malloc
(
sizeof
(
ProcessEventType
));
evt
->
event_type
=
strdup
(
event_type
);
evt
->
listener_count
=
0
;
evt
->
listener_capacity
=
INITIAL_LISTENER_CAPACITY
;
evt
->
listeners
=
malloc
(
sizeof
(
ProcessEventListener
)
*
evt
->
listener_capacity
);
HASH_ADD_KEYPTR
(
hh
,
stdin_events
,
evt
->
event_type
,
strlen
(
evt
->
event_type
),
evt
);
}
return
evt
;
}
static
ProcessEventType
*
find_or_create_stdout_event
(
const
char
*
event_type
)
{
ProcessEventType
*
evt
=
NULL
;
HASH_FIND_STR
(
stdout_events
,
event_type
,
evt
);
if
(
evt
==
NULL
)
{
evt
=
malloc
(
sizeof
(
ProcessEventType
));
evt
->
event_type
=
strdup
(
event_type
);
evt
->
listener_count
=
0
;
evt
->
listener_capacity
=
INITIAL_LISTENER_CAPACITY
;
evt
->
listeners
=
malloc
(
sizeof
(
ProcessEventListener
)
*
evt
->
listener_capacity
);
HASH_ADD_KEYPTR
(
hh
,
stdout_events
,
evt
->
event_type
,
strlen
(
evt
->
event_type
),
evt
);
}
return
evt
;
}
static
void
emit_stdio_event
(
ProcessEventType
*
events
,
const
char
*
event_type
,
jsval_t
*
args
,
int
nargs
)
{
if
(
!
rt
->
js
)
return
;
ProcessEventType
*
evt
=
NULL
;
HASH_FIND_STR
(
events
,
event_type
,
evt
);
if
(
evt
==
NULL
||
evt
->
listener_count
==
0
)
return
;
int
i
=
0
;
while
(
i
<
evt
->
listener_count
)
{
ProcessEventListener
*
listener
=
&
evt
->
listeners
[
i
];
js_call
(
rt
->
js
,
listener
->
listener
,
args
,
nargs
);
if
(
listener
->
once
)
{
for
(
int
j
=
i
;
j
<
evt
->
listener_count
-
1
;
j
++
)
{
evt
->
listeners
[
j
]
=
evt
->
listeners
[
j
+
1
];
}
evt
->
listener_count
--
;
}
else
i
++
;
}
}
static
bool
stdin_is_tty
(
void
)
{
return
uv_guess_handle
(
STDIN_FILENO
)
==
UV_TTY
;
}
static
bool
stdout_is_tty
(
void
)
{
return
uv_guess_handle
(
STDOUT_FILENO
)
==
UV_TTY
;
}
static
bool
stderr_is_tty
(
void
)
{
return
uv_guess_handle
(
STDERR_FILENO
)
==
UV_TTY
;
}
static
void
get_tty_size
(
int
fd
,
int
*
rows
,
int
*
cols
)
{
int
out_rows
=
24
,
out_cols
=
80
;
#ifndef _WIN32
struct
winsize
ws
;
if
(
ioctl
(
fd
,
TIOCGWINSZ
,
&
ws
)
==
0
)
{
if
(
ws
.
ws_row
>
0
)
out_rows
=
ws
.
ws_row
;
if
(
ws
.
ws_col
>
0
)
out_cols
=
ws
.
ws_col
;
}
#else
CONSOLE_SCREEN_BUFFER_INFO
csbi
;
if
(
GetConsoleScreenBufferInfo
(
GetStdHandle
(
STD_OUTPUT_HANDLE
),
&
csbi
))
{
int
width
=
csbi
.
srWindow
.
Right
-
csbi
.
srWindow
.
Left
+
1
;
int
height
=
csbi
.
srWindow
.
Bottom
-
csbi
.
srWindow
.
Top
+
1
;
if
(
height
>
0
)
out_rows
=
height
;
if
(
width
>
0
)
out_cols
=
width
;
}
#endif
if
(
rows
)
*
rows
=
out_rows
;
if
(
cols
)
*
cols
=
out_cols
;
}
#ifndef _WIN32
static
bool
stdin_set_raw_mode
(
bool
enable
)
{
if
(
!
stdin_is_tty
())
return
false
;
if
(
enable
)
{
if
(
stdin_raw_mode
)
return
true
;
if
(
tcgetattr
(
STDIN_FILENO
,
&
stdin_saved_termios
)
==
-1
)
return
false
;
struct
termios
raw
=
stdin_saved_termios
;
raw
.
c_lflag
&=
~
(
ICANON
|
ECHO
|
ISIG
);
raw
.
c_cc
[
VMIN
]
=
1
;
raw
.
c_cc
[
VTIME
]
=
0
;
if
(
tcsetattr
(
STDIN_FILENO
,
TCSANOW
,
&
raw
)
==
-1
)
return
false
;
stdin_raw_mode
=
true
;
return
true
;
}
if
(
!
stdin_raw_mode
)
return
true
;
if
(
tcsetattr
(
STDIN_FILENO
,
TCSANOW
,
&
stdin_saved_termios
)
==
-1
)
return
false
;
stdin_raw_mode
=
false
;
return
true
;
}
#else
static
bool
stdin_set_raw_mode
(
bool
enable
)
{
(
void
)
enable
;
return
false
;
}
#endif
static
void
stdin_alloc_buffer
(
uv_handle_t
*
handle
,
size_t
suggested_size
,
uv_buf_t
*
buf
)
{
(
void
)
handle
;
buf
->
base
=
malloc
(
suggested_size
);
buf
->
len
=
suggested_size
;
}
static
void
on_stdin_read
(
uv_stream_t
*
stream
,
ssize_t
nread
,
const
uv_buf_t
*
buf
)
{
(
void
)
stream
;
if
(
nread
>
0
&&
rt
->
js
)
{
jsval_t
data_val
=
js_mkstr
(
rt
->
js
,
buf
->
base
,
(
size_t
)
nread
);
emit_stdio_event
(
stdin_events
,
"data"
,
&
data_val
,
1
);
}
if
(
buf
->
base
)
free
(
buf
->
base
);
}
static
void
stdin_start_reading
(
void
)
{
if
(
stdin_reading
)
return
;
if
(
!
stdin_tty_initialized
)
{
uv_loop_t
*
loop
=
uv_default_loop
();
if
(
uv_tty_init
(
loop
,
&
stdin_tty
,
STDIN_FILENO
,
1
)
!=
0
)
return
;
#ifndef _WIN32
uv_tty_set_mode
(
&
stdin_tty
,
stdin_raw_mode
?
UV_TTY_MODE_RAW
:
UV_TTY_MODE_NORMAL
);
#endif
stdin_tty
.
data
=
NULL
;
stdin_tty_initialized
=
true
;
}
else
{
#ifndef _WIN32
uv_tty_set_mode
(
&
stdin_tty
,
stdin_raw_mode
?
UV_TTY_MODE_RAW
:
UV_TTY_MODE_NORMAL
);
#endif
}
stdin_reading
=
true
;
uv_read_start
((
uv_stream_t
*
)
&
stdin_tty
,
stdin_alloc_buffer
,
on_stdin_read
);
}
static
void
stdin_stop_reading
(
void
)
{
if
(
!
stdin_reading
)
return
;
uv_read_stop
((
uv_stream_t
*
)
&
stdin_tty
);
stdin_reading
=
false
;
}
#ifndef _WIN32
static
void
on_sigwinch
(
uv_signal_t
*
handle
,
int
signum
)
{
(
void
)
handle
;
(
void
)
signum
;
if
(
!
rt
->
js
)
return
;
jsval_t
process_obj
=
js_get
(
rt
->
js
,
js_glob
(
rt
->
js
),
"process"
);
if
(
js_type
(
process_obj
)
!=
JS_OBJ
)
return
;
jsval_t
stdout_obj
=
js_get
(
rt
->
js
,
process_obj
,
"stdout"
);
if
(
js_type
(
stdout_obj
)
!=
JS_OBJ
)
return
;
int
rows
=
0
,
cols
=
0
;
get_tty_size
(
STDOUT_FILENO
,
&
rows
,
&
cols
);
js_set
(
rt
->
js
,
stdout_obj
,
"rows"
,
js_mknum
(
rows
));
js_set
(
rt
->
js
,
stdout_obj
,
"columns"
,
js_mknum
(
cols
));
emit_stdio_event
(
stdout_events
,
"resize"
,
NULL
,
0
);
}
#endif
static
void
start_sigwinch_handler
(
void
)
{
#ifndef _WIN32
if
(
sigwinch_initialized
)
return
;
uv_loop_t
*
loop
=
uv_default_loop
();
if
(
uv_signal_init
(
loop
,
&
sigwinch_handle
)
!=
0
)
return
;
if
(
uv_signal_start
(
&
sigwinch_handle
,
on_sigwinch
,
SIGWINCH
)
!=
0
)
{
uv_close
((
uv_handle_t
*
)
&
sigwinch_handle
,
NULL
);
return
;
}
uv_unref
((
uv_handle_t
*
)
&
sigwinch_handle
);
sigwinch_initialized
=
true
;
#endif
}
static
jsval_t
js_stdin_set_raw_mode
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
bool
enable
=
nargs
>
0
?
js_truthy
(
js
,
args
[
0
])
:
true
;
return
stdin_set_raw_mode
(
enable
)
?
js_mktrue
()
:
js_mkfalse
();
}
static
jsval_t
js_stdin_resume
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
(
void
)
args
;
(
void
)
nargs
;
stdin_start_reading
();
return
js_getthis
(
js
);
}
static
jsval_t
js_stdin_pause
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
(
void
)
args
;
(
void
)
nargs
;
stdin_stop_reading
();
return
js_getthis
(
js
);
}
static
jsval_t
js_stdin_on
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
jsval_t
this_obj
=
js_getthis
(
js
);
if
(
nargs
<
2
)
return
this_obj
;
char
*
event
=
js_getstr
(
js
,
args
[
0
],
NULL
);
if
(
!
event
||
js_type
(
args
[
1
])
!=
JS_FUNC
)
return
this_obj
;
ProcessEventType
*
evt
=
find_or_create_stdin_event
(
event
);
if
(
!
ensure_listener_capacity
(
evt
))
return
this_obj
;
evt
->
listeners
[
evt
->
listener_count
].
listener
=
args
[
1
];
evt
->
listeners
[
evt
->
listener_count
].
once
=
false
;
evt
->
listener_count
++
;
if
(
strcmp
(
event
,
"data"
)
==
0
)
stdin_start_reading
();
return
this_obj
;
}
static
jsval_t
js_stdin_remove_all_listeners
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
jsval_t
this_obj
=
js_getthis
(
js
);
if
(
nargs
<
1
)
{
ProcessEventType
*
evt
,
*
tmp
;
HASH_ITER
(
hh
,
stdin_events
,
evt
,
tmp
)
{
evt
->
listener_count
=
0
;
}
stdin_stop_reading
();
return
this_obj
;
}
char
*
event
=
js_getstr
(
js
,
args
[
0
],
NULL
);
if
(
!
event
)
return
this_obj
;
ProcessEventType
*
evt
=
NULL
;
HASH_FIND_STR
(
stdin_events
,
event
,
evt
);
if
(
evt
)
evt
->
listener_count
=
0
;
if
(
strcmp
(
event
,
"data"
)
==
0
)
stdin_stop_reading
();
return
this_obj
;
}
static
jsval_t
js_stdout_write
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_mkfalse
();
size_t
len
=
0
;
char
*
data
=
js_getstr
(
js
,
args
[
0
],
&
len
);
if
(
!
data
)
return
js_mkfalse
();
fwrite
(
data
,
1
,
len
,
stdout
);
fflush
(
stdout
);
return
js_mktrue
();
}
static
jsval_t
js_stdout_on
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
jsval_t
this_obj
=
js_getthis
(
js
);
if
(
nargs
<
2
)
return
this_obj
;
char
*
event
=
js_getstr
(
js
,
args
[
0
],
NULL
);
if
(
!
event
||
js_type
(
args
[
1
])
!=
JS_FUNC
)
return
this_obj
;
ProcessEventType
*
evt
=
find_or_create_stdout_event
(
event
);
if
(
!
ensure_listener_capacity
(
evt
))
return
this_obj
;
evt
->
listeners
[
evt
->
listener_count
].
listener
=
args
[
1
];
evt
->
listeners
[
evt
->
listener_count
].
once
=
false
;
evt
->
listener_count
++
;
if
(
strcmp
(
event
,
"resize"
)
==
0
)
start_sigwinch_handler
();
return
this_obj
;
}
static
jsval_t
js_stdout_once
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
jsval_t
this_obj
=
js_getthis
(
js
);
if
(
nargs
<
2
)
return
this_obj
;
char
*
event
=
js_getstr
(
js
,
args
[
0
],
NULL
);
if
(
!
event
||
js_type
(
args
[
1
])
!=
JS_FUNC
)
return
this_obj
;
ProcessEventType
*
evt
=
find_or_create_stdout_event
(
event
);
if
(
!
ensure_listener_capacity
(
evt
))
return
this_obj
;
evt
->
listeners
[
evt
->
listener_count
].
listener
=
args
[
1
];
evt
->
listeners
[
evt
->
listener_count
].
once
=
true
;
evt
->
listener_count
++
;
if
(
strcmp
(
event
,
"resize"
)
==
0
)
start_sigwinch_handler
();
return
this_obj
;
}
static
jsval_t
js_stdout_remove_all_listeners
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
jsval_t
this_obj
=
js_getthis
(
js
);
if
(
nargs
<
1
)
{
ProcessEventType
*
evt
,
*
tmp
;
HASH_ITER
(
hh
,
stdout_events
,
evt
,
tmp
)
{
evt
->
listener_count
=
0
;
}
return
this_obj
;
}
char
*
event
=
js_getstr
(
js
,
args
[
0
],
NULL
);
if
(
!
event
)
return
this_obj
;
ProcessEventType
*
evt
=
NULL
;
HASH_FIND_STR
(
stdout_events
,
event
,
evt
);
if
(
evt
)
evt
->
listener_count
=
0
;
return
this_obj
;
}
static
jsval_t
js_stdout_get_window_size
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
(
void
)
args
;
(
void
)
nargs
;
int
rows
=
0
,
cols
=
0
;
get_tty_size
(
STDOUT_FILENO
,
&
rows
,
&
cols
);
jsval_t
arr
=
js_mkarr
(
js
);
js_arr_push
(
js
,
arr
,
js_mknum
(
cols
));
js_arr_push
(
js
,
arr
,
js_mknum
(
rows
));
return
arr
;
}
static
jsval_t
js_stdout_rows_getter
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
(
void
)
args
;
(
void
)
nargs
;
int
rows
=
0
,
cols
=
0
;
get_tty_size
(
STDOUT_FILENO
,
&
rows
,
&
cols
);
return
js_mknum
(
rows
);
}
static
jsval_t
js_stdout_columns_getter
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
(
void
)
args
;
(
void
)
nargs
;
int
rows
=
0
,
cols
=
0
;
get_tty_size
(
STDOUT_FILENO
,
&
rows
,
&
cols
);
return
js_mknum
(
cols
);
}
static
ProcessEventType
*
find_or_create_stderr_event
(
const
char
*
event_type
)
{
ProcessEventType
*
evt
=
NULL
;
HASH_FIND_STR
(
stderr_events
,
event_type
,
evt
);
if
(
evt
==
NULL
)
{
evt
=
malloc
(
sizeof
(
ProcessEventType
));
evt
->
event_type
=
strdup
(
event_type
);
evt
->
listener_count
=
0
;
evt
->
listener_capacity
=
INITIAL_LISTENER_CAPACITY
;
evt
->
listeners
=
malloc
(
sizeof
(
ProcessEventListener
)
*
evt
->
listener_capacity
);
HASH_ADD_KEYPTR
(
hh
,
stderr_events
,
evt
->
event_type
,
strlen
(
evt
->
event_type
),
evt
);
}
return
evt
;
}
static
jsval_t
js_stderr_write
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_mkfalse
();
size_t
len
=
0
;
char
*
data
=
js_getstr
(
js
,
args
[
0
],
&
len
);
if
(
!
data
)
return
js_mkfalse
();
fwrite
(
data
,
1
,
len
,
stderr
);
fflush
(
stderr
);
return
js_mktrue
();
}
static
jsval_t
js_stderr_on
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
jsval_t
this_obj
=
js_getthis
(
js
);
if
(
nargs
<
2
)
return
this_obj
;
char
*
event
=
js_getstr
(
js
,
args
[
0
],
NULL
);
if
(
!
event
||
js_type
(
args
[
1
])
!=
JS_FUNC
)
return
this_obj
;
ProcessEventType
*
evt
=
find_or_create_stderr_event
(
event
);
if
(
!
ensure_listener_capacity
(
evt
))
return
this_obj
;
evt
->
listeners
[
evt
->
listener_count
].
listener
=
args
[
1
];
evt
->
listeners
[
evt
->
listener_count
].
once
=
false
;
evt
->
listener_count
++
;
return
this_obj
;
}
static
jsval_t
js_stderr_once
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
jsval_t
this_obj
=
js_getthis
(
js
);
if
(
nargs
<
2
)
return
this_obj
;
char
*
event
=
js_getstr
(
js
,
args
[
0
],
NULL
);
if
(
!
event
||
js_type
(
args
[
1
])
!=
JS_FUNC
)
return
this_obj
;
ProcessEventType
*
evt
=
find_or_create_stderr_event
(
event
);
if
(
!
ensure_listener_capacity
(
evt
))
return
this_obj
;
evt
->
listeners
[
evt
->
listener_count
].
listener
=
args
[
1
];
evt
->
listeners
[
evt
->
listener_count
].
once
=
true
;
evt
->
listener_count
++
;
return
this_obj
;
}
static
jsval_t
js_stderr_remove_all_listeners
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
jsval_t
this_obj
=
js_getthis
(
js
);
if
(
nargs
<
1
)
{
ProcessEventType
*
evt
,
*
tmp
;
HASH_ITER
(
hh
,
stderr_events
,
evt
,
tmp
)
{
evt
->
listener_count
=
0
;
}
return
this_obj
;
}
char
*
event
=
js_getstr
(
js
,
args
[
0
],
NULL
);
if
(
!
event
)
return
this_obj
;
ProcessEventType
*
evt
=
NULL
;
HASH_FIND_STR
(
stderr_events
,
event
,
evt
);
if
(
evt
)
evt
->
listener_count
=
0
;
return
this_obj
;
}
static
jsval_t
process_uptime
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
(
void
)
args
;
(
void
)
nargs
;
uint64_t
now
=
uv_hrtime
();
double
seconds
=
(
double
)(
now
-
process_start_time
)
/
1e9
;
return
js_mknum
(
seconds
);
}
static
jsval_t
process_hrtime
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
uint64_t
now
=
uv_hrtime
();
if
(
nargs
>
0
&&
js_type
(
args
[
0
])
==
T_ARR
)
{
jsval_t
prev_sec
=
js_get
(
js
,
args
[
0
],
"0"
);
jsval_t
prev_nsec
=
js_get
(
js
,
args
[
0
],
"1"
);
if
(
js_type
(
prev_sec
)
==
JS_NUM
&&
js_type
(
prev_nsec
)
==
JS_NUM
)
{
uint64_t
prev
=
(
uint64_t
)
js_getnum
(
prev_sec
)
*
1000000000ULL
+
(
uint64_t
)
js_getnum
(
prev_nsec
);
now
=
now
-
prev
;
}
}
jsval_t
arr
=
js_mkarr
(
js
);
uint64_t
secs
=
now
/
1000000000ULL
;
uint64_t
nsecs
=
now
%
1000000000ULL
;
js_arr_push
(
js
,
arr
,
js_mknum
((
double
)
secs
));
js_arr_push
(
js
,
arr
,
js_mknum
((
double
)
nsecs
));
return
arr
;
}
static
jsval_t
process_hrtime_bigint
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
(
void
)
args
;
(
void
)
nargs
;
uint64_t
now
=
uv_hrtime
();
char
buf
[
32
];
snprintf
(
buf
,
sizeof
(
buf
),
"%llu"
,
(
unsigned
long
long
)
now
);
return
js_mkbigint
(
js
,
buf
,
strlen
(
buf
),
false
);
}
static
jsval_t
process_memory_usage
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
(
void
)
args
;
(
void
)
nargs
;
jsval_t
obj
=
js_mkobj
(
js
);
size_t
rss
=
0
;
uv_resident_set_memory
(
&
rss
);
js_set
(
js
,
obj
,
"rss"
,
js_mknum
((
double
)
rss
));
#ifdef _WIN32
PROCESS_MEMORY_COUNTERS_EX
pmc
;
if
(
GetProcessMemoryInfo
(
GetCurrentProcess
(),
(
PROCESS_MEMORY_COUNTERS
*
)
&
pmc
,
sizeof
(
pmc
)))
{
js_set
(
js
,
obj
,
"heapTotal"
,
js_mknum
((
double
)
pmc
.
WorkingSetSize
));
js_set
(
js
,
obj
,
"heapUsed"
,
js_mknum
((
double
)
pmc
.
PrivateUsage
));
}
else
{
js_set
(
js
,
obj
,
"heapTotal"
,
js_mknum
(
0
));
js_set
(
js
,
obj
,
"heapUsed"
,
js_mknum
(
0
));
}
#else
struct
rusage
usage
;
if
(
getrusage
(
RUSAGE_SELF
,
&
usage
)
==
0
)
{
js_set
(
js
,
obj
,
"heapTotal"
,
js_mknum
((
double
)
rss
));
js_set
(
js
,
obj
,
"heapUsed"
,
js_mknum
((
double
)
rss
));
}
else
{
js_set
(
js
,
obj
,
"heapTotal"
,
js_mknum
(
0
));
js_set
(
js
,
obj
,
"heapUsed"
,
js_mknum
(
0
));
}
#endif
js_set
(
js
,
obj
,
"external"
,
js_mknum
(
0
));
js_set
(
js
,
obj
,
"arrayBuffers"
,
js_mknum
(
0
));
return
obj
;
}
static
jsval_t
process_memory_usage_rss
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
(
void
)
args
;
(
void
)
nargs
;
size_t
rss
=
0
;
uv_resident_set_memory
(
&
rss
);
return
js_mknum
((
double
)
rss
);
}
static
jsval_t
process_cpu_usage
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
jsval_t
obj
=
js_mkobj
(
js
);
uv_rusage_t
rusage
;
if
(
uv_getrusage
(
&
rusage
)
==
0
)
{
int64_t
user_usec
=
rusage
.
ru_utime
.
tv_sec
*
1000000L
L
+
rusage
.
ru_utime
.
tv_usec
;
int64_t
sys_usec
=
rusage
.
ru_stime
.
tv_sec
*
1000000L
L
+
rusage
.
ru_stime
.
tv_usec
;
if
(
nargs
>
0
&&
js_type
(
args
[
0
])
==
JS_OBJ
)
{
jsval_t
prev_user
=
js_get
(
js
,
args
[
0
],
"user"
);
jsval_t
prev_system
=
js_get
(
js
,
args
[
0
],
"system"
);
if
(
js_type
(
prev_user
)
==
JS_NUM
)
user_usec
-=
(
int64_t
)
js_getnum
(
prev_user
);
if
(
js_type
(
prev_system
)
==
JS_NUM
)
sys_usec
-=
(
int64_t
)
js_getnum
(
prev_system
);
}
js_set
(
js
,
obj
,
"user"
,
js_mknum
((
double
)
user_usec
));
js_set
(
js
,
obj
,
"system"
,
js_mknum
((
double
)
sys_usec
));
}
else
{
js_set
(
js
,
obj
,
"user"
,
js_mknum
(
0
));
js_set
(
js
,
obj
,
"system"
,
js_mknum
(
0
));
}
return
obj
;
}
static
jsval_t
process_kill
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_mkerr
(
js
,
"process.kill requires at least 1 argument"
);
if
(
js_type
(
args
[
0
])
!=
JS_NUM
)
return
js_mkerr
(
js
,
"pid must be a number"
);
int
pid
=
(
int
)
js_getnum
(
args
[
0
]);
int
sig
=
SIGTERM
;
if
(
nargs
>
1
)
{
if
(
js_type
(
args
[
1
])
==
JS_NUM
)
{
sig
=
(
int
)
js_getnum
(
args
[
1
]);
}
else
if
(
js_type
(
args
[
1
])
==
JS_STR
)
{
char
*
sig_name
=
js_getstr
(
js
,
args
[
1
],
NULL
);
if
(
sig_name
)
{
int
signum
=
get_signal_number
(
sig_name
);
if
(
signum
>
0
)
sig
=
signum
;
else
return
js_mkerr
(
js
,
"Unknown signal"
);
}
}
}
int
result
=
uv_kill
(
pid
,
sig
);
if
(
result
!=
0
)
return
js_mkerr
(
js
,
"Failed to send signal"
);
return
js_mktrue
();
}
static
jsval_t
process_abort
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
(
void
)
js
;
(
void
)
args
;
(
void
)
nargs
;
abort
();
return
js_mkundef
();
}
static
jsval_t
process_chdir
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_mkerr
(
js
,
"process.chdir requires 1 argument"
);
char
*
dir
=
js_getstr
(
js
,
args
[
0
],
NULL
);
if
(
!
dir
)
return
js_mkerr
(
js
,
"directory must be a string"
);
int
result
=
uv_chdir
(
dir
);
if
(
result
!=
0
)
return
js_mkerr
(
js
,
"ENOENT: no such file or directory, chdir"
);
return
js_mkundef
();
}
static
jsval_t
process_umask
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
#ifdef _WIN32
(
void
)
args
;
(
void
)
nargs
;
return
js_mknum
(
0
);
#else
if
(
nargs
>
0
&&
js_type
(
args
[
0
])
==
JS_NUM
)
{
int
new_mask
=
(
int
)
js_getnum
(
args
[
0
]);
int
old_mask
=
umask
((
mode_t
)
new_mask
);
return
js_mknum
(
old_mask
);
}
int
cur
=
umask
(
0
);
umask
((
mode_t
)
cur
);
return
js_mknum
(
cur
);
#endif
}
#ifndef _WIN32
static
jsval_t
process_getuid
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
(
void
)
args
;
(
void
)
nargs
;
return
js_mknum
((
double
)
getuid
());
}
static
jsval_t
process_geteuid
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
(
void
)
args
;
(
void
)
nargs
;
return
js_mknum
((
double
)
geteuid
());
}
static
jsval_t
process_getgid
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
(
void
)
args
;
(
void
)
nargs
;
return
js_mknum
((
double
)
getgid
());
}
static
jsval_t
process_getegid
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
(
void
)
args
;
(
void
)
nargs
;
return
js_mknum
((
double
)
getegid
());
}
static
jsval_t
process_getgroups
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
(
void
)
args
;
(
void
)
nargs
;
int
ngroups
=
getgroups
(
0
,
NULL
);
if
(
ngroups
<
0
)
return
js_mkarr
(
js
);
gid_t
*
groups
=
malloc
(
sizeof
(
gid_t
)
*
(
size_t
)
ngroups
);
if
(
!
groups
)
return
js_mkarr
(
js
);
ngroups
=
getgroups
(
ngroups
,
groups
);
jsval_t
arr
=
js_mkarr
(
js
);
for
(
int
i
=
0
;
i
<
ngroups
;
i
++
)
{
js_arr_push
(
js
,
arr
,
js_mknum
((
double
)
groups
[
i
]));
}
free
(
groups
);
return
arr
;
}
static
jsval_t
process_setuid
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_mkerr
(
js
,
"process.setuid requires 1 argument"
);
uid_t
uid
;
if
(
js_type
(
args
[
0
])
==
JS_NUM
)
{
uid
=
(
uid_t
)
js_getnum
(
args
[
0
]);
}
else
if
(
js_type
(
args
[
0
])
==
JS_STR
)
{
char
*
name
=
js_getstr
(
js
,
args
[
0
],
NULL
);
struct
passwd
*
pwd
=
getpwnam
(
name
);
if
(
!
pwd
)
return
js_mkerr
(
js
,
"setuid user not found"
);
uid
=
pwd
->
pw_uid
;
}
else
{
return
js_mkerr
(
js
,
"uid must be a number or string"
);
}
if
(
setuid
(
uid
)
!=
0
)
return
js_mkerr
(
js
,
"setuid failed"
);
return
js_mkundef
();
}
static
jsval_t
process_setgid
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_mkerr
(
js
,
"process.setgid requires 1 argument"
);
gid_t
gid
;
if
(
js_type
(
args
[
0
])
==
JS_NUM
)
{
gid
=
(
gid_t
)
js_getnum
(
args
[
0
]);
}
else
if
(
js_type
(
args
[
0
])
==
JS_STR
)
{
char
*
name
=
js_getstr
(
js
,
args
[
0
],
NULL
);
struct
group
*
grp
=
getgrnam
(
name
);
if
(
!
grp
)
return
js_mkerr
(
js
,
"setgid group not found"
);
gid
=
grp
->
gr_gid
;
}
else
{
return
js_mkerr
(
js
,
"gid must be a number or string"
);
}
if
(
setgid
(
gid
)
!=
0
)
return
js_mkerr
(
js
,
"setgid failed"
);
return
js_mkundef
();
}
static
jsval_t
process_seteuid
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_mkerr
(
js
,
"process.seteuid requires 1 argument"
);
uid_t
uid
;
if
(
js_type
(
args
[
0
])
==
JS_NUM
)
{
uid
=
(
uid_t
)
js_getnum
(
args
[
0
]);
}
else
if
(
js_type
(
args
[
0
])
==
JS_STR
)
{
char
*
name
=
js_getstr
(
js
,
args
[
0
],
NULL
);
struct
passwd
*
pwd
=
getpwnam
(
name
);
if
(
!
pwd
)
return
js_mkerr
(
js
,
"seteuid user not found"
);
uid
=
pwd
->
pw_uid
;
}
else
{
return
js_mkerr
(
js
,
"uid must be a number or string"
);
}
if
(
seteuid
(
uid
)
!=
0
)
return
js_mkerr
(
js
,
"seteuid failed"
);
return
js_mkundef
();
}
static
jsval_t
process_setegid
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_mkerr
(
js
,
"process.setegid requires 1 argument"
);
gid_t
gid
;
if
(
js_type
(
args
[
0
])
==
JS_NUM
)
{
gid
=
(
gid_t
)
js_getnum
(
args
[
0
]);
}
else
if
(
js_type
(
args
[
0
])
==
JS_STR
)
{
char
*
name
=
js_getstr
(
js
,
args
[
0
],
NULL
);
struct
group
*
grp
=
getgrnam
(
name
);
if
(
!
grp
)
return
js_mkerr
(
js
,
"setegid group not found"
);
gid
=
grp
->
gr_gid
;
}
else
{
return
js_mkerr
(
js
,
"gid must be a number or string"
);
}
if
(
setegid
(
gid
)
!=
0
)
return
js_mkerr
(
js
,
"setegid failed"
);
return
js_mkundef
();
}
static
jsval_t
process_setgroups
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
||
js_type
(
args
[
0
])
!=
T_ARR
)
{
return
js_mkerr
(
js
,
"process.setgroups requires an array"
);
}
jsval_t
len_val
=
js_get
(
js
,
args
[
0
],
"length"
);
int
len
=
(
int
)
js_getnum
(
len_val
);
gid_t
*
groups
=
malloc
(
sizeof
(
gid_t
)
*
(
size_t
)
len
);
if
(
!
groups
)
return
js_mkerr
(
js
,
"allocation failed"
);
for
(
int
i
=
0
;
i
<
len
;
i
++
)
{
char
idx
[
16
];
snprintf
(
idx
,
sizeof
(
idx
),
"%d"
,
i
);
jsval_t
val
=
js_get
(
js
,
args
[
0
],
idx
);
if
(
js_type
(
val
)
==
JS_NUM
)
{
groups
[
i
]
=
(
gid_t
)
js_getnum
(
val
);
}
else
if
(
js_type
(
val
)
==
JS_STR
)
{
char
*
name
=
js_getstr
(
js
,
val
,
NULL
);
struct
group
*
grp
=
getgrnam
(
name
);
if
(
!
grp
)
{
free
(
groups
);
return
js_mkerr
(
js
,
"group not found"
);
}
groups
[
i
]
=
grp
->
gr_gid
;
}
else
{
free
(
groups
);
return
js_mkerr
(
js
,
"group id must be number or string"
);
}
}
if
(
setgroups
(
len
,
groups
)
!=
0
)
{
free
(
groups
);
return
js_mkerr
(
js
,
"setgroups failed"
);
}
free
(
groups
);
return
js_mkundef
();
}
static
jsval_t
process_initgroups
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
if
(
nargs
<
2
)
return
js_mkerr
(
js
,
"process.initgroups requires 2 arguments"
);
char
*
user
=
js_getstr
(
js
,
args
[
0
],
NULL
);
if
(
!
user
)
return
js_mkerr
(
js
,
"user must be a string"
);
gid_t
gid
;
if
(
js_type
(
args
[
1
])
==
JS_NUM
)
{
gid
=
(
gid_t
)
js_getnum
(
args
[
1
]);
}
else
if
(
js_type
(
args
[
1
])
==
JS_STR
)
{
char
*
name
=
js_getstr
(
js
,
args
[
1
],
NULL
);
struct
group
*
grp
=
getgrnam
(
name
);
if
(
!
grp
)
return
js_mkerr
(
js
,
"group not found"
);
gid
=
grp
->
gr_gid
;
}
else
{
return
js_mkerr
(
js
,
"gid must be a number or string"
);
}
if
(
initgroups
(
user
,
gid
)
!=
0
)
return
js_mkerr
(
js
,
"initgroups failed"
);
return
js_mkundef
();
}
#endif
static
jsval_t
env_getter
(
ant_t
*
js
,
jsval_t
obj
,
const
char
*
key
,
size_t
key_len
)
{
char
*
key_str
=
(
char
*
)
malloc
(
key_len
+
1
);
if
(
!
key_str
)
return
js_mkundef
();
memcpy
(
key_str
,
key
,
key_len
);
key_str
[
key_len
]
=
'\0'
;
char
*
value
=
getenv
(
key_str
);
free
(
key_str
);
if
(
value
==
NULL
)
return
js_mkundef
();
return
js_mkstr
(
js
,
value
,
strlen
(
value
));
}
static
void
load_dotenv_file
(
ant_t
*
js
,
jsval_t
env_obj
)
{
FILE
*
fp
=
fopen
(
".env"
,
"r"
);
if
(
fp
==
NULL
)
return
;
char
line
[
1024
];
while
(
fgets
(
line
,
sizeof
(
line
),
fp
)
!=
NULL
)
{
size_t
len
=
strlen
(
line
);
if
(
len
>
0
&&
line
[
len
-
1
]
==
'\n'
)
{
line
[
len
-
1
]
=
'\0'
;
len
--
;
}
if
(
len
>
0
&&
line
[
len
-
1
]
==
'\r'
)
{
line
[
len
-
1
]
=
'\0'
;
len
--
;
}
if
(
len
==
0
||
line
[
0
]
==
'#'
)
continue
;
char
*
equals
=
strchr
(
line
,
'='
);
if
(
equals
==
NULL
)
continue
;
*
equals
=
'\0'
;
char
*
key
=
line
;
char
*
value
=
equals
+
1
;
while
(
*
key
==
' '
||
*
key
==
'\t'
)
key
++
;
char
*
key_end
=
key
+
strlen
(
key
)
-
1
;
while
(
key_end
>
key
&&
(
*
key_end
==
' '
||
*
key_end
==
'\t'
))
{
*
key_end
=
'\0'
;
key_end
--
;
}
while
(
*
value
==
' '
||
*
value
==
'\t'
)
value
++
;
char
*
value_end
=
value
+
strlen
(
value
)
-
1
;
while
(
value_end
>
value
&&
(
*
value_end
==
' '
||
*
value_end
==
'\t'
))
{
*
value_end
=
'\0'
;
value_end
--
;
}
if
(
strlen
(
value
)
>=
2
&&
((
value
[
0
]
==
'"'
&&
value
[
strlen
(
value
)
-
1
]
==
'"'
)
||
(
value
[
0
]
==
'\''
&&
value
[
strlen
(
value
)
-
1
]
==
'\''
)))
{
value
[
strlen
(
value
)
-
1
]
=
'\0'
;
value
++
;
}
js_set
(
js
,
env_obj
,
key
,
js_mkstr
(
js
,
value
,
strlen
(
value
)));
}
fclose
(
fp
);
}
static
jsval_t
process_exit
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
int
code
=
0
;
if
(
nargs
>
0
&&
js_type
(
args
[
0
])
==
JS_NUM
)
{
code
=
(
int
)
js_getnum
(
args
[
0
]);
}
exit
(
code
);
return
js_mkundef
();
}
static
jsval_t
env_to_object
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
jsval_t
obj
=
js_mkobj
(
js
);
for
(
char
**
env
=
environ
;
*
env
!=
NULL
;
env
++
)
{
char
*
entry
=
*
env
;
char
*
equals
=
strchr
(
entry
,
'='
);
if
(
equals
==
NULL
)
continue
;
size_t
key_len
=
(
size_t
)(
equals
-
entry
);
char
*
value
=
equals
+
1
;
char
*
key
=
malloc
(
key_len
+
1
);
if
(
!
key
)
continue
;
memcpy
(
key
,
entry
,
key_len
);
key
[
key_len
]
=
'\0'
;
js_set
(
js
,
obj
,
key
,
js_mkstr
(
js
,
value
,
strlen
(
value
)));
free
(
key
);
}
return
obj
;
}
static
jsval_t
process_cwd
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
char
cwd
[
4096
];
if
(
getcwd
(
cwd
,
sizeof
(
cwd
))
!=
NULL
)
{
return
js_mkstr
(
js
,
cwd
,
strlen
(
cwd
));
}
return
js_mkundef
();
}
static
jsval_t
process_on
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
if
(
nargs
<
2
)
return
js_mkerr
(
js
,
"process.on requires 2 arguments"
);
char
*
event
=
js_getstr
(
js
,
args
[
0
],
NULL
);
if
(
!
event
)
return
js_mkerr
(
js
,
"event must be a string"
);
if
(
js_type
(
args
[
1
])
!=
JS_FUNC
)
return
js_mkerr
(
js
,
"listener must be a function"
);
int
signum
=
get_signal_number
(
event
);
if
(
signum
>
0
)
{
signal
(
signum
,
process_signal_handler
);
}
ProcessEventType
*
evt
=
find_or_create_event_type
(
event
);
if
(
!
ensure_listener_capacity
(
evt
))
{
return
js_mkerr
(
js
,
"failed to allocate listener"
);
}
evt
->
listeners
[
evt
->
listener_count
].
listener
=
args
[
1
];
evt
->
listeners
[
evt
->
listener_count
].
once
=
false
;
evt
->
listener_count
++
;
check_listener_warning
(
event
);
return
js_get
(
js
,
js_glob
(
js
),
"process"
);
}
static
jsval_t
process_once
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
if
(
nargs
<
2
)
return
js_mkerr
(
js
,
"process.once requires 2 arguments"
);
char
*
event
=
js_getstr
(
js
,
args
[
0
],
NULL
);
if
(
!
event
)
return
js_mkerr
(
js
,
"event must be a string"
);
if
(
js_type
(
args
[
1
])
!=
JS_FUNC
)
return
js_mkerr
(
js
,
"listener must be a function"
);
int
signum
=
get_signal_number
(
event
);
if
(
signum
>
0
)
{
signal
(
signum
,
process_signal_handler
);
}
ProcessEventType
*
evt
=
find_or_create_event_type
(
event
);
if
(
!
ensure_listener_capacity
(
evt
))
{
return
js_mkerr
(
js
,
"failed to allocate listener"
);
}
evt
->
listeners
[
evt
->
listener_count
].
listener
=
args
[
1
];
evt
->
listeners
[
evt
->
listener_count
].
once
=
true
;
evt
->
listener_count
++
;
check_listener_warning
(
event
);
return
js_get
(
js
,
js_glob
(
js
),
"process"
);
}
static
jsval_t
process_off
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
jsval_t
process_obj
=
js_get
(
js
,
js_glob
(
js
),
"process"
);
if
(
nargs
<
2
)
return
process_obj
;
char
*
event
=
js_getstr
(
js
,
args
[
0
],
NULL
);
if
(
!
event
)
return
process_obj
;
ProcessEventType
*
evt
=
NULL
;
HASH_FIND_STR
(
process_events
,
event
,
evt
);
if
(
!
evt
)
return
process_obj
;
for
(
int
i
=
0
;
i
<
evt
->
listener_count
;
i
++
)
{
if
(
evt
->
listeners
[
i
].
listener
==
args
[
1
])
{
for
(
int
j
=
i
;
j
<
evt
->
listener_count
-
1
;
j
++
)
{
evt
->
listeners
[
j
]
=
evt
->
listeners
[
j
+
1
];
}
evt
->
listener_count
--
;
break
;
}
}
if
(
evt
->
listener_count
==
0
)
{
int
signum
=
get_signal_number
(
event
);
if
(
signum
>
0
)
signal
(
signum
,
SIG_DFL
);
}
return
process_obj
;
}
static
jsval_t
process_remove_all_listeners
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
jsval_t
process_obj
=
js_get
(
js
,
js_glob
(
js
),
"process"
);
if
(
nargs
>
0
&&
js_type
(
args
[
0
])
==
JS_STR
)
{
char
*
event
=
js_getstr
(
js
,
args
[
0
],
NULL
);
if
(
event
)
{
ProcessEventType
*
evt
=
NULL
;
HASH_FIND_STR
(
process_events
,
event
,
evt
);
if
(
evt
)
{
evt
->
listener_count
=
0
;
int
signum
=
get_signal_number
(
event
);
if
(
signum
>
0
)
signal
(
signum
,
SIG_DFL
);
}
}
}
else
{
ProcessEventType
*
evt
,
*
tmp
;
HASH_ITER
(
hh
,
process_events
,
evt
,
tmp
)
{
int
signum
=
get_signal_number
(
evt
->
event_type
);
if
(
signum
>
0
)
signal
(
signum
,
SIG_DFL
);
evt
->
listener_count
=
0
;
}
}
return
process_obj
;
}
static
jsval_t
process_emit
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_mkfalse
();
char
*
event
=
js_getstr
(
js
,
args
[
0
],
NULL
);
if
(
!
event
)
return
js_mkfalse
();
emit_process_event
(
event
,
nargs
>
1
?
&
args
[
1
]
:
NULL
,
nargs
-
1
);
return
js_mktrue
();
}
static
jsval_t
process_listener_count
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_mknum
(
0
);
char
*
event
=
js_getstr
(
js
,
args
[
0
],
NULL
);
if
(
!
event
)
return
js_mknum
(
0
);
ProcessEventType
*
evt
=
NULL
;
HASH_FIND_STR
(
process_events
,
event
,
evt
);
return
js_mknum
(
evt
?
evt
->
listener_count
:
0
);
}
static
jsval_t
process_set_max_listeners
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_mkerr
(
js
,
"setMaxListeners requires 1 argument"
);
if
(
js_type
(
args
[
0
])
!=
JS_NUM
)
return
js_mkerr
(
js
,
"n must be a number"
);
int
n
=
(
int
)
js_getnum
(
args
[
0
]);
if
(
n
<
0
)
return
js_mkerr
(
js
,
"n must be non-negative"
);
max_listeners
=
n
;
return
js_get
(
js
,
js_glob
(
js
),
"process"
);
}
static
jsval_t
process_get_max_listeners
(
ant_t
*
js
,
jsval_t
*
args
,
int
nargs
)
{
return
js_mknum
(
max_listeners
);
}
void
init_process_module
()
{
ant_t
*
js
=
rt
->
js
;
jsval_t
global
=
js_glob
(
js
);
process_start_time
=
uv_hrtime
();
jsval_t
process_proto
=
js_mkobj
(
js
);
js_set
(
js
,
process_proto
,
"exit"
,
js_mkfun
(
process_exit
));
js_set
(
js
,
process_proto
,
"on"
,
js_mkfun
(
process_on
));
js_set
(
js
,
process_proto
,
"addListener"
,
js_mkfun
(
process_on
));
js_set
(
js
,
process_proto
,
"once"
,
js_mkfun
(
process_once
));
js_set
(
js
,
process_proto
,
"off"
,
js_mkfun
(
process_off
));
js_set
(
js
,
process_proto
,
"removeListener"
,
js_mkfun
(
process_off
));
js_set
(
js
,
process_proto
,
"removeAllListeners"
,
js_mkfun
(
process_remove_all_listeners
));
js_set
(
js
,
process_proto
,
"emit"
,
js_mkfun
(
process_emit
));
js_set
(
js
,
process_proto
,
"listenerCount"
,
js_mkfun
(
process_listener_count
));
js_set
(
js
,
process_proto
,
"setMaxListeners"
,
js_mkfun
(
process_set_max_listeners
));
js_set
(
js
,
process_proto
,
"getMaxListeners"
,
js_mkfun
(
process_get_max_listeners
));
js_set
(
js
,
process_proto
,
"cwd"
,
js_mkfun
(
process_cwd
));
js_set
(
js
,
process_proto
,
"chdir"
,
js_mkfun
(
process_chdir
));
js_set
(
js
,
process_proto
,
"uptime"
,
js_mkfun
(
process_uptime
));
js_set
(
js
,
process_proto
,
"cpuUsage"
,
js_mkfun
(
process_cpu_usage
));
js_set
(
js
,
process_proto
,
"kill"
,
js_mkfun
(
process_kill
));
js_set
(
js
,
process_proto
,
"abort"
,
js_mkfun
(
process_abort
));
js_set
(
js
,
process_proto
,
"umask"
,
js_mkfun
(
process_umask
));
jsval_t
mem_usage_fn
=
js_heavy_mkfun
(
js
,
process_memory_usage
,
js_mkundef
());
js_set
(
js
,
mem_usage_fn
,
"rss"
,
js_mkfun
(
process_memory_usage_rss
));
js_set
(
js
,
process_proto
,
"memoryUsage"
,
mem_usage_fn
);
jsval_t
hrtime_fn
=
js_heavy_mkfun
(
js
,
process_hrtime
,
js_mkundef
());
js_set
(
js
,
hrtime_fn
,
"bigint"
,
js_mkfun
(
process_hrtime_bigint
));
js_set
(
js
,
process_proto
,
"hrtime"
,
hrtime_fn
);
#ifndef _WIN32
js_set
(
js
,
process_proto
,
"getuid"
,
js_mkfun
(
process_getuid
));
js_set
(
js
,
process_proto
,
"geteuid"
,
js_mkfun
(
process_geteuid
));
js_set
(
js
,
process_proto
,
"getgid"
,
js_mkfun
(
process_getgid
));
js_set
(
js
,
process_proto
,
"getegid"
,
js_mkfun
(
process_getegid
));
js_set
(
js
,
process_proto
,
"getgroups"
,
js_mkfun
(
process_getgroups
));
js_set
(
js
,
process_proto
,
"setuid"
,
js_mkfun
(
process_setuid
));
js_set
(
js
,
process_proto
,
"setgid"
,
js_mkfun
(
process_setgid
));
js_set
(
js
,
process_proto
,
"seteuid"
,
js_mkfun
(
process_seteuid
));
js_set
(
js
,
process_proto
,
"setegid"
,
js_mkfun
(
process_setegid
));
js_set
(
js
,
process_proto
,
"setgroups"
,
js_mkfun
(
process_setgroups
));
js_set
(
js
,
process_proto
,
"initgroups"
,
js_mkfun
(
process_initgroups
));
#endif
js_set
(
js
,
process_proto
,
get_toStringTag_sym_key
(),
js_mkstr
(
js
,
"process"
,
7
));
jsval_t
process_obj
=
js_mkobj
(
js
);
js_set_proto
(
js
,
process_obj
,
process_proto
);
jsval_t
env_obj
=
js_mkobj
(
js
);
load_dotenv_file
(
js
,
env_obj
);
js_set_getter
(
js
,
env_obj
,
env_getter
);
js_set
(
js
,
env_obj
,
"toObject"
,
js_mkfun
(
env_to_object
));
js_set
(
js
,
process_obj
,
"env"
,
env_obj
);
jsval_t
argv_arr
=
js_mkarr
(
js
);
for
(
int
i
=
0
;
i
<
rt
->
argc
;
i
++
)
{
js_arr_push
(
js
,
argv_arr
,
js_mkstr
(
js
,
rt
->
argv
[
i
],
strlen
(
rt
->
argv
[
i
])));
}
js_set
(
js
,
process_obj
,
"argv"
,
argv_arr
);
js_set
(
js
,
process_obj
,
"execArgv"
,
js_mkarr
(
js
));
js_set
(
js
,
process_obj
,
"argv0"
,
rt
->
argc
>
0
?
js_mkstr
(
js
,
rt
->
argv
[
0
],
strlen
(
rt
->
argv
[
0
]))
:
js_mkstr
(
js
,
"ant"
,
3
));
js_set
(
js
,
process_obj
,
"execPath"
,
rt
->
argc
>
0
?
js_mkstr
(
js
,
rt
->
argv
[
0
],
strlen
(
rt
->
argv
[
0
]))
:
js_mkundef
());
js_set
(
js
,
process_obj
,
"pid"
,
js_mknum
((
double
)
getpid
()));
js_set
(
js
,
process_obj
,
"ppid"
,
js_mknum
((
double
)
getppid
()));
char
version_str
[
128
];
snprintf
(
version_str
,
sizeof
(
version_str
),
"v%s"
,
ANT_VERSION
);
js_set
(
js
,
process_obj
,
"version"
,
js_mkstr
(
js
,
version_str
,
strlen
(
version_str
)));
jsval_t
versions_obj
=
js_mkobj
(
js
);
js_set
(
js
,
versions_obj
,
"ant"
,
js_mkstr
(
js
,
ANT_VERSION
,
strlen
(
ANT_VERSION
)));
char
uv_ver
[
32
];
snprintf
(
uv_ver
,
sizeof
(
uv_ver
),
"%d.%d.%d"
,
UV_VERSION_MAJOR
,
UV_VERSION_MINOR
,
UV_VERSION_PATCH
);
js_set
(
js
,
versions_obj
,
"uv"
,
js_mkstr
(
js
,
uv_ver
,
strlen
(
uv_ver
)));
js_set
(
js
,
process_obj
,
"versions"
,
versions_obj
);
jsval_t
release_obj
=
js_mkobj
(
js
);
js_set
(
js
,
release_obj
,
"name"
,
js_mkstr
(
js
,
"ant"
,
3
));
js_set
(
js
,
process_obj
,
"release"
,
release_obj
);
// process.platform
#if defined(__APPLE__)
js_set
(
js
,
process_obj
,
"platform"
,
js_mkstr
(
js
,
"darwin"
,
6
));
#elif defined(__linux__)
js_set
(
js
,
process_obj
,
"platform"
,
js_mkstr
(
js
,
"linux"
,
5
));
#elif defined(_WIN32) || defined(_WIN64)
js_set
(
js
,
process_obj
,
"platform"
,
js_mkstr
(
js
,
"win32"
,
5
));
#elif defined(__FreeBSD__)
js_set
(
js
,
process_obj
,
"platform"
,
js_mkstr
(
js
,
"freebsd"
,
7
));
#else
js_set
(
js
,
process_obj
,
"platform"
,
js_mkstr
(
js
,
"unknown"
,
7
));
#endif
// process.arch
#if defined(__x86_64__) || defined(_M_X64)
js_set
(
js
,
process_obj
,
"arch"
,
js_mkstr
(
js
,
"x64"
,
3
));
#elif defined(__i386__) || defined(_M_IX86)
js_set
(
js
,
process_obj
,
"arch"
,
js_mkstr
(
js
,
"ia32"
,
4
));
#elif defined(__aarch64__) || defined(_M_ARM64)
js_set
(
js
,
process_obj
,
"arch"
,
js_mkstr
(
js
,
"arm64"
,
5
));
#elif defined(__arm__) || defined(_M_ARM)
js_set
(
js
,
process_obj
,
"arch"
,
js_mkstr
(
js
,
"arm"
,
3
));
#else
js_set
(
js
,
process_obj
,
"arch"
,
js_mkstr
(
js
,
"unknown"
,
7
));
#endif
jsval_t
stdin_proto
=
js_mkobj
(
js
);
js_set
(
js
,
stdin_proto
,
"setRawMode"
,
js_mkfun
(
js_stdin_set_raw_mode
));
js_set
(
js
,
stdin_proto
,
"resume"
,
js_mkfun
(
js_stdin_resume
));
js_set
(
js
,
stdin_proto
,
"pause"
,
js_mkfun
(
js_stdin_pause
));
js_set
(
js
,
stdin_proto
,
"on"
,
js_mkfun
(
js_stdin_on
));
js_set
(
js
,
stdin_proto
,
"removeAllListeners"
,
js_mkfun
(
js_stdin_remove_all_listeners
));
js_set
(
js
,
stdin_proto
,
get_toStringTag_sym_key
(),
js_mkstr
(
js
,
"ReadStream"
,
10
));
jsval_t
stdin_obj
=
js_mkobj
(
js
);
js_set_proto
(
js
,
stdin_obj
,
stdin_proto
);
js_set
(
js
,
stdin_obj
,
"isTTY"
,
stdin_is_tty
()
?
js_mktrue
()
:
js_mkfalse
());
js_set
(
js
,
process_obj
,
"stdin"
,
stdin_obj
);
jsval_t
stdout_proto
=
js_mkobj
(
js
);
js_set
(
js
,
stdout_proto
,
"write"
,
js_mkfun
(
js_stdout_write
));
js_set
(
js
,
stdout_proto
,
"on"
,
js_mkfun
(
js_stdout_on
));
js_set
(
js
,
stdout_proto
,
"once"
,
js_mkfun
(
js_stdout_once
));
js_set
(
js
,
stdout_proto
,
"removeAllListeners"
,
js_mkfun
(
js_stdout_remove_all_listeners
));
js_set
(
js
,
stdout_proto
,
"getWindowSize"
,
js_mkfun
(
js_stdout_get_window_size
));
js_set
(
js
,
stdout_proto
,
get_toStringTag_sym_key
(),
js_mkstr
(
js
,
"WriteStream"
,
11
));
jsval_t
stdout_obj
=
js_mkobj
(
js
);
js_set_proto
(
js
,
stdout_obj
,
stdout_proto
);
js_set
(
js
,
stdout_obj
,
"isTTY"
,
stdout_is_tty
()
?
js_mktrue
()
:
js_mkfalse
());
js_set_getter_desc
(
js
,
stdout_obj
,
"rows"
,
4
,
js_mkfun
(
js_stdout_rows_getter
),
JS_DESC_E
|
JS_DESC_C
);
js_set_getter_desc
(
js
,
stdout_obj
,
"columns"
,
7
,
js_mkfun
(
js_stdout_columns_getter
),
JS_DESC_E
|
JS_DESC_C
);
js_set
(
js
,
process_obj
,
"stdout"
,
stdout_obj
);
jsval_t
stderr_proto
=
js_mkobj
(
js
);
js_set
(
js
,
stderr_proto
,
"write"
,
js_mkfun
(
js_stderr_write
));
js_set
(
js
,
stderr_proto
,
"on"
,
js_mkfun
(
js_stderr_on
));
js_set
(
js
,
stderr_proto
,
"once"
,
js_mkfun
(
js_stderr_once
));
js_set
(
js
,
stderr_proto
,
"removeAllListeners"
,
js_mkfun
(
js_stderr_remove_all_listeners
));
js_set
(
js
,
stderr_proto
,
get_toStringTag_sym_key
(),
js_mkstr
(
js
,
"WriteStream"
,
11
));
jsval_t
stderr_obj
=
js_mkobj
(
js
);
js_set_proto
(
js
,
stderr_obj
,
stderr_proto
);
js_set
(
js
,
stderr_obj
,
"isTTY"
,
stderr_is_tty
()
?
js_mktrue
()
:
js_mkfalse
());
js_set
(
js
,
process_obj
,
"stderr"
,
stderr_obj
);
js_set
(
js
,
global
,
"process"
,
process_obj
);
}
#define GC_FWD_EVENTS(events) do { \
ProcessEventType *evt, *tmp; \
HASH_ITER(hh, events, evt, tmp) { \
for (int i = 0; i < evt->listener_count; i++) \
evt->listeners[i].listener = fwd_val(ctx, evt->listeners[i].listener); \
} \
} while(0)
void
process_gc_update_roots
(
GC_FWD_ARGS
)
{
GC_FWD_EVENTS
(
process_events
);
GC_FWD_EVENTS
(
stdin_events
);
GC_FWD_EVENTS
(
stdout_events
);
GC_FWD_EVENTS
(
stderr_events
);
}
#undef GC_FWD_EVENTS
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Fri, Mar 27, 4:35 AM (1 d, 22 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
512737
Default Alt Text
process.c (43 KB)
Attached To
Mode
rANT Ant
Attached
Detach File
Event Timeline
Log In to Comment