Merge branch 'develop-tfe4a' of https://git.mesalab.cn/tango/tfe into develop-tfe4a
This commit is contained in:
@@ -51,5 +51,5 @@ if [ -n "${PACKAGE}" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -n "${UPLOAD_SYMBOL_FILES}" ]; then
|
if [ -n "${UPLOAD_SYMBOL_FILES}" ]; then
|
||||||
sentry-cli upload-dif -t elf build/
|
sentry-cli upload-dif -t elf ./
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -28,8 +28,6 @@ void ssl_stream_process_zero_eof(struct ssl_stream * s_stream, struct ssl_mgr* m
|
|||||||
|
|
||||||
|
|
||||||
enum ssl_stream_action ssl_upstream_create_result_release_action(future_result_t * result);
|
enum ssl_stream_action ssl_upstream_create_result_release_action(future_result_t * result);
|
||||||
evutil_socket_t ssl_upstream_create_result_release_fd(future_result_t * result);
|
|
||||||
|
|
||||||
struct ssl_stream * ssl_upstream_create_result_release_stream(future_result_t * result);
|
struct ssl_stream * ssl_upstream_create_result_release_stream(future_result_t * result);
|
||||||
struct bufferevent * ssl_upstream_create_result_release_bev(future_result_t * result);
|
struct bufferevent * ssl_upstream_create_result_release_bev(future_result_t * result);
|
||||||
void ssl_async_upstream_create(struct future * f, struct ssl_mgr * mgr, evutil_socket_t fd_upstream,
|
void ssl_async_upstream_create(struct future * f, struct ssl_mgr * mgr, evutil_socket_t fd_upstream,
|
||||||
@@ -44,7 +42,7 @@ void ssl_async_downstream_create(struct future * f, struct ssl_mgr * mgr, struct
|
|||||||
evutil_socket_t fd_downstream, struct tfe_stream* tcp_stream);
|
evutil_socket_t fd_downstream, struct tfe_stream* tcp_stream);
|
||||||
|
|
||||||
|
|
||||||
void ssl_stream_free_and_close_fd(struct ssl_stream * s_stream, struct event_base * evbase, struct bufferevent * bev);
|
void ssl_stream_free(struct ssl_stream * s_stream, struct event_base * evbase, struct bufferevent * bev);
|
||||||
const char* ssl_stream_dump_info(struct ssl_stream *stream, char* buffer, size_t sz);
|
const char* ssl_stream_dump_info(struct ssl_stream *stream, char* buffer, size_t sz);
|
||||||
//Follow functions are allowed to call during runtime.
|
//Follow functions are allowed to call during runtime.
|
||||||
int ssl_manager_add_trust_ca(struct ssl_mgr* mgr, const char* pem_file);
|
int ssl_manager_add_trust_ca(struct ssl_mgr* mgr, const char* pem_file);
|
||||||
|
|||||||
@@ -47,6 +47,8 @@ void acceptor_kni_v2_event(evutil_socket_t fd, short what, void * user)
|
|||||||
struct tfe_cmsg * cmsg = NULL;
|
struct tfe_cmsg * cmsg = NULL;
|
||||||
|
|
||||||
int * __fds = NULL;
|
int * __fds = NULL;
|
||||||
|
unsigned int __nr_fds = 0;
|
||||||
|
|
||||||
assert(__ctx != NULL && __ctx->thread == pthread_self());
|
assert(__ctx != NULL && __ctx->thread == pthread_self());
|
||||||
assert(what & EV_READ);
|
assert(what & EV_READ);
|
||||||
|
|
||||||
@@ -92,10 +94,18 @@ void acceptor_kni_v2_event(evutil_socket_t fd, short what, void * user)
|
|||||||
goto __drop_recieved_fds;
|
goto __drop_recieved_fds;
|
||||||
}
|
}
|
||||||
|
|
||||||
__fds = (int *) (CMSG_DATA(__cmsghdr));
|
switch(__cmsghdr->cmsg_len)
|
||||||
if (unlikely(__fds == NULL))
|
|
||||||
{
|
{
|
||||||
TFE_LOG_ERROR(__ctx->logger, "failed at fetch CMSG_DATA() from incoming fds.");
|
case CMSG_LEN(0 * sizeof(int)): { __nr_fds = 0; break;}
|
||||||
|
case CMSG_LEN(1 * sizeof(int)): { __nr_fds = 1; break;}
|
||||||
|
case CMSG_LEN(2 * sizeof(int)): { __nr_fds = 2; break; }
|
||||||
|
default: assert(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
__fds = (int *) (CMSG_DATA(__cmsghdr));
|
||||||
|
if (unlikely(__fds == NULL || __nr_fds < 2))
|
||||||
|
{
|
||||||
|
TFE_LOG_ERROR(__ctx->logger, "No available file descriptors, drop the incoming fds.");
|
||||||
goto __drop_recieved_fds;
|
goto __drop_recieved_fds;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,9 +130,13 @@ __die:
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
__drop_recieved_fds:
|
__drop_recieved_fds:
|
||||||
TFE_PROXY_STAT_INCREASE(STAT_FD_CLOSE_BY_KNI_ACCEPT_FAIL, 2);
|
TFE_PROXY_STAT_INCREASE(STAT_FD_CLOSE_BY_KNI_ACCEPT_FAIL, __nr_fds);
|
||||||
if (__fds != NULL) evutil_closesocket(__fds[0]);
|
for (unsigned int i = 0; i < __nr_fds; i++)
|
||||||
if (__fds != NULL) evutil_closesocket(__fds[1]);
|
{
|
||||||
|
evutil_closesocket(__fds[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(__nr_fds <= 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void * acceptor_kni_v2_event_thread_entry(void * args)
|
void * acceptor_kni_v2_event_thread_entry(void * args)
|
||||||
|
|||||||
@@ -2121,7 +2121,7 @@ complete:
|
|||||||
* Guarantees that SSL and the corresponding SSL_CTX are freed and the
|
* Guarantees that SSL and the corresponding SSL_CTX are freed and the
|
||||||
* socket is closed, eventually, or in the case of fatal errors, immediately.
|
* socket is closed, eventually, or in the case of fatal errors, immediately.
|
||||||
*/
|
*/
|
||||||
void ssl_stream_free_and_close_fd(struct ssl_stream * s_stream, struct event_base * evbase, struct bufferevent * bev)
|
void ssl_stream_free(struct ssl_stream * s_stream, struct event_base * evbase, struct bufferevent * bev)
|
||||||
{
|
{
|
||||||
UNUSED struct ssl_shutdown_ctx * sslshutctx = NULL;
|
UNUSED struct ssl_shutdown_ctx * sslshutctx = NULL;
|
||||||
evutil_socket_t fd=-1;
|
evutil_socket_t fd=-1;
|
||||||
@@ -2165,8 +2165,8 @@ void ssl_stream_free_and_close_fd(struct ssl_stream * s_stream, struct event_bas
|
|||||||
bufferevent_setcb(ubev, NULL, NULL, NULL, NULL);
|
bufferevent_setcb(ubev, NULL, NULL, NULL, NULL);
|
||||||
bufferevent_free(ubev);
|
bufferevent_free(ubev);
|
||||||
}
|
}
|
||||||
|
|
||||||
ssl_stream_free(s_stream);
|
ssl_stream_free(s_stream);
|
||||||
evutil_closesocket(fd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int ssl_manager_add_trust_ca(struct ssl_mgr* mgr, const char* pem_file)
|
int ssl_manager_add_trust_ca(struct ssl_mgr* mgr, const char* pem_file)
|
||||||
|
|||||||
@@ -401,7 +401,11 @@ evutil_socket_t __conn_private_release_fd(struct tfe_conn_private * conn)
|
|||||||
|
|
||||||
static void __conn_private_destory(struct tfe_conn_private * conn)
|
static void __conn_private_destory(struct tfe_conn_private * conn)
|
||||||
{
|
{
|
||||||
|
if (conn->bev)
|
||||||
|
{
|
||||||
bufferevent_disable(conn->bev, EV_READ | EV_WRITE);
|
bufferevent_disable(conn->bev, EV_READ | EV_WRITE);
|
||||||
|
bufferevent_free(conn->bev);
|
||||||
|
}
|
||||||
|
|
||||||
if(conn->ratelimit_bucket)
|
if(conn->ratelimit_bucket)
|
||||||
{
|
{
|
||||||
@@ -409,10 +413,9 @@ static void __conn_private_destory(struct tfe_conn_private * conn)
|
|||||||
conn->ratelimit_bucket = NULL;
|
conn->ratelimit_bucket = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
bufferevent_free(conn->bev);
|
|
||||||
if (conn->fd > 0)
|
if (conn->fd > 0)
|
||||||
{
|
{
|
||||||
evutil_closesocket(conn->fd);
|
assert(evutil_closesocket(conn->fd) >= 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(conn);
|
free(conn);
|
||||||
@@ -423,8 +426,7 @@ static void __conn_private_destory_with_ssl(struct event_base * ev_base,
|
|||||||
struct tfe_conn_private * conn, struct ssl_stream * ssl_stream)
|
struct tfe_conn_private * conn, struct ssl_stream * ssl_stream)
|
||||||
{
|
{
|
||||||
if (ssl_stream == NULL) return __conn_private_destory(conn);
|
if (ssl_stream == NULL) return __conn_private_destory(conn);
|
||||||
ssl_stream_free_and_close_fd(ssl_stream, ev_base, conn->bev);
|
ssl_stream_free(ssl_stream, ev_base, conn->bev);
|
||||||
conn->fd = -1;
|
|
||||||
return __conn_private_destory(conn);
|
return __conn_private_destory(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -950,14 +952,15 @@ void ssl_downstream_create_on_success(future_result_t * result, void * user)
|
|||||||
{
|
{
|
||||||
struct tfe_stream_private * _stream = (struct tfe_stream_private *) user;
|
struct tfe_stream_private * _stream = (struct tfe_stream_private *) user;
|
||||||
struct ssl_stream * downstream = ssl_downstream_create_result_release_stream(result);
|
struct ssl_stream * downstream = ssl_downstream_create_result_release_stream(result);
|
||||||
|
|
||||||
struct bufferevent * bev = ssl_downstream_create_result_release_bev(result);
|
struct bufferevent * bev = ssl_downstream_create_result_release_bev(result);
|
||||||
|
_stream->defer_fd_downstream = 0;
|
||||||
|
|
||||||
_stream->conn_downstream = __conn_private_create_by_bev(_stream, bev);
|
_stream->conn_downstream = __conn_private_create_by_bev(_stream, bev);
|
||||||
_stream->ssl_downstream = downstream;
|
_stream->ssl_downstream = downstream;
|
||||||
|
|
||||||
future_destroy(_stream->future_downstream_create);
|
future_destroy(_stream->future_downstream_create);
|
||||||
_stream->future_downstream_create = NULL;
|
_stream->future_downstream_create = NULL;
|
||||||
_stream->defer_fd_downstream = 0;
|
|
||||||
|
|
||||||
assert(_stream->conn_downstream != NULL && _stream->conn_upstream != NULL);
|
assert(_stream->conn_downstream != NULL && _stream->conn_upstream != NULL);
|
||||||
|
|
||||||
@@ -988,19 +991,17 @@ void ssl_downstream_create_on_fail(enum e_future_error err, const char * what, v
|
|||||||
void ssl_upstream_create_on_success(future_result_t * result, void * user)
|
void ssl_upstream_create_on_success(future_result_t * result, void * user)
|
||||||
{
|
{
|
||||||
struct tfe_stream_private * _stream = (struct tfe_stream_private *) user;
|
struct tfe_stream_private * _stream = (struct tfe_stream_private *) user;
|
||||||
evutil_socket_t fd=-1;
|
evutil_socket_t fd = -1;
|
||||||
enum ssl_stream_action ssl_action=ssl_upstream_create_result_release_action(result);
|
enum ssl_stream_action ssl_action = ssl_upstream_create_result_release_action(result);
|
||||||
if(SSL_ACTION_PASSTHROUGH==ssl_action)
|
if (SSL_ACTION_PASSTHROUGH == ssl_action)
|
||||||
{
|
{
|
||||||
_stream->tcp_passthough=1;
|
_stream->tcp_passthough = 1;
|
||||||
fd=ssl_upstream_create_result_release_fd(result);
|
_stream->conn_upstream = __conn_private_create_by_fd(_stream, _stream->defer_fd_upstream);
|
||||||
_stream->conn_upstream=__conn_private_create_by_fd(_stream, fd);
|
_stream->conn_downstream = __conn_private_create_by_fd(_stream, _stream->defer_fd_downstream);
|
||||||
_stream->conn_downstream=__conn_private_create_by_fd(_stream, _stream->defer_fd_downstream);
|
|
||||||
__conn_private_enable(_stream->conn_downstream);
|
__conn_private_enable(_stream->conn_downstream);
|
||||||
__conn_private_enable(_stream->conn_upstream);
|
__conn_private_enable(_stream->conn_upstream);
|
||||||
|
|
||||||
}
|
}
|
||||||
else if(SSL_ACTION_SHUTDOWN==ssl_action)
|
else if (SSL_ACTION_SHUTDOWN == ssl_action)
|
||||||
{
|
{
|
||||||
tfe_stream_destory(_stream);
|
tfe_stream_destory(_stream);
|
||||||
}
|
}
|
||||||
@@ -1010,7 +1011,8 @@ void ssl_upstream_create_on_success(future_result_t * result, void * user)
|
|||||||
struct bufferevent * bev = ssl_upstream_create_result_release_bev(result);
|
struct bufferevent * bev = ssl_upstream_create_result_release_bev(result);
|
||||||
assert(upstream != NULL && bev != NULL);
|
assert(upstream != NULL && bev != NULL);
|
||||||
|
|
||||||
/* Create connection ctx by bev */
|
/* Create connection ctx by bev, fd's ownership is transfer to bev */
|
||||||
|
_stream->defer_fd_upstream = 0;
|
||||||
_stream->conn_upstream = __conn_private_create_by_bev(_stream, bev);
|
_stream->conn_upstream = __conn_private_create_by_bev(_stream, bev);
|
||||||
_stream->ssl_upstream = upstream;
|
_stream->ssl_upstream = upstream;
|
||||||
|
|
||||||
@@ -1024,10 +1026,9 @@ void ssl_upstream_create_on_success(future_result_t * result, void * user)
|
|||||||
ssl_async_downstream_create(_stream->future_downstream_create, _stream->ssl_mgr,
|
ssl_async_downstream_create(_stream->future_downstream_create, _stream->ssl_mgr,
|
||||||
_stream->ssl_upstream, _stream->defer_fd_downstream, &_stream->head);
|
_stream->ssl_upstream, _stream->defer_fd_downstream, &_stream->head);
|
||||||
}
|
}
|
||||||
|
|
||||||
future_destroy(_stream->future_upstream_create);
|
future_destroy(_stream->future_upstream_create);
|
||||||
_stream->future_upstream_create = NULL;
|
_stream->future_upstream_create = NULL;
|
||||||
_stream->defer_fd_upstream = 0;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ssl_upstream_create_on_fail(enum e_future_error err, const char * what, void * user)
|
void ssl_upstream_create_on_fail(enum e_future_error err, const char * what, void * user)
|
||||||
@@ -1126,21 +1127,23 @@ void tfe_stream_destory(struct tfe_stream_private * stream)
|
|||||||
|
|
||||||
if (__is_ssl(stream) && stream->ssl_upstream)
|
if (__is_ssl(stream) && stream->ssl_upstream)
|
||||||
{
|
{
|
||||||
ssl_stream_free_and_close_fd(stream->ssl_upstream, ev_base, stream->conn_upstream->bev);
|
ssl_stream_free(stream->ssl_upstream, ev_base, stream->conn_upstream->bev);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (__is_ssl(stream) && stream->ssl_downstream)
|
if (__is_ssl(stream) && stream->ssl_downstream)
|
||||||
{
|
{
|
||||||
ssl_stream_free_and_close_fd(stream->ssl_downstream, ev_base, stream->conn_downstream->bev);
|
ssl_stream_free(stream->ssl_downstream, ev_base, stream->conn_downstream->bev);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stream->conn_upstream)
|
if (stream->conn_upstream)
|
||||||
{
|
{
|
||||||
|
assert(stream->defer_fd_upstream <= 0);
|
||||||
__conn_private_destory(stream->conn_upstream);
|
__conn_private_destory(stream->conn_upstream);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stream->conn_downstream)
|
if (stream->conn_downstream)
|
||||||
{
|
{
|
||||||
|
assert(stream->defer_fd_downstream <= 0);
|
||||||
__conn_private_destory(stream->conn_downstream);
|
__conn_private_destory(stream->conn_downstream);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1327,13 +1330,21 @@ int tfe_stream_init_by_fds(struct tfe_stream * stream, evutil_socket_t fd_downst
|
|||||||
if (_stream->session_type == STREAM_PROTO_PLAIN)
|
if (_stream->session_type == STREAM_PROTO_PLAIN)
|
||||||
{
|
{
|
||||||
_stream->conn_downstream = __conn_private_create_by_fd(_stream, fd_downstream);
|
_stream->conn_downstream = __conn_private_create_by_fd(_stream, fd_downstream);
|
||||||
_stream->conn_upstream = __conn_private_create_by_fd(_stream, fd_upstream);
|
if (_stream->conn_downstream != NULL)
|
||||||
|
{
|
||||||
/* Defer FD has been transfer to conn_downstream/conn_upstream */
|
|
||||||
_stream->defer_fd_downstream = 0;
|
_stream->defer_fd_downstream = 0;
|
||||||
_stream->defer_fd_upstream = 0;
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
goto __errout;
|
||||||
|
}
|
||||||
|
|
||||||
if (unlikely(_stream->conn_downstream == NULL || _stream->conn_upstream == NULL))
|
_stream->conn_upstream = __conn_private_create_by_fd(_stream, fd_upstream);
|
||||||
|
if (_stream->conn_upstream != NULL)
|
||||||
|
{
|
||||||
|
_stream->defer_fd_downstream = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
goto __errout;
|
goto __errout;
|
||||||
}
|
}
|
||||||
@@ -1364,6 +1375,12 @@ int tfe_stream_init_by_fds(struct tfe_stream * stream, evutil_socket_t fd_downst
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
__errout:
|
__errout:
|
||||||
|
/* The fds not been accept by this function, clear up and release at caller */
|
||||||
|
_stream->defer_fd_downstream = 0;
|
||||||
|
_stream->defer_fd_upstream = 0;
|
||||||
|
_stream->log_fd_downstream = 0;
|
||||||
|
_stream->log_fd_upstream = 0;
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
install(PROGRAMS user/r2_tfe DESTINATION ./ COMPONENT Program)
|
|
||||||
install(PROGRAMS user/r3_tfe DESTINATION ./ COMPONENT Program)
|
|
||||||
install(FILES sysctl/80-tfe.conf DESTINATION /etc/sysctl.d/ COMPONENT Program)
|
install(FILES sysctl/80-tfe.conf DESTINATION /etc/sysctl.d/ COMPONENT Program)
|
||||||
|
install(FILES service/tfe.service DESTINATION /usr/lib/systemd/system/ COMPONENT Program)
|
||||||
install(FILES service/tfe-env.service DESTINATION /usr/lib/systemd/system/ COMPONENT Program)
|
install(FILES service/tfe-env.service DESTINATION /usr/lib/systemd/system/ COMPONENT Program)
|
||||||
install(FILES service/tfe-env-config DESTINATION /etc/sysconfig/ COMPONENT Profile)
|
install(FILES service/tfe-env-config DESTINATION /etc/sysconfig/ COMPONENT Profile)
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
[Unit]
|
[Unit]
|
||||||
Description=Tango Frontend Engine - Running Environment Setup
|
Description=Tango Frontend Engine - Running Environment Setup
|
||||||
|
Before=tfe.service
|
||||||
|
Wants=network-online.target
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
EnvironmentFile=/etc/sysconfig/tfe-env-config
|
EnvironmentFile=/etc/sysconfig/tfe-env-config
|
||||||
@@ -10,7 +12,7 @@ RemainAfterExit=yes
|
|||||||
ExecStart=/bin/true
|
ExecStart=/bin/true
|
||||||
ExecStop=/bin/true
|
ExecStop=/bin/true
|
||||||
|
|
||||||
# dataincoming interface
|
ExecStartPost=/usr/sbin/modprobe tfe-kmod
|
||||||
ExecStartPost=/usr/sbin/ip link set ${TFE_DEVICE_DATA_INCOMING} address ${TFE_LOCAL_MAC_DATA_INCOMING}
|
ExecStartPost=/usr/sbin/ip link set ${TFE_DEVICE_DATA_INCOMING} address ${TFE_LOCAL_MAC_DATA_INCOMING}
|
||||||
ExecStartPost=/usr/sbin/ip link set ${TFE_DEVICE_DATA_INCOMING} up
|
ExecStartPost=/usr/sbin/ip link set ${TFE_DEVICE_DATA_INCOMING} up
|
||||||
ExecStartPost=/usr/sbin/ip addr flush dev ${TFE_DEVICE_DATA_INCOMING}
|
ExecStartPost=/usr/sbin/ip addr flush dev ${TFE_DEVICE_DATA_INCOMING}
|
||||||
@@ -41,6 +43,8 @@ ExecStopPost=/usr/sbin/ip -6 route del default via fd00::01
|
|||||||
ExecStopPost=/usr/sbin/ip -6 route del local default dev lo table 102
|
ExecStopPost=/usr/sbin/ip -6 route del local default dev lo table 102
|
||||||
ExecStopPost=/usr/sbin/ip addr del fd00::02/64 dev ${TFE_DEVICE_DATA_INCOMING}
|
ExecStopPost=/usr/sbin/ip addr del fd00::02/64 dev ${TFE_DEVICE_DATA_INCOMING}
|
||||||
ExecStopPost=/usr/sbin/ip link set ${TFE_DEVICE_DATA_INCOMING} down
|
ExecStopPost=/usr/sbin/ip link set ${TFE_DEVICE_DATA_INCOMING} down
|
||||||
|
ExecStopPost=/usr/sbin/modprobe -r tfe-kmod
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
|
RequiredBy=tfe.service
|
||||||
WantedBy=multi-user.target
|
WantedBy=multi-user.target
|
||||||
|
|||||||
20
script/service/tfe.service
Normal file
20
script/service/tfe.service
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Tango Frontend Engine
|
||||||
|
Requires=tfe-env.service
|
||||||
|
After=tfe-env.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
ExecStart=/opt/tsg/tfe/bin/tfe
|
||||||
|
TimeoutSec=180s
|
||||||
|
RestartSec=10s
|
||||||
|
Restart=always
|
||||||
|
LimitNOFILE=infinity
|
||||||
|
LimitNPROC=infinity
|
||||||
|
LimitCORE=infinity
|
||||||
|
TasksMax=infinity
|
||||||
|
Delegate=yes
|
||||||
|
KillMode=process
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
Reference in New Issue
Block a user