[Git][NTPsec/ntpsec][master] Added ntpsnmpd in prototype state.
Ian Bruene
gitlab at mg.gitlab.com
Sun Oct 29 16:20:26 UTC 2017
Ian Bruene pushed to branch master at NTPsec / ntpsec
Commits:
ef798530 by Ian Bruene at 2017-10-29T11:17:58-05:00
Added ntpsnmpd in prototype state.
- - - - -
2 changed files:
- + ntpclients/ntpsnmpd
- wscript
Changes:
=====================================
ntpclients/ntpsnmpd
=====================================
--- /dev/null
+++ b/ntpclients/ntpsnmpd
@@ -0,0 +1,671 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from __future__ import print_function, division
+
+import sys
+import os
+import getopt
+import time
+import socket
+import select
+import subprocess
+
+try:
+ import ntp.util
+ import ntp.agentx
+ ax = ntp.agentx
+except ImportError as e:
+ sys.stderr.write(
+ "ntpq: can't find Python NTP library -- check PYTHONPATH.\n")
+ sys.stderr.write("%s\n" % e)
+ sys.exit(1)
+
+
+logfile = "ntpsnmpd.log"
+logfp = sys.stderr
+nofork = True # don't daemonize while still under construction
+debug = 0
+timeout = 5 # default timeout, what shuold this be?
+
+ntpRootOID = (1, 3, 6, 1, 2, 1, 197) # mib-2 . 197, aka: NTPv4-MIB
+
+
+class DataSource: # This may be broken up in future to be less NTP-specific
+ def __init__(self):
+ # This is defined as a dict tree because simpler, and avoids
+ # certain edge cases
+ # OIDs are relative from ntp root
+ # ntpEntNotifications
+ self.oidTree = {0: (None,
+ # ntpEntNotifModeChange
+ {1: (None, None),
+ # ntpEntNotifStratumChange
+ 2: (None, None),
+ # ntpEntNotifSyspeerChange
+ 3: (None, None),
+ # ntpEntNotifAddAssociation
+ 4: (None, None),
+ # ntpEntNotifRemoveAsociation
+ 5: (None, None),
+ # ntpEntNotifConfigChanged
+ 6: (None, None),
+ # ntpEntNotifLeapSecondAnnounced
+ 7: (None, None),
+ # ntpEntNotifHeartbeat
+ 8: (None, None)}),
+ # ntpSnmpMIBObjects
+ 1: (None,
+ # ntpEntInfo
+ {1: (None,
+ # ntpNetSoftwareName utf8str
+ {1: ((lambda oid:
+ self.cb_systemInfo(oid, "name")),
+ None),
+ # ntpEntSoftwareVersion utf8str
+ 2: ((lambda oid:
+ self.cb_systemInfo(oid, "version")),
+ None),
+ # ntpEntSoftwareVendor utf8str
+ 3: ((lambda oid:
+ self.cb_systemInfo(oid, "vendor")),
+ None),
+ # ntpEntSystemType utf8str
+ 4: ((lambda oid:
+ self.cb_systemInfo(oid, "system")),
+ None),
+ # ntpEntTimeResolution uint32
+ 5: (self.cb_timeResolution, None),
+ # ntpEntTimePrecision int32
+ 6: (self.cb_timePrecision, None),
+ # ntpEntTimeDistance DisplayString
+ 7: (self.cb_timeDistance, None)}),
+ # ntpEntStatus
+ 2: (None,
+ # ntpEntStatusCurrentMode INTEGER {...}
+ {1: (self.cb_statusCurrentMode, None),
+ # ntpEntStatusStratum NtpStratum
+ 2: (self.cb_statusStratum, None),
+ # ntpEntStatusActiveRefSourceId
+ # uint32 (0..99999)
+ 3: (self.cb_statusActiveRefSourceID, None),
+ # ntpEntStatusActiveRefSourceName utf8str
+ 4: (self.cb_statusActiveRefSourceName, None),
+ # ntpEntStatusActiveOffset DisplayString
+ 5: (self.cb_statusActiveOffset, None),
+ # ntpEntStatusNumberOfRefSources
+ # unit32 (0..99)
+ 6: (self.cb_statusNumRefSources, None),
+ # ntpEntStatusDispersion DisplayString
+ 7: (self.cb_statusDispersion, None),
+ # ntpEntStatusEntityUptime TimeTicks
+ 8: (self.cb_statusEntityUptime, None),
+ # ntpEntStatusDateTime NtpDateTime
+ 9: (self.cb_statusDateTime, None),
+ # ntpEntStatusLeapSecond NtpDateTime
+ 10: (self.cb_statusLeapSecond, None),
+ # ntpEntStatusLeapSecondDirection
+ # int32 (-1..1)
+ 11: (self.cb_statusLeapSecDirection, None),
+ # ntpEntStatusInPkts Counter32
+ 12: (self.cb_statusInPkts, None),
+ # ntpEntStatusOutPkts Counter32
+ 13: (self.cb_statusOutPkts, None),
+ # ntpEntStatusBadVersion Counter32
+ 14: (self.cb_statusBadVersion, None),
+ # ntpEntStatusProtocolError Counter32
+ 15: (self.cb_statusProtocolError, None),
+ # ntpEntStatusNotifications Counter32
+ 16: (self.cb_statusNotifications, None),
+ # ntpEntStatPktModeTable
+ # SEQUENCE of NtpEntStatPktModeEntry
+ 17: (None,
+ # ntpEntStatPktModeEntry SEQUENCE {...}
+ {1: (None,
+ # ntpEntStatPktMode INTEGER {...}
+ {1: (None, None),
+ # ntpEntStatPktSent Counter32
+ 2: (None, None),
+ # ntpEntStatPktRecived Counter32
+ 3: (None, None)})})}),
+ # ntpAssociation
+ 3: (None,
+ # ntpAssociationTable
+ # SEQUENCE of NtpAssociationEntry
+ {1: (None,
+ # ntpAssociationEntry SEQUENCE {...}
+ {1: (None,
+ # ntpAssocId uint32 (1..99999)
+ {1: (self.cb_assocID, None),
+ # ntpAssocName utf8str
+ 2: (self.cb_assocName, None),
+ # ntpAssocRefId DisplayString
+ 3: (self.cb_assocRefID, None),
+ # ntpAssocAddressType
+ # InetAddressType
+ 4: (self.cb_assocAddrType, None),
+ # ntpAssocAddress
+ # InetAddress SIZE (4|8|16|20)
+ 5: (self.cb_assocAddr, None),
+ # ntpAssocOffset DisplayString
+ 6: (self.cb_assocOffset, None),
+ # ntpAssocStratum NtpStratum
+ 7: (self.cb_assocStratum, None),
+ # ntpAssocStatusJitter DisplayString
+ 8: (self.cb_assocStatusJitter,
+ None),
+ # ntpAssocStatusDelay DisplayString
+ 9: (self.cb_assocStatusDelay, None),
+ # ntpAssocStatusDispersion
+ # DisplayString
+ 10: (self.cb_assocStatusDisp,
+ None)})}),
+ # ntpAssociationStatisticsTable
+ # SEQUENCE of ntpAssociationStatisticsEntry
+ 2: (None,
+ # ntpAssociationStatisticsEntry
+ # SEQUENCE {...}
+ {1: (None,
+ # ntpAssocStatInPkts Counter32
+ {1: (self.cb_assocStatInPkts, None),
+ # ntpAssocStatOutPkts Counter32
+ 2: (self.cb_assocStatOutPkts,
+ None),
+ # ntpAssocStatProtocolError
+ # Counter32
+ 3: (self.cb_assocStatProtoErr,
+ None)})})}),
+ # ntpEntControl
+ 4: (None,
+ # ntpEntHeartbeatInterval unit32
+ {1: (self.cb_entHeartbeatInterval, None),
+ # ntpEntNotifBits BITS {...}
+ 2: (self.cb_entNotifBits, None)}),
+ # ntpEntNotifObjects
+ 5: (None,
+ # ntpEntNotifMessage utf8str
+ {1: (self.cb_entNotifMessage, None)})}),
+ # ntpEntConformance
+ 2: (None,
+ # ntpEntCompliances
+ {1: (None,
+ # ntpEntNTPCompliance
+ {1: (None, None),
+ # ntpEntSNTPCompliance
+ 2: (None, None)}),
+ # ntpEntGroups
+ 2: (None,
+ # ntpEntObjectsGroup1 OBJECTS {...}
+ {1: (None, None),
+ # ntpEntObjectsGroup2 OBJECTS {...}
+ 2: (None, None),
+ # ntpEntNotifGroup NOTIFICATIONS {...}
+ 3: (None, None)})})}
+ self.oidList = ntp.agentx.mibTree2List(self.oidTree, ntpRootOID)
+
+ def getOID(self, oid, acceptNext=False):
+ "Get the requested OID, or the next lexographical OID"
+ for node in self.oidList:
+ if node[0] is None:
+ continue # skip over not yet implemented OIDs
+ if (node[1] == oid):
+ return node # (callback, oid)
+ elif (node[1] > oid) and (acceptNext is True):
+ return node
+ # Nothing in the list
+ return (None, None)
+
+ def getNextOID(self, oid):
+ for pos in range(len(self.oidList)):
+ callback, current = self.oidList[pos]
+ if callback is None:
+ continue # skip over not yet implemented OIDs
+ if current <= oid:
+ continue
+ else:
+ return self.oidList[pos]
+ # Nothing after the supplied oid
+ return (None, None)
+
+ def getOIDsInRange(self, oidrange, firstOnly=False):
+ oids = []
+ for node in self.oidList:
+ if node[0] is None: # No callback
+ continue # skip over not yet implemented OIDs
+ elif node[1] > oidrange.start: # Past the start, in the body
+ if (oidrange.end is not None) and (node[1] >= oidrange.end):
+ break # Past the end of a bounded range
+ else:
+ oids.append(node) # Found a match
+ elif (node[1].subids == oidrange.start.subids) and \
+ (oidrange.start.include is True):
+ oids.append(node) # Inclusive search and a match at the start
+ else:
+ pass
+ if (firstOnly is True) and (len(oids) > 0):
+ break
+ return oids
+
+ # Data retrevial callbacks start here
+ # comment divider lines represent not yet implemented callbacks
+
+ #########################
+
+ def cb_systemInfo(self, oid, category):
+ if category == "name": # The product name of the running NTP version
+ data = "NTPsec"
+ elif category == "version": # version string
+ data = ntp.util.stdversion()
+ elif category == "vendor": # vendor/author name
+ data = "Internet Civil Engineering Institute"
+ elif category == "system": # system / hardware info
+ proc = subprocess.Popen(["uname","-srm"], stdout=subprocess.PIPE)
+ data = proc.communicate()[0]
+ vb = ax.Varbind(ax.VALUE_OCTET_STR, oid, data)
+ return vb
+
+ def cb_timeResolution(self, oid): # DUMMY
+ # Uinteger32
+ return ax.Varbind(ax.VALUE_GAUGE32, oid, 42)
+
+ def cb_timePrecision(self, oid): # DUMMY
+ return ax.Varbind(ax.VALUE_INTEGER, oid, 23)
+
+ def cb_timeDistance(self, oid): # DUMMY
+ # Displaystring
+ return ax.Varbind(ax.VALUE_OCTET_STR, oid, "foo")
+
+ #############################
+
+ def cb_statusCurrentMode(self, oid): # DUMMY
+ # Range of integers
+ return ax.Varbind(ax.VALUE_INTEGER, oid, 15)
+
+ def cb_statusStratum(self, oid): # DUMMY
+ # NTPstratum
+ return ax.Varbind(ax.VALUE_GAUGE32, oid, 16)
+
+ def cb_statusActiveRefSourceID(self, oid): # DUMMY
+ # range of uint32
+ return ax.Varbind(ax.VALUE_GAUGE32, oid, 1024)
+
+ def cb_statusActiveRefSourceName(self, oid): # DUMMY
+ # utf8
+ return ax.Varbind(ax.VALUE_OCTET_STR, oid, "bar")
+
+ def cb_statusActiveOffset(self, oid): # DUMMY
+ # DisplayString
+ return ax.Varbind(ax.VALUE_OCTET_STR, oid, "baz")
+
+ def cb_statusNumRefSources(self, oid): # DUMMY
+ # range of uint32
+ return ax.Varbind(ax.VALUE_GAUGE32, oid, 50)
+
+ def cb_statusDispersion(self, oid): # DUMMY
+ # DisplayString
+ return ax.Varbind(ax.VALUE_OCTET_STR, oid, "quux")
+
+ def cb_statusEntityUptime(self, oid): # DUMMY
+ # TimeTicks
+ return ax.Varbind(ax.VALUE_TIME_TICKS, oid, 8)
+
+ def cb_statusDateTime(self, oid): # DUMMY
+ # NtpDateTime
+ return ax.Varbind(ax.VALUE_OCTET_STR, oid, "fred")
+
+ def cb_statusLeapSecond(self, oid): # DUMMY
+ # NtpDateTime
+ return ax.Varbind(ax.VALUE_OCTET_STR, oid, "blah")
+
+ def cb_statusLeapSecDirection(self, oid): # DUMMY
+ # range of int32
+ return ax.Varbind(ax.VALUE_INTEGER, oid, -1)
+
+ def cb_statusInPkts(self, oid): # DUMMY
+ return ax.Varbind(ax.VALUE_COUNTER32, oid, 100)
+
+ def cb_statusOutPkts(self, oid): # DUMMY
+ return ax.Varbind(ax.VALUE_COUNTER32, oid, 200)
+
+ def cb_statusBadVersion(self, oid): # DUMMY
+ return ax.Varbind(ax.VALUE_COUNTER32, oid, 300)
+
+ def cb_statusProtocolError(self, oid): # DUMMY
+ return ax.Varbind(ax.VALUE_COUNTER32, oid, 400)
+
+ def cb_statusNotifications(self, oid): # DUMMY
+ return ax.Varbind(ax.VALUE_COUNTER32, oid, 500)
+
+ ##############################
+
+ def cb_assocID(self, oid): # DUMMY
+ return ax.Varbind(ax.VALUE_GAUGE32, oid, 1)
+
+ def cb_assocName(self, oid): # DUMMY
+ return ax.Varbind(ax.VALUE_OCTET_STR, oid, "It")
+
+ def cb_assocRefID(self, oid): # DUMMY
+ # DisplayString
+ return ax.Varbind(ax.VALUE_OCTET_STR, oid, "says;")
+
+ def cb_assocAddrType(self, oid): # DUMMY
+ # InetAddressType (range of ints)
+ return ax.Varbind(ax.VALUE_INTEGER, oid, 3)
+
+ def cb_assocAddr(self, oid): # DUMMY
+ # InetAddress
+ return ax.Varbind(ax.VALUE_OCTET_STR, oid, "\x01\x02\x03\x04")
+
+ def cb_assocOffset(self, oid): # DUMMY
+ # DisplayString
+ return ax.Varbind(ax.VALUE_OCTET_STR, oid, "Would")
+
+ def cb_assocStratum(self, oid): # DUMMY
+ # NTPStratum
+ return ax.Varbind(ax.VALUE_GAUGE32, oid, 12)
+
+ def cb_assocStatusJitter(self, oid): # DUMMY
+ # DisplayString
+ return ax.Varbind(ax.VALUE_OCTET_STR, oid, "You")
+
+ def cb_assocStatusDelay(self, oid): # DUMMY
+ # DisplayString
+ return ax.Varbind(ax.VALUE_OCTET_STR, oid, "Kindly?")
+
+ def cb_assocStatusDisp(self, oid): # DUMMY
+ # DisplayString
+ return ax.Varbind(ax.VALUE_OCTET_STR, oid, "*thunk*")
+
+ def cb_assocStatInPkts(self, oid): # DUMMY
+ return ax.Varbind(ax.VALUE_COUNTER32, oid, 2)
+
+ def cb_assocStatOutPkts(self, oid): # DUMMY
+ return ax.Varbind(ax.VALUE_COUNTER32, oid, 4)
+
+ def cb_assocStatProtoErr(self, oid): # DUMMY
+ return ax.Varbind(ax.VALUE_COUNTER32, oid, 8)
+
+ #########################
+
+ def cb_entHeartbeatInterval(self, oid): # DUMMY
+ # uint32
+ return ax.Varbind(ax.VALUE_GAUGE32, oid, 16)
+
+ def cb_entNotifBits(self, oid): # DUMMY
+ # BITS
+ return ax.Varbind(ax.VALUE_OCTET_STR, oid, "\x10\x20")
+
+ ##########################
+
+ def cb_entNotifMessage(self, oid): # DUMMY
+ # utf8str
+ return ax.Varbind(ax.VALUE_OCTET_STR, oid, "jabber")
+
+ #########################
+
+
+def dolog(text, level):
+ if debug >= level:
+ logfp.write(text)
+
+
+def connect():
+ sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+ try:
+ sock.connect("/var/agentx/master")
+ except socket.error as msg:
+ dolog(repr(msg) + "\n", 2)
+ sys.exit(1)
+ return sock
+
+
+class PacketControl:
+ def __init__(self, sock, dbase, spinGap=0.001, timeout=5):
+ # take a pre-made socket instead of making our own so that
+ # PacketControl doesn't have to know or care about implementation
+ self.socket = sock
+ self.spinGap = spinGap # sleep() time on each loop
+ # indexed on: (session_id, transaction_id, packet_id)
+ # contains: (timeout, packet class)
+ self.packetLog = {} # Sent packets kept until response is received
+ self.loopCallback = None # called each loop in runforever mode
+ self.database = dbase # class for handling data requests
+ self.recievedData = "" # buffer for data from incomplete packets
+ self.recievedPackets = [] # use as FIFO
+ self.timeout = timeout # default 5s, arbitrary
+ self.sessionID = None # need this for all packets
+ # indexed on pdu code
+ self.pduHandlers = {ax.PDU_GET: self.handle_GetPDU,
+ ax.PDU_GET_NEXT: self.handle_GetNextPDU,
+ ax.PDU_GET_BULK: self.handle_GetBulkPDU}
+
+ def mainloop(self, runforever):
+ if runforever:
+ while True:
+ self._doloop()
+ if self.loopCallback is not None:
+ self.loopCallback()
+ time.sleep(self.spinGap)
+ else:
+ self._doloop()
+
+ def _doloop(self):
+ # loop body split out to seperate the one-shot/run-forever switches
+ # from the actual logic
+ self.packetEater()
+ while len(self.recievedPackets) > 0:
+ packet = self.recievedPackets.pop(0)
+ ptype = packet.pduType
+ if ptype in self.pduHandlers:
+ self.pduHandlers[ptype](packet)
+ else:
+ dolog("dropping packet type %i, not implemented\n" % ptype, 1)
+
+ def initNewSession(self):
+ dolog("init new session...\n", 1)
+ # We already have a connection, need to open a session.
+ openpkt = ntp.agentx.OpenPDU(True, 23, 0, 0, self.timeout, (),
+ "NTPsec SNMP subagent")
+ self.sendPacket(openpkt, False)
+ dolog("Sent open packet\n", 1)
+ response = self.waitForResponse(openpkt, True)
+ self.sessionID = response.sessionID
+ # Register the tree, just random crap for testing right now
+ fooregister = ntp.agentx.RegisterPDU(True, self.sessionID, 1, 1,
+ self.timeout, 1, ntpRootOID)
+ self.sendPacket(fooregister, False)
+ dolog("Sent register\n", 1)
+ response = self.waitForResponse(fooregister, True)
+
+ def waitForResponse(self, opkt, ignoreSID=False):
+ while True:
+ self.packetEater()
+ while len(self.recievedPackets) > 0:
+ packet = self.recievedPackets.pop(0)
+ dolog("Waiting, got packet: " + repr(packet) + "\n\n", 3)
+ # This will drop anything that is not the response
+ # but if this method is being called we don't care
+ if packet.__class__ != ntp.agentx.ResponsePDU:
+ continue
+ haveit = (opkt.transactionID == packet.transactionID) and \
+ (opkt.packetID == packet.packetID)
+ if ignoreSID is False:
+ haveit = haveit and (opkt.sessionID == packet.sessionID)
+ if haveit is True:
+ return packet
+ time.sleep(self.spinGap)
+
+ def packetEater(self):
+ self.pollSocket()
+ while True:
+ datalen = len(self.recievedData)
+ if datalen < 20:
+ return None # We don't even have a packet header, bail
+ try:
+ pkt, extraData = ntp.agentx.decode_packet(self.recievedData)
+ self.recievedData = extraData
+ self.recievedPackets.append(pkt)
+ dolog("\npacketEater got a full packet: %s\n" % repr(pkt), 3)
+ except IndexError:
+ return None # this happens if we don't have all of a packet
+
+ def sendPacket(self, packet, expectsReply):
+ encoded = packet.encode()
+ dolog("\nsending packet: %s\n%s \n" % (repr(packet), repr(encoded)), 4)
+ self.socket.sendall(encoded)
+ if expectsReply is True:
+ index = (packet.sessionID,
+ packet.transactionID,
+ packet.packetID)
+ self.packetLog[index] = packet
+
+ def pollSocket(self):
+ "Reads all currently available data from sock, non-blocking"
+ data = ""
+ while True:
+ tmp = select.select([self.socket], [], [], 0)[0]
+ if len(tmp) == 0: # No socket, means no data available
+ break
+ tmp = tmp[0]
+ newdata = tmp.recv(4096) # Arbitrary value
+ if len(newdata) > 0:
+ dolog("Received data: " + repr(newdata) + "\n", 4)
+ data += newdata
+ else:
+ break
+ self.recievedData += data
+
+ # Packet handlers start here
+
+ def handle_GetPDU(self, packet):
+ binds = []
+ for oidr in packet.oidranges:
+ target = oidr.start
+ callback, oid = self.database.getOID(target, False)
+ if (oid != target) or (callback is None):
+ binds.append(ax.Varbind(ax.VALUE_NO_SUCH_OBJECT, target))
+ else:
+ binds.append(callback(oid))
+ # There should also be a situation that leads to noSuchInstance
+ # but I do not understand the requirements for that
+ # Need to implement genError
+ resp = ax.ResponsePDU(True, self.sessionID, packet.transactionID,
+ packet.packetID, 0, ax.ERR_NOERROR, 0, binds)
+ self.sendPacket(resp, False)
+
+ def handle_GetNextPDU(self, packet):
+ binds = []
+ for oidr in packet.oidranges:
+ oids = self.database.getOIDsInRange(oidr, True)
+ if len(oids) == 0: # Nothing found
+ binds.append(ax.Varbind(ax.VALUE_END_OF_MIB_VIEW, oidr.start))
+ else:
+ callback, oid = oids[0]
+ binds.append(callback(oid))
+ # Need to implement genError
+ resp = ax.ResponsePDU(True, self.sessionID, packet.transactionID,
+ packet.packetID, 0, ax.ERR_NOERROR, 0, binds)
+ self.sendPacket(resp, False)
+
+ def handle_GetBulkPDU(self, packet):
+ binds = []
+ nonreps = packet.oidranges[:packet.nonReps]
+ repeats = packet.oidranges[packet.nonReps:]
+ # Handle non-repeats
+ for oidr in nonreps:
+ oids = self.database.getOIDsInRange(oidr, True)
+ if len(oids) == 0: # Nothing found
+ binds.append(ax.Varbind(ax.VALUE_END_OF_MIB_VIEW, oidr.start))
+ else:
+ callback, oid = oids[0]
+ binds.append(callback(oid))
+ binds.append(varbind)
+ # Handle repeaters
+ for oidr in repeats:
+ oids = self.database.getOIDsInRange(oidr)
+ if len(oids) == 0: # Nothing found
+ binds.append(ax.Varbind(ax.VALUE_END_OF_MIB_VIEW, oidr.start))
+ else:
+ for callback, oid in oids[:packet.maxReps]:
+ binds.append(callback(oid))
+ resp = ax.ResponsePDU(True, self.sessionID, packet.transactionID,
+ packet.packetID, 0, ax.ERR_NOERROR, 0, binds)
+ self.sendPacket(resp, False)
+
+
+def mainloop():
+ dolog("initing loop\n", 1)
+ sock = connect()
+ dbase = DataSource()
+ control = PacketControl(sock, dbase)
+ control.initNewSession()
+ control.mainloop(True)
+
+
+def daemonize(runfunc):
+ pid = os.fork()
+ if pid < 0:
+ print("Forking error", pid)
+ sys.exit(pid)
+ elif pid > 0: # We are the parent
+ print("Daemonization success, child pid:", pid)
+ sys.exit(0)
+
+ # We must be the child
+
+ os.umask(0)
+
+ global logfp
+ logfp = open(logfile, "a", 1)
+
+ sid = os.setsid()
+
+ # chdir should be here, change to what? root?
+
+ sys.stdin.close()
+ sys.stdout.close()
+ sys.stderr.close()
+
+ runfunc()
+
+
+usage = """
+USAGE: ntpsnmpd [-n]
+ Flg Arg Option-Name Description
+ -n no no-fork Do not fork and daemonize.
+ -d no debug-level Increase output debug message level
+ - may appear multiple times
+ -D Int set-debug-level Set the output debug message level
+ - may appear multiple times
+ -V no version Output version information and exit
+"""
+
+
+if __name__ == "__main__":
+ try:
+ (options, arguments) = getopt.getopt(
+ sys.argv[1:],
+ "ndD:V",
+ ["no-fork", "debug-level", "set-debug-level", "version"])
+ except getopt.GetoptError as e:
+ sys.stderr.write("%s\n" % e)
+ sys.stderr.write(usage)
+ raise SystemExit(1)
+
+ for (switch, val) in options:
+ if switch in ("-n", "--no-fork"):
+ # currently non functional, as nofork is inited to True
+ nofork = True
+ elif switch in ("-d", "--debug-level"):
+ debug += 1
+ elif switch in ("-D", "--set-debug-level"):
+ errmsg = "Error: -D parameter '%s' not a number\n"
+ debug = ntp.util.safeargcast(val, int, errmsg, usage)
+ elif switch in ("-V", "--version"):
+ print("ntpsnmpd %s" % ntp.util.stdversion())
+ raise SystemExit(0)
+
+ if nofork is True:
+ mainloop()
+ else:
+ daemonize(mainloop)
=====================================
wscript
=====================================
--- a/wscript
+++ b/wscript
@@ -1050,6 +1050,7 @@ python_scripts = [
"ntpclients/ntpviz",
"ntpclients/ntpwait",
"ntpclients/ntplogtemp",
+ "ntpclients/ntpsnmpd",
]
View it on GitLab: https://gitlab.com/NTPsec/ntpsec/commit/ef798530df64d10c57732d88e23d3dbc990ee879
---
View it on GitLab: https://gitlab.com/NTPsec/ntpsec/commit/ef798530df64d10c57732d88e23d3dbc990ee879
You're receiving this email because of your account on gitlab.com.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.ntpsec.org/pipermail/vc/attachments/20171029/1ec4632c/attachment.html>
More information about the vc
mailing list