This commit is contained in:
Fedora Release Engineering 2019-08-08 16:45:26 +00:00
parent f808227815
commit 3b709249ea
30 changed files with 1 additions and 29343 deletions

14
.gitignore vendored
View File

@ -1,14 +0,0 @@
/torque-2.5.2.tar.gz
/torque-2.5.3.tar.gz
/torque-2.5.4.tar.gz
/torque-2.5.5.tar.gz
/torque-2.5.7.tar.gz
/torque-3.0.0.tar.gz
/torque-3.0.0-snap.201102011355.tar.gz
/torque-3.0.1.tar.gz
/torque-3.0.2.tar.gz
/torque-3.0.3.tar.gz
/torque-3.0.4.tar.gz
/torque-4.2.6.1.tar.gz
/torque-4.2.8.tar.gz
/torque-4.2.10.tar.gz

View File

@ -1,26 +0,0 @@
diff --git a/src/server/process_request.c b/src/server/process_request.c
index 4817ed0..6b4c955 100644
--- a/src/server/process_request.c
+++ b/src/server/process_request.c
@@ -679,6 +679,21 @@ void process_request(
log_buffer);
}
+ if (svr_conn[sfds].cn_authen != PBS_NET_CONN_FROM_PRIVIL)
+ {
+ sprintf(log_buffer, "request type %s from host %s rejected (connection not privileged)",
+ reqtype_to_txt(request->rq_type),
+ request->rq_host);
+
+ log_record(PBSEVENT_JOB, PBS_EVENTCLASS_JOB, id, log_buffer);
+
+ req_reject(PBSE_BADHOST, 0, request, NULL, "request not authorized");
+
+ close_client(sfds);
+
+ return;
+ }
+
/* if (!tfind(svr_conn[sfds].cn_addr, &okclients)) */
if (!AVL_is_in_tree(svr_conn[sfds].cn_addr, 0, okclients))
{

View File

@ -1,411 +0,0 @@
From 64da0af7ed27284f3397081313850bba270593db Mon Sep 17 00:00:00 2001
From: David Beer <dbeer@adaptivecomputing.com>
Date: Mon, 11 Nov 2013 11:55:08 -0700
Subject: [PATCH] Fix CVE 2013-4495. Note: this patch has been verified as
fixing this security hole but has not received other regression testing.
---
src/server/svr_mail.c | 297 ++++++++++++++++++++++++++++++--------------------
1 file changed, 178 insertions(+), 119 deletions(-)
diff --git a/src/server/svr_mail.c b/src/server/svr_mail.c
index 26b6dd7..a776399 100644
--- a/src/server/svr_mail.c
+++ b/src/server/svr_mail.c
@@ -91,6 +91,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
#include "list_link.h"
#include "attribute.h"
#include "server_limits.h"
@@ -98,7 +99,7 @@
#include "log.h"
#include "server.h"
#include "rpp.h"
-
+#include "utils.h"
/* External Functions Called */
@@ -111,21 +112,100 @@ extern struct server server;
extern int LOGLEVEL;
+
+
+
+/*
+ * write_email()
+ *
+ * In emailing, the mail body is written to a pipe connected to
+ * standard input for sendmail. This function supplies the body
+ * of the message.
+ *
+ */
+void write_email(
+
+ FILE *outmail_input,
+ job *pjob,
+ char *mailto,
+ int mailpoint,
+ char *text)
+
+ {
+ char *bodyfmt = NULL;
+ char bodyfmtbuf[MAXLINE];
+ char *subjectfmt = NULL;
+
+ /* Pipe in mail headers: To: and Subject: */
+ fprintf(outmail_input, "To: %s\n", mailto);
+
+ /* mail subject line formating statement */
+ if ((server.sv_attr[SRV_ATR_MailSubjectFmt].at_flags & ATR_VFLAG_SET) &&
+ (server.sv_attr[SRV_ATR_MailSubjectFmt].at_val.at_str != NULL))
+ {
+ subjectfmt = server.sv_attr[SRV_ATR_MailSubjectFmt].at_val.at_str;
+ }
+ else
+ {
+ subjectfmt = "PBS JOB %i";
+ }
+
+ fprintf(outmail_input, "Subject: ");
+ svr_format_job(outmail_input, pjob, subjectfmt, mailpoint, text);
+ fprintf(outmail_input, "\n");
+
+ /* Set "Precedence: bulk" to avoid vacation messages, etc */
+ fprintf(outmail_input, "Precedence: bulk\n\n");
+
+ /* mail body formating statement */
+ if ((server.sv_attr[SRV_ATR_MailBodyFmt].at_flags & ATR_VFLAG_SET) &&
+ (server.sv_attr[SRV_ATR_MailBodyFmt].at_val.at_str != NULL))
+ {
+ bodyfmt = server.sv_attr[SRV_ATR_MailBodyFmt].at_val.at_str;
+ }
+ else
+ {
+ bodyfmt = strcpy(bodyfmtbuf, "PBS Job Id: %i\n"
+ "Job Name: %j\n");
+ if (pjob->ji_wattr[JOB_ATR_exec_host].at_flags & ATR_VFLAG_SET)
+ {
+ strcat(bodyfmt, "Exec host: %h\n");
+ }
+
+ strcat(bodyfmt, "%m\n");
+
+ if (text != NULL)
+ {
+ strcat(bodyfmt, "%d\n");
+ }
+ }
+
+ /* Now pipe in the email body */
+ svr_format_job(outmail_input, pjob, bodyfmt, mailpoint, text);
+ } /* write_email() */
+
+
+
void svr_mailowner(
job *pjob, /* I */
- int mailpoint, /* note, single character */
+ int mailpoint, /* note, single character */
int force, /* if set to MAIL_FORCE, force mail delivery */
char *text) /* (optional) additional message text */
{
- char *cmdbuf;
- int i;
- char *mailfrom;
- char mailto[1024];
- char *bodyfmt, *subjectfmt;
- char bodyfmtbuf[1024];
- FILE *outmail;
+ int status = 0;
+ int numargs = 0;
+ int pipes[2];
+ int counter;
+ pid_t pid;
+ char *mailptr;
+ char *mailfrom = NULL;
+ char tmpBuf[LOG_BUF_SIZE];
+ // We call sendmail with cmd_name + 2 arguments + # of mailto addresses + 1 for null
+ char *sendmail_args[100];
+ char mailto[1024];
+ FILE *stream;
struct array_strings *pas;
@@ -217,17 +297,12 @@ void svr_mailowner(
return; /* its all up to the child now */
}
- /*
- * From here on, we are a child process of the server.
- * Fix up file descriptors and signal handlers.
- */
-
- rpp_terminate();
-
- net_close(-1);
-
+ /* Close the rest of the open file descriptors */
+ int numfds = sysconf(_SC_OPEN_MAX);
+ while (--numfds > 0)
+ close(numfds);
+
/* Who is mail from, if SRV_ATR_mailfrom not set use default */
-
if ((mailfrom = server.sv_attr[SRV_ATR_mailfrom].at_val.at_str) == NULL)
{
if (LOGLEVEL >= 5)
@@ -244,19 +319,18 @@ void svr_mailowner(
}
mailfrom = PBS_DEFAULT_MAIL;
}
-
+
/* Who does the mail go to? If mail-list, them; else owner */
-
*mailto = '\0';
if (pjob->ji_wattr[JOB_ATR_mailuser].at_flags & ATR_VFLAG_SET)
{
/* has mail user list, send to them rather than owner */
-
pas = pjob->ji_wattr[JOB_ATR_mailuser].at_val.at_arst;
if (pas != NULL)
{
+ int i;
for (i = 0;i < pas->as_usedptr;i++)
{
if ((strlen(mailto) + strlen(pas->as_string[i]) + 2) < sizeof(mailto))
@@ -270,7 +344,6 @@ void svr_mailowner(
else
{
/* no mail user list, just send to owner */
-
if ((server.sv_attr[SRV_ATR_MailDomain].at_flags & ATR_VFLAG_SET) &&
(server.sv_attr[SRV_ATR_MailDomain].at_val.at_str != NULL))
{
@@ -316,135 +389,121 @@ void svr_mailowner(
}
}
- /* mail subject line formating statement */
-
- if ((server.sv_attr[SRV_ATR_MailSubjectFmt].at_flags & ATR_VFLAG_SET) &&
- (server.sv_attr[SRV_ATR_MailSubjectFmt].at_val.at_str != NULL))
- {
- subjectfmt = server.sv_attr[SRV_ATR_MailSubjectFmt].at_val.at_str;
- }
- else
- {
- subjectfmt = "PBS JOB %i";
- }
-
- /* mail body formating statement */
+ sendmail_args[numargs++] = (char *)SENDMAIL_CMD;
+ sendmail_args[numargs++] = (char *)"-f";
+ sendmail_args[numargs++] = (char *)mailfrom;
- if ((server.sv_attr[SRV_ATR_MailBodyFmt].at_flags & ATR_VFLAG_SET) &&
- (server.sv_attr[SRV_ATR_MailBodyFmt].at_val.at_str != NULL))
- {
- bodyfmt = server.sv_attr[SRV_ATR_MailBodyFmt].at_val.at_str;
- }
- else
+ /* Add the e-mail addresses to the command line */
+ mailptr = strdup(mailto);
+ sendmail_args[numargs++] = mailptr;
+ for (counter=0; counter < (int)strlen(mailptr); counter++)
{
- bodyfmt = strcpy(bodyfmtbuf, "PBS Job Id: %i\n"
- "Job Name: %j\n");
- if (pjob->ji_wattr[JOB_ATR_exec_host].at_flags & ATR_VFLAG_SET)
- {
- strcat(bodyfmt, "Exec host: %h\n");
- }
-
- strcat(bodyfmt, "%m\n");
-
- if (text != NULL)
+ if (mailptr[counter] == ',')
{
- strcat(bodyfmt, "%d\n");
+ mailptr[counter] = '\0';
+ sendmail_args[numargs++] = mailptr + counter + 1;
+ if (numargs >= 99)
+ break;
}
}
- /* setup sendmail command line with -f from_whom */
-
- i = strlen(SENDMAIL_CMD) + strlen(mailfrom) + strlen(mailto) + 6;
- if ((cmdbuf = malloc(i)) == NULL)
+ sendmail_args[numargs] = NULL;
+
+ /* Create a pipe to talk to the sendmail process we are about to fork */
+ if (pipe(pipes) == -1)
{
- char tmpBuf[LOG_BUF_SIZE];
-
- snprintf(tmpBuf,sizeof(tmpBuf),
- "Unable to popen() command '%s' for writing: '%s' (error %d)\n",
- cmdbuf,
- strerror(errno),
- errno);
+ snprintf(tmpBuf, sizeof(tmpBuf), "Unable to pipes for sending e-mail\n");
log_event(PBSEVENT_ERROR | PBSEVENT_ADMIN | PBSEVENT_JOB,
PBS_EVENTCLASS_JOB,
pjob->ji_qs.ji_jobid,
tmpBuf);
- exit(1);
+ free(mailptr);
+ exit(-1);
}
- sprintf(cmdbuf, "%s -f %s %s",
-
- SENDMAIL_CMD,
- mailfrom,
- mailto);
-
- outmail = (FILE *)popen(cmdbuf, "w");
-
- if (outmail == NULL)
+ if ((pid=fork()) == -1)
{
- char tmpBuf[LOG_BUF_SIZE];
-
- snprintf(tmpBuf,sizeof(tmpBuf),
- "Unable to popen() command '%s' for writing: '%s' (error %d)\n",
- cmdbuf,
- strerror(errno),
- errno);
+ snprintf(tmpBuf, sizeof(tmpBuf), "Unable to fork for sending e-mail\n");
log_event(PBSEVENT_ERROR | PBSEVENT_ADMIN | PBSEVENT_JOB,
PBS_EVENTCLASS_JOB,
pjob->ji_qs.ji_jobid,
tmpBuf);
+ free(mailptr);
+ close(pipes[0]);
+ close(pipes[1]);
+ exit(-1);
+ }
+ else if (pid == 0)
+ {
+ /* CHILD */
+
+ /* Make stdin the read end of the pipe */
+ dup2(pipes[0], 0);
+
+ /* Close the rest of the open file descriptors */
+ int numfds = sysconf(_SC_OPEN_MAX);
+ while (--numfds > 0)
+ close(numfds);
+
+ execv(SENDMAIL_CMD, sendmail_args);
+ /* This never returns, but if the execv fails the child should exit */
exit(1);
}
+ else
+ {
+ /* This is the parent */
- /* Pipe in mail headers: To: and Subject: */
+ /* Close the read end of the pipe */
+ close(pipes[0]);
- fprintf(outmail, "To: %s\n",
- mailto);
+ /* Write the body to the pipe */
+ stream = fdopen(pipes[1], "w");
+ write_email(stream, pjob, mailto, mailpoint, text);
- fprintf(outmail, "Subject: ");
- svr_format_job(outmail, pjob, subjectfmt, mailpoint, text);
- fprintf(outmail, "\n");
+ fflush(stream);
- /* Set "Precedence: bulk" to avoid vacation messages, etc */
+ /* Close and wait for the command to finish */
+ if (fclose(stream) != 0)
+ {
+ snprintf(tmpBuf,sizeof(tmpBuf),
+ "Piping mail body to sendmail closed: errno %d:%s\n",
+ errno, strerror(errno));
- fprintf(outmail, "Precedence: bulk\n\n");
+ log_event(PBSEVENT_ERROR | PBSEVENT_ADMIN | PBSEVENT_JOB,
+ PBS_EVENTCLASS_JOB,
+ pjob->ji_qs.ji_jobid,
+ tmpBuf);
+ }
- /* Now pipe in the email body */
- svr_format_job(outmail, pjob, bodyfmt, mailpoint, text);
+ // we aren't going to block in order to find out whether or not sendmail worked
+ if ((waitpid(pid, &status, WNOHANG) != 0) &&
+ (status != 0))
+ {
+ snprintf(tmpBuf,sizeof(tmpBuf),
+ "Sendmail command returned %d. Mail may not have been sent\n",
+ status);
- errno = 0;
- if ((i = pclose(outmail)) != 0)
- {
- char tmpBuf[LOG_BUF_SIZE];
+ log_event(PBSEVENT_ERROR | PBSEVENT_ADMIN | PBSEVENT_JOB,
+ PBS_EVENTCLASS_JOB,
+ pjob->ji_qs.ji_jobid,
+ tmpBuf);
+ }
- snprintf(tmpBuf,sizeof(tmpBuf),
- "Email '%c' to %s failed: Child process '%s' %s %d (errno %d:%s)\n",
- mailpoint,
- mailto,
- cmdbuf,
- ((WIFEXITED(i)) ? ("returned") : ((WIFSIGNALED(i)) ? ("killed by signal") : ("croaked"))),
- ((WIFEXITED(i)) ? (WEXITSTATUS(i)) : ((WIFSIGNALED(i)) ? (WTERMSIG(i)) : (i))),
- errno,
- strerror(errno));
- log_event(PBSEVENT_ERROR | PBSEVENT_ADMIN | PBSEVENT_JOB,
- PBS_EVENTCLASS_JOB,
- pjob->ji_qs.ji_jobid,
- tmpBuf);
- }
- else if (LOGLEVEL >= 4)
- {
- log_event(PBSEVENT_ERROR | PBSEVENT_ADMIN | PBSEVENT_JOB,
- PBS_EVENTCLASS_JOB,
- pjob->ji_qs.ji_jobid,
- "Email sent successfully\n");
+ // don't leave zombies
+ while (waitpid(-1, &status, WNOHANG) != 0)
+ {
+ // zombie reaped, NO-OP
+ }
+
+ free(mailptr);
+ exit(0);
}
+
+ /* NOT REACHED */
exit(0);
-
- /*NOTREACHED*/
-
- return;
} /* END svr_mailowner() */
/* END svr_mail.c */

View File

@ -1,84 +0,0 @@
This README describes how to get the most basic working
torque service on a single host.
To setup a basic single-node localhost-only batch system, install the
torque-server, torque-mom, and torque-scheduler packages, and do something like
this:
0) If torque is built with munge support then this
must be enabled first on all nodes. The munge
package should allready be installed.
Create a munge key with
/usr/sbin/create-munge-key
Copy resulting key /etc/munge/munge.key to
all torque nodes in your cluster including
pbs_server, pbs_mom and client (qstat,qsub) nodes.
1) Get your full hostname with
# /bin/hostname --long
e.g myhost.example.org
2) Edit /etc/torque/server_name
to contain the single line
myhost.example.org
3) Edit /etc/torque/mom/config
to contain the single line
$pbsserver myhost.example.org
4) Create a torque serverdb file.
# /usr/sbin/pbs_server -D -t create
Warning this will remove any existing serverdb
file located at /var/lib/torque/server_priv/serverdb
You will have to Ctrl^C the pbs_server command, it will
only take a moment to create this file.
5) Start the pbs_server and configure it.
service pbs_server start
# qmgr -c "s s scheduling=true"
# qmgr -c "c q batch queue_type=execution"
# qmgr -c "s q batch started=true"
# qmgr -c "s q batch enabled=true"
# qmgr -c "s q batch resources_default.nodes=1"
# qmgr -c "s q batch resources_default.walltime=3600"
# qmgr -c "s s default_queue=batch"
6) Add one batch worker to your pbs_server.
# qmgr -c "c n myhost.example.org"
7) Start the pbs_mom and pbs_sched deamons.
# service pbs_mom start
# service pbs_sched start
8) Use chkconfig to start the services at boot time.
# /sbin/chkconfig pbs_mom on
# /sbin/chkconfig pbs_server on
# /sbin/chkconfig pbs_sched on
# /sbin/chkconfig munge on
9) Submit a test job.
As a user not as root run the following
$ qsub <<EOF
hostname
echo "Hi I am a batch job running in torque"
EOF
10 ) Monitor the state of that job with qstat.
In case of problems first of all look in /var/log/torque

2
config
View File

@ -1,2 +0,0 @@
# Configuration for pbs_mom.
$pbsserver localhost

1
dead.package Normal file
View File

@ -0,0 +1 @@
torque fails to build from source: https://bugzilla.redhat.com/show_bug.cgi?id=1676147

View File

@ -1 +0,0 @@
nodes=0

View File

@ -1,103 +0,0 @@
#! /bin/sh
package="pbs"
version="2.3.8"
prefix="/usr"
exec_prefix="/usr"
bindir="/usr/bin"
sbindir="/usr/sbin"
libexecdir="/usr/libexec"
datadir="/usr/share"
sysconfdir="/etc"
sharedstatedir="/usr/com"
localstatedir="/var"
infodir="/usr/share/info"
mandir="/usr/share/man"
includedir="/usr/include/torque"
libs="-ltorque"
if test "$#" -eq 0; then
cat <<EOF
Usage: $package-config OPTIONS
Options:
--prefix=DIR) : \$prefix
--package) : \$package
--version) : \$version
--cflags) : -I\$includedir
--libs) : \$libs
--help) print all the options (not just these)
EOF
fi
o=""
h=""
for i in "$@"; do
case $i in
--prefix=*) prefix=`echo $i | sed -e "s/--prefix=//"` ;;
--prefix) o="$o $prefix" ;;
--package) o="$o $package" ;;
--version) o="$o $version" ;;
--cflags) if test "_$includedir" != "_/usr/include"
then o="$o -I$includedir" ; fi
;;
--libs) o="$o $libs" ;;
--exec_prefix|--eprefix) o="$o $exec_prefix" ;;
--bindir) o="$o $bindir" ;;
--sbindir) o="$o $sbindir" ;;
--libexecdir) o="$o $libexecdir" ;;
--datadir) o="$o $datadir" ;;
--datainc) o="$o -I$datadir" ;;
--datalib) o="$o -L$datadir" ;;
--sysconfdir) o="$o $sysconfdir" ;;
--sharedstatedir) o="$o $sharedstatedir" ;;
--localstatedir) o="$o $localstatedir" ;;
--infodir) o="$o $infodir" ;;
--mandir) o="$o $mandir" ;;
--includedir) o="$o $includedir" ;;
--data) o="$o -I$datadir/$package" ;;
--pkgdatadir) o="$o $datadir/$package" ;;
--pkgdatainc) o="$o -I$datadir/$package" ;;
--pkgdatalib) o="$o -L$datadir/$package" ;;
--pkglibinc) o="$o -I$libinc/$package" ;;
--pkglibadd) o="$o -L$libadd/$package" ;;
--pkgincludedir) o="$o $includedir/$package" ;;
--help) h="1" ;;
-?//*|-?/*//*|-?./*//*|//*|/*//*|./*//*)
v=`echo $i | sed -e s://:\$:g`
v=`eval "echo $v"`
o="$o $v" ;;
esac
done
o=`eval "echo $o"`
o=`eval "echo $o"`
eval "echo $o"
if test ! -z "$h" ; then
cat <<EOF
--prefix=xxx) (what is that for anyway?)
--prefix) \$prefix $prefix
--package) \$package $package
--version) \$version $version
--cflags) -I\$includedir unless it is /usr/include
--libs) -l\$PACKAGE \$LIBS
--exec_prefix) or...
--eprefix) \$exec_prefix $exec_prefix
--bindir) \$bindir $bindir
--sbindir) \$sbindir $sbindir
--libexecdir) \$libexecdir $libexecdir
--datadir) \$datadir $datadir
--sysconfdir) \$sysconfdir $sysconfdir
--sharedstatedir) \$sharedstatedir$sharedstatedir
--localstatedir) \$localstatedir $localstatedir
--infodir) \$infodir $infodir
--mandir) \$mandir $mandir
--data) -I\$datadir/\$package
--pkgdatadir) \$datadir/\$package
--pkgincludedir) \$includedir/\$package
--help) generated by ac_create_generic_config.m4
-I//varname and other inc-targets like --pkgdatainc supported
-L//varname and other lib-targets, e.g. --pkgdatalib or --libadd
EOF
fi

View File

@ -1,11 +0,0 @@
[Unit]
Description=pbs-mom
After=syslog.target network.target trqauthd.service
[Service]
Type=forking
ExecStart=/usr/sbin/pbs_mom
PIDFile=/var/lib/torque/mom_priv/mom.lock
[Install]
WantedBy=multi-user.target

View File

@ -1,11 +0,0 @@
[Unit]
Description=pbs-sched
After=syslog.target network.target trqauthd.service
[Service]
Type=forking
ExecStart=/usr/sbin/pbs_sched
PIDFile=/var/lib/torque/sched_priv/sched.lock
[Install]
WantedBy=multi-user.target

View File

@ -1,11 +0,0 @@
[Unit]
Description=pbs-server
After=syslog.target network.target trqauthd.service
[Service]
Type=forking
ExecStart=/usr/sbin/pbs_server
PIDFile=/var/lib/torque/server_priv/server.lock
[Install]
WantedBy=multi-user.target

View File

@ -1,2 +0,0 @@
3dd4348f54ba236ee7c208cc6b97f674 torque-4.2.8.tar.gz
541f58ab46166e86d7a468500be3fa4d torque-4.2.10.tar.gz

View File

@ -1,12 +0,0 @@
diff -uNr torque-2.5.7.ORIG/src/server/req_getcred.c torque-2.5.7/src/server/req_getcred.c
--- torque-2.5.7.ORIG/src/server/req_getcred.c 2011-12-03 19:05:46.670461225 +0100
+++ torque-2.5.7/src/server/req_getcred.c 2011-12-03 19:07:50.013609563 +0100
@@ -471,7 +471,7 @@
if(rc)
{
/* FAILED */
- req_reject(PBSE_SYSTEM, 0, preq, NULL, "munge failure");
+ /* req_reject(PBSE_SYSTEM, 0, preq, NULL, "munge failure"); */
return (PBSE_SYSTEM);
}

File diff suppressed because it is too large Load Diff

View File

@ -1,61 +0,0 @@
--- a/contrib/init.d/pbs_mom.in 2015-03-19 20:24:58.000000000 -0700
+++ b/contrib/init.d/pbs_mom.in 2016-02-20 18:46:26.058196405 -0800
@@ -13,11 +13,21 @@
SBIN_PATH=@sbindir@
PBS_DAEMON="$SBIN_PATH/pbs_mom"
PBS_HOME=@PBS_HOME@
+# this should be the integer port value
+PBS_PORT=""
if [ -f /etc/sysconfig/pbs_mom ];then
. /etc/sysconfig/pbs_mom
fi
+if [ -z "$PBS_PORT" ]; then
+ momctl_port_arg=""
+ pbs_mom_port_arg=""
+else
+ momctl_port_arg="$PBS_PORT"
+ pbs_mom_port_arg="-M $PBS_PORT"
+fi
+
if [ -z "$previous" ];then
# being run manually, don't disturb jobs
args="$args -p"
@@ -41,7 +51,7 @@
fi
retval=1
while kill -0 $pid 2>/dev/null;do
- $SBIN_PATH/momctl -s
+ $SBIN_PATH/momctl -s $momctl_port_arg
retval=$?
sleep 1
done
@@ -58,7 +68,7 @@
[ $RET -eq 0 ] && echo -n "pbs_mom already running" && success && echo && exit 0
# ulimit -c unlimited # Uncomment this to preserve core files
- daemon $PBS_DAEMON $args -d $PBS_HOME
+ daemon $PBS_DAEMON $args $pbs_mom_port_arg -d $PBS_HOME
RET=$?
touch /var/lock/subsys/pbs_mom
echo
--- a/contrib/init.d/pbs_sched.in 2016-02-20 18:48:08.593799420 -0800
+++ b/contrib/init.d/pbs_sched.in 2016-02-20 18:48:54.455727300 -0800
@@ -11,6 +11,7 @@
PBS_DAEMON=@sbindir@/pbs_sched
PBS_HOME=@PBS_HOME@
export PBS_DAEMON PBS_HOME
+PBS_ARGS=""
if [ -f /etc/sysconfig/pbs_sched ];then
. /etc/sysconfig/pbs_sched
@@ -24,7 +25,7 @@
RET=$?
[ $RET -eq 0 ] && echo -n "pbs_sched already running" && success && echo && exit 0
- daemon $PBS_DAEMON -d $PBS_HOME
+ daemon $PBS_DAEMON -d $PBS_HOME $PBS_ARGS
RET=$?
[ $RET -eq 0 ] && touch /var/lock/subsys/pbs_sched
echo

View File

@ -1,29 +0,0 @@
From fb7c21c16423cecdbd8ac2429118305c26b82bb4 Mon Sep 17 00:00:00 2001
From: Justin Bronder <jsbronder@gmail.com>
Date: Sat, 1 Jun 2013 11:37:27 -0400
Subject: [PATCH] Libnet: remove unused header
Do not include <rpc/rpc.h> as it is unused. While this is normally
harmless, glibc is dropping support for rpc as of 2.14 [1] and ipv6 is
only supported in ti-rpc.
This fixes building on distros that have not manually patched rpc
support back into glibc.
1. http://sourceware.org/bugzilla/show_bug.cgi?id=12949
---
src/lib/Libnet/net_client.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/src/lib/Libnet/net_client.c b/src/lib/Libnet/net_client.c
index d8e51312f8..04c3ba0d78 100644
--- a/src/lib/Libnet/net_client.c
+++ b/src/lib/Libnet/net_client.c
@@ -80,7 +80,6 @@
#include <sys/types.h>
#include <sys/socket.h>
-#include <rpc/rpc.h>
#include <netinet/in.h>
#include <stdio.h>
#include <errno.h>

View File

@ -1,173 +0,0 @@
diff -uNr torque-2.5.5.ORIG/src/lib/Libnet/get_hostaddr.c torque-2.5.5/src/lib/Libnet/get_hostaddr.c
--- torque-2.5.5.ORIG/src/lib/Libnet/get_hostaddr.c 2011-06-08 18:40:00.251913002 +0200
+++ torque-2.5.5/src/lib/Libnet/get_hostaddr.c 2011-06-08 18:41:06.651911946 +0200
@@ -147,7 +147,8 @@
if (hp == NULL)
{
- sprintf(log_buffer,"cannot resolve IP address for host '%s' herror=%d: %s",
+ snprintf(log_buffer, sizeof(log_buffer),
+ "cannot resolve IP address for host '%s' herror=%d: %s",
hostname,
h_errno,
hstrerror(h_errno));
diff -uNr torque-2.5.5.ORIG/src/server/req_quejob.c torque-2.5.5/src/server/req_quejob.c
--- torque-2.5.5.ORIG/src/server/req_quejob.c 2011-06-08 18:40:00.315913002 +0200
+++ torque-2.5.5/src/server/req_quejob.c 2011-06-08 18:49:36.449912391 +0200
@@ -1053,17 +1053,19 @@
{
if (errno == 0)
{
- sprintf(log_buffer, "job %s in unexpected state '%s'",
- pj->ji_qs.ji_jobid,
- PJobSubState[pj->ji_qs.ji_substate]);
+ snprintf(log_buffer, sizeof(log_buffer),
+ "job %s in unexpected state '%s'",
+ pj->ji_qs.ji_jobid,
+ PJobSubState[pj->ji_qs.ji_substate]);
}
else
{
- sprintf(log_buffer, "job %s in unexpected state '%s' (errno=%d - %s)",
- pj->ji_qs.ji_jobid,
- PJobSubState[pj->ji_qs.ji_substate],
- errno,
- strerror(errno));
+ snprintf(log_buffer, sizeof(log_buffer),
+ "job %s in unexpected state '%s' (errno=%d - %s)",
+ pj->ji_qs.ji_jobid,
+ PJobSubState[pj->ji_qs.ji_substate],
+ errno,
+ strerror(errno));
}
log_err(errno, id, log_buffer);
@@ -1264,9 +1266,10 @@
if (LOGLEVEL >= 6)
{
- sprintf(log_buffer, "successfully moved file '%s' for job '%s'",
- namebuf,
- preq->rq_ind.rq_jobfile.rq_jobid);
+ snprintf(log_buffer, sizeof(log_buffer),
+ "successfully moved file '%s' for job '%s'",
+ namebuf,
+ preq->rq_ind.rq_jobfile.rq_jobid);
log_record(
PBSEVENT_JOB,
@@ -1382,9 +1385,11 @@
{
char tmpLine[1024];
- sprintf(tmpLine, "cannot save job - errno=%d - %s",
- errno,
- strerror(errno));
+ snprintf(tmpLine, sizeof(tmpLine),
+ "cannot save job - errno=%d - %s",
+ errno,
+ strerror(errno));
+
log_err(errno, id, tmpLine);
@@ -1408,9 +1413,11 @@
{
/* reply failed, purge the job and close the connection */
- sprintf(log_buffer, "cannot report jobid - errno=%d - %s",
- errno,
- strerror(errno));
+ snprintf(log_buffer, sizeof(log_buffer),
+ "cannot report jobid - errno=%d - %s",
+ errno,
+ strerror(errno));
+
log_err(errno, id, log_buffer);
@@ -1700,11 +1707,12 @@
/* need to format message first, before request goes away */
- sprintf(log_buffer, msg_jobnew,
- preq->rq_user, preq->rq_host,
- pj->ji_wattr[(int)JOB_ATR_job_owner].at_val.at_str,
- pj->ji_wattr[(int)JOB_ATR_jobname].at_val.at_str,
- pj->ji_qhdr->qu_qs.qu_name);
+ snprintf(log_buffer, sizeof(log_buffer),
+ msg_jobnew,
+ preq->rq_user, preq->rq_host,
+ pj->ji_wattr[JOB_ATR_job_owner].at_val.at_str,
+ pj->ji_wattr[JOB_ATR_jobname].at_val.at_str,
+ pj->ji_qhdr->qu_qs.qu_name);
/* acknowledge the request with the job id */
@@ -1739,8 +1747,10 @@
{
if (LOGLEVEL >= 7)
{
- sprintf(log_buffer, "Trying to AUTORUN job %s",
- pj->ji_qs.ji_jobid);
+ snprintf(log_buffer, sizeof(log_buffer),
+ "Trying to AUTORUN job %s",
+ pj->ji_qs.ji_jobid);
+
log_record(
PBSEVENT_JOB,
PBS_EVENTCLASS_JOB,
@@ -1861,7 +1871,7 @@
if (!user_account_read_user(arguser))
{
- sprintf(log_buffer, "user_account_verify(%s, %s) -> USER NOT FOUND",
+ snprintf(log_buffer,sizeof(log_buffer), "user_account_verify(%s, %s) -> USER NOT FOUND",
arguser,
argaccount);
@@ -1872,7 +1882,7 @@
{
if (strcmp(argaccount, UserAcct.ActAdr[i]) == 0)
{
- sprintf(log_buffer, "user_account_verify(%s, %s) -> SUCCESS",
+ snprintf(log_buffer,sizeof(log_buffer), "user_account_verify(%s, %s) -> SUCCESS",
arguser,
argaccount);
@@ -1882,7 +1892,7 @@
}
} /* END for (i) */
- sprintf(log_buffer, "user_account_verify(%s, %s) -> FAILED",
+ snprintf(log_buffer, sizeof(log_buffer) "user_account_verify(%s, %s) -> FAILED",
arguser,
argaccount);
@@ -1909,7 +1919,7 @@
if (!user_account_read_user(arguser))
{
- sprintf(log_buffer, "user_account_default(%s) = USER NOT FOUND",
+ snprintf(log_buffer,sizeof(log_buffer), "user_account_default(%s) = USER NOT FOUND",
arguser);
goto user_account_default_done;
@@ -1917,7 +1927,7 @@
if (UserAcct.ActCnt < 1)
{
- sprintf(log_buffer, "user_account_default(%s) = NO PROJECT FOUND",
+ snprintf(log_buffer, sizeof(log_buffer), "user_account_default(%s) = NO PROJECT FOUND",
arguser);
goto user_account_default_done;
@@ -1925,7 +1935,7 @@
rc = UserAcct.ActAdr[0];
- sprintf(log_buffer, "user_account_default(%s) = %s",
+ snprintf(log_buffer, sizeof(log_buffer), "user_account_default(%s) = %s",
arguser,
rc);

View File

@ -1,42 +0,0 @@
diff -uNr torque-2.5.2.ORIG/contrib/init.d/pbs_server torque-2.5.2/contrib/init.d/pbs_server
--- torque-2.5.2.ORIG/contrib/init.d/pbs_server 2010-10-14 22:16:32.978386147 +0200
+++ torque-2.5.2/contrib/init.d/pbs_server 2010-10-14 23:01:59.911917744 +0200
@@ -25,11 +25,29 @@
then
daemon $PBS_DAEMON -d $PBS_HOME
else
+ echo -n "use \"service pbs_server create\"" && failure && echo && exit 5
+ fi
+ RET=$?
+ [ $RET -eq 0 ] && touch /var/lock/subsys/pbs_server
+ echo
+ ;;
+ create)
+ echo -n "Creating Torque Server Database:... "
+ if [ -r $PBS_HOME/server_priv/serverdb ]
+ then
+ echo -n "serverdb file allready exists?" && failure && echo && exit 5
+ else
daemon $PBS_DAEMON -t create -d $PBS_HOME
fi
RET=$?
[ $RET -eq 0 ] && touch /var/lock/subsys/pbs_server
echo
+ sleep 3
+ echo -n "Shutting down TORQUE Server: "
+ killproc pbs_server
+ RET=$?
+ rm -f /var/lock/subsys/pbs_server
+ echo
;;
stop)
echo -n "Shutting down TORQUE Server: "
@@ -53,7 +71,7 @@
echo
;;
*)
- echo "Usage: pbs_server {start|stop|restart|status|reload}"
+ echo "Usage: pbs_server {start|stop|restart|status|reload|create}"
exit 1
esac
exit $RET

View File

@ -1,109 +0,0 @@
*** process_request.c.orig 2011-11-08 14:20:50.000000000 +0100
--- process_request.c 2011-11-08 17:15:21.000000000 +0100
***************
*** 539,564 ****
if (ENABLE_TRUSTED_AUTH == TRUE )
rc = 0; /* bypass the authentication of the user--trust the client completely */
! else if(munge_on)
{
! /* If munge_on is true we will validate the connection now */
! if ( request->rq_type == PBS_BATCH_AltAuthenUser)
{
! rc = req_altauthenuser(request);
! if (rc == PBSE_NONE)
{
! conn_credent[sfds].timestamp = time_now;
! svr_conn[sfds].cn_authen = PBS_NET_CONN_AUTHENTICATED;
}
return;
}
else
! {
! rc = authenticate_user(request, &conn_credent[sfds]);
! }
}
- else if (svr_conn[sfds].cn_authen != PBS_NET_CONN_AUTHENTICATED)
- rc = PBSE_BADCRED;
else
rc = authenticate_user(request, &conn_credent[sfds]);
--- 539,562 ----
if (ENABLE_TRUSTED_AUTH == TRUE )
rc = 0; /* bypass the authentication of the user--trust the client completely */
! else if (svr_conn[sfds].cn_authen != PBS_NET_CONN_AUTHENTICATED)
{
! if (munge_on && request->rq_type == PBS_BATCH_AltAuthenUser)
{
! /* If munge_on is true do the validation request now */
! if (request->rq_ind.rq_authen.rq_port != svr_conn[sfds].cn_port)
! {
! req_reject(PBSE_IVALREQ, 0, request, NULL, "Unexpected request to authenticate an alternate connection");
! }
! else
{
! req_altauthenuser(request);
}
return;
}
else
! rc = PBSE_BADCRED;
}
else
rc = authenticate_user(request, &conn_credent[sfds]);
***************
*** 1032,1038 ****
break;
case PBS_BATCH_AltAuthenUser:
!
break;
case PBS_BATCH_JobObit:
--- 1030,1036 ----
break;
case PBS_BATCH_AltAuthenUser:
! req_reject(PBSE_IVALREQ, 0, request, NULL, "Unexpected request to authenticate at this point");
break;
case PBS_BATCH_JobObit:
*** req_getcred.c.orig 2011-11-08 17:27:36.000000000 +0100
--- req_getcred.c 2011-11-08 17:20:18.000000000 +0100
***************
*** 365,371 ****
/* Something went wrong. We will have to depend on the parent
to let everyone know */
close(fd_pipe[1]);
! exit(0);
}
--- 365,371 ----
/* Something went wrong. We will have to depend on the parent
to let everyone know */
close(fd_pipe[1]);
! _exit(0);
}
***************
*** 453,459 ****
for (s = 0;s < PBS_NET_MAX_CONNECTIONS;++s)
{
! if (preq->rq_ind.rq_authen.rq_port != svr_conn[s].cn_port)
{
continue;
}
--- 453,460 ----
for (s = 0;s < PBS_NET_MAX_CONNECTIONS;++s)
{
! if (preq->rq_ind.rq_authen.rq_port != svr_conn[s].cn_port ||
! svr_conn[preq->rq_conn].cn_addr != svr_conn[s].cn_addr)
{
continue;
}

View File

@ -1,94 +0,0 @@
Index: branches/2.5-fixes/src/include/batch_request.h
===================================================================
--- branches/2.5-fixes/src/include/batch_request.h (revision 5100)
+++ branches/2.5-fixes/src/include/batch_request.h (revision 5101)
@@ -404,7 +404,7 @@
#ifndef PBS_MOM
extern void req_authenuser (struct batch_request *req);
-extern void req_altauthenuser (struct batch_request *req);
+extern int req_altauthenuser (struct batch_request *req);
extern void req_connect (struct batch_request *req);
extern void req_locatejob (struct batch_request *req);
extern void req_manager (struct batch_request *req);
Index: branches/2.5-fixes/src/server/req_getcred.c
===================================================================
--- branches/2.5-fixes/src/server/req_getcred.c (revision 5100)
+++ branches/2.5-fixes/src/server/req_getcred.c (revision 5101)
@@ -436,7 +436,7 @@
* utility
*
*/
-void req_altauthenuser(
+int req_altauthenuser(
struct batch_request *preq) /* I */
@@ -462,7 +462,7 @@
if(s >= PBS_NET_MAX_CONNECTIONS)
{
req_reject(PBSE_BADCRED, 0, preq, NULL, "cannot authenticate user");
- return;
+ return (PBSE_BADCRED);
}
@@ -470,7 +470,8 @@
if(rc)
{
/* FAILED */
- return;
+ req_reject(PBSE_SYSTEM, 0, preq, NULL, "munge failure");
+ return (PBSE_SYSTEM);
}
/* SUCCESS */
@@ -482,7 +483,7 @@
svr_conn[s].cn_authen = PBS_NET_CONN_AUTHENTICATED;
reply_ack(preq);
- return;
+ return (PBSE_NONE);
} /* END req_altauthenuser() */
Index: branches/2.5-fixes/src/server/process_request.c
===================================================================
--- branches/2.5-fixes/src/server/process_request.c (revision 5100)
+++ branches/2.5-fixes/src/server/process_request.c (revision 5101)
@@ -541,10 +541,21 @@
rc = 0; /* bypass the authentication of the user--trust the client completely */
else if(munge_on)
{
- /* If munge_on is true we will validate the connection later */
- conn_credent[sfds].timestamp = time_now;
- svr_conn[sfds].cn_authen = PBS_NET_CONN_AUTHENTICATED;
- rc = 0;
+ /* If munge_on is true we will validate the connection now */
+ if ( request->rq_type == PBS_BATCH_AltAuthenUser)
+ {
+ rc = req_altauthenuser(request);
+ if (rc == PBSE_NONE)
+ {
+ conn_credent[sfds].timestamp = time_now;
+ svr_conn[sfds].cn_authen = PBS_NET_CONN_AUTHENTICATED;
+ }
+ return;
+ }
+ else
+ {
+ rc = authenticate_user(request, &conn_credent[sfds]);
+ }
}
else if (svr_conn[sfds].cn_authen != PBS_NET_CONN_AUTHENTICATED)
rc = PBSE_BADCRED;
@@ -1021,9 +1032,6 @@
break;
case PBS_BATCH_AltAuthenUser:
- /* Use given authentication method to determine
- if user is valid */
- req_altauthenuser(request);
break;

View File

@ -1,19 +0,0 @@
diff -uNr torque-3.0.2.ORIG/contrib/init.d/pbs_server torque-3.0.2/contrib/init.d/pbs_server
--- torque-3.0.2.ORIG/contrib/init.d/pbs_server 2011-10-09 00:09:29.026651535 +0200
+++ torque-3.0.2/contrib/init.d/pbs_server 2011-10-09 00:12:05.012653474 +0200
@@ -14,13 +14,11 @@
echo "Configuration already exists. Please remove $PBS_SERVERDB to create a new one."
exit 1
fi
-
$PBS_DAEMON -d $PBS_HOME -t create &
- while [ ! -r $PBS_SERVERDB ]; do
- sleep 1
- done
+ sleep 5
killproc pbs_server
RET=$?
+
}
start() {

View File

@ -1,25 +0,0 @@
From 12a8d7dde1d07aed670f0dd50b317b256daaa991 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ha=C3=AFkel=20Gu=C3=A9mar?= <hguemar@fedoraproject.org>
Date: Sun, 12 Jan 2014 11:42:32 +0100
Subject: [PATCH] munge size fix
---
src/include/libpbs.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/include/libpbs.h b/src/include/libpbs.h
index 6d32c8b..06b1bec 100644
--- a/src/include/libpbs.h
+++ b/src/include/libpbs.h
@@ -121,7 +121,7 @@
#define EOF -1
#endif
-#define MUNGE_SIZE 256 /* I do not know what the proper size of this should be. My
+#define MUNGE_SIZE 1024 /* I do not know what the proper size of this should be. My
testing with munge shows it creates a string of 128 bytes */
--
1.8.4.2

View File

@ -1,124 +0,0 @@
+ e - Added a new function DIS_tcp_close to the the code. This takes care of a problem
+ where TORQUE memory keeps growing because the read and write buffers associated
+ with each tcparray entry would grow to accommodate incoming and outgoing data
+ but would not shrink.
Index: src/include/dis.h
===================================================================
--- src/include/dis.h (revision 5257)
+++ src/include/dis.h (revision 5258)
@@ -238,13 +238,15 @@
/* the following routines set/control DIS over tcp */
-extern void DIS_tcp_reset (int fd, int rw);
-extern void DIS_tcp_setup (int fd);
-extern int DIS_tcp_wflush (int fd);
-extern void DIS_tcp_settimeout (long timeout);
-extern int DIS_tcp_istimeout (int fd);
+void DIS_tcp_reset (int fd, int rw);
+void DIS_tcp_setup (int fd);
+int DIS_tcp_wflush (int fd);
+void DIS_tcp_settimeout (long timeout);
+int DIS_tcp_istimeout (int fd);
+void DIS_tcp_close (int fd);
+
extern int PConnTimeout(int);
/* NOTE: increase THE_BUF_SIZE to 131072 for systems > 5k nodes */
Index: src/lib/Libattr/attr_fn_arst.c
===================================================================
--- src/lib/Libattr/attr_fn_arst.c (revision 5257)
+++ src/lib/Libattr/attr_fn_arst.c (revision 5258)
@@ -186,13 +186,14 @@
bksize = (ns - 1) * sizeof(char *) + sizeof(struct array_strings);
- if ((stp = (struct array_strings *)malloc(bksize)) == NULL)
+ if (( patr->at_val.at_arst = (struct array_strings *)malloc(bksize)) == NULL)
{
/* FAILURE */
return(PBSE_SYSTEM);
}
+ stp = patr->at_val.at_arst;
memset(stp, 0, bksize);
stp->as_npointers = ns;
@@ -238,7 +239,7 @@
patr->at_flags |= ATR_VFLAG_SET | ATR_VFLAG_MODIFY;
- patr->at_val.at_arst = stp;
+/* patr->at_val.at_arst = stp;*/
free(tmpval);
Index: src/lib/Libifl/tcp_dis.c
===================================================================
--- src/lib/Libifl/tcp_dis.c (revision 5257)
+++ src/lib/Libifl/tcp_dis.c (revision 5258)
@@ -790,9 +790,30 @@
return;
}
+void DIS_tcp_close(
+ int fd)
+ {
+ struct tcp_chan *tcp;
+ tcp = tcparray[fd];
+ if(tcp != NULL)
+ {
+ if(tcp->readbuf.tdis_thebuf != NULL)
+ free(tcp->readbuf.tdis_thebuf);
+ if(tcp->writebuf.tdis_thebuf != NULL)
+ free(tcp->writebuf.tdis_thebuf);
+
+ free(tcp);
+ tcparray[fd] = NULL;
+ }
+
+ return;
+ }
+
+
+
/*
* DIS_tcp_setup - setup supports routines for dis, "data is strings", to
* use tcp stream I/O. Also initializes an array of pointers to
Index: src/lib/Libnet/net_server.c
===================================================================
--- src/lib/Libnet/net_server.c (revision 5257)
+++ src/lib/Libnet/net_server.c (revision 5258)
@@ -114,6 +114,7 @@
#include "server_limits.h"
#include "net_connect.h"
#include "log.h"
+#include "dis.h" /* DIS_tcp_close */
extern int LOGLEVEL;
@@ -718,6 +719,7 @@
int sd) /* I */
{
+
if ((sd < 0) || (max_connection <= sd))
{
return;
@@ -757,6 +759,9 @@
num_connections--;
+ DIS_tcp_close(sd);
+
+
return;
} /* END close_conn() */

View File

@ -1,27 +0,0 @@
Index: src/lib/Libifl/tcp_dis.c
===================================================================
--- src/lib/Libifl/tcp_dis.c (revision 5269)
+++ src/lib/Libifl/tcp_dis.c (revision 5270)
@@ -797,12 +797,19 @@
{
struct tcp_chan *tcp;
+ /* On startup tcparray may not yet be initialized. check it */
+ if (tcparray == NULL)
+ return;
+
+ if (fd > tcparraymax)
+ return;
+
tcp = tcparray[fd];
- if(tcp != NULL)
+ if (tcp != NULL)
{
- if(tcp->readbuf.tdis_thebuf != NULL)
+ if (tcp->readbuf.tdis_thebuf != NULL)
free(tcp->readbuf.tdis_thebuf);
- if(tcp->writebuf.tdis_thebuf != NULL)
+ if (tcp->writebuf.tdis_thebuf != NULL)
free(tcp->writebuf.tdis_thebuf);
free(tcp);

File diff suppressed because it is too large Load Diff

View File

@ -1,10 +0,0 @@
[Unit]
Description=trqauthd
After=syslog.target network.target
[Service]
Type=forking
ExecStart=/usr/sbin/trqauthd
[Install]
WantedBy=multi-user.target

View File

@ -1,11 +0,0 @@
[Desktop Entry]
Encoding=UTF-8
Name=xPBS
GenericName=PBS/TORQUE client
Comment=View job status and submit jobs
Exec=xpbs
Icon=xpbs.png
Terminal=false
Type=Application
Categories=Education;Science;ComputerScience;ParallelComputing;
Version=1.0

BIN
xpbs.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

View File

@ -1,11 +0,0 @@
[Desktop Entry]
Encoding=UTF-8
Name=xPBSMon
GenericName=PBS/TORQUE cluster monitor
Comment=View node status
Exec=xpbsmon
Icon=xpbsmon.png
Terminal=false
Type=Application
Categories=Education;Science;ComputerScience;ParallelComputing;
Version=1.0

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB