summaryrefslogtreecommitdiffstats
path: root/ksysguard/ksysguardd/Solaris/NetDev.c
diff options
context:
space:
mode:
authortoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
committertoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
commit4aed2c8219774f5d797760606b8489a92ddc5163 (patch)
tree3f8c130f7d269626bf6a9447407ef6c35954426a /ksysguard/ksysguardd/Solaris/NetDev.c
downloadtdebase-4aed2c8219774f5d797760606b8489a92ddc5163.tar.gz
tdebase-4aed2c8219774f5d797760606b8489a92ddc5163.zip
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdebase@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'ksysguard/ksysguardd/Solaris/NetDev.c')
-rw-r--r--ksysguard/ksysguardd/Solaris/NetDev.c679
1 files changed, 679 insertions, 0 deletions
diff --git a/ksysguard/ksysguardd/Solaris/NetDev.c b/ksysguard/ksysguardd/Solaris/NetDev.c
new file mode 100644
index 000000000..89db266cb
--- /dev/null
+++ b/ksysguard/ksysguardd/Solaris/NetDev.c
@@ -0,0 +1,679 @@
+/*
+ KSysGuard, the KDE System Guard
+
+ Copyright (c) 1999, 2000 Chris Schlaeger <[email protected]>
+
+ Solaris support by Torsten Kasch <[email protected]>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of version 2 of the GNU General Public
+ License as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <stropts.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <net/if.h>
+
+#include "config.h"
+
+#ifdef HAVE_KSTAT
+#include <kstat.h>
+#endif
+
+#include "ksysguardd.h"
+#include "Command.h"
+#include "NetDev.h"
+
+/*
+ * available network interface statistics through kstat(3):
+ *
+ * kstat name value
+ * ----------------------------------------------------------------------
+ * for the loopback interface(s) we can get
+ * ipackets # packets received
+ * opackets # packets sent
+ * in addition to those, for "real" interfaces:
+ * oerrors # xmit errors
+ * ierrors # recv errors
+ * macxmt_errors # xmit errors reported by hardware?
+ * macrcv_errors # recv errors reported by hardware?
+ * opackets64 same as opackets (64bit)
+ * ipackets64 same as ipackets (64bit)
+ * obytes # bytes sent
+ * rbytes # bytes received
+ * obytes64 same as obytes (64bit)
+ * rbytes64 same as ibytes (64bit)
+ * collisions # collisions
+ * multixmt # multicasts sent?
+ * multircv # multicasts received?
+ * brdcstxmt # broadcasts transmitted
+ * brdcstrcv # broadcasts received
+ * unknowns
+ * blocked
+ * ex_collisions
+ * defer_xmts
+ * align_errors
+ * fcs_errors
+ * oflo # overflow errors
+ * uflo # underflow errors
+ * runt_errors
+ * missed
+ * tx_late_collisions
+ * carrier_errors
+ * noxmtbuf
+ * norcvbuf
+ * xmt_badinterp
+ * rcv_badinterp
+ * intr # interrupts?
+ * xmtretry # xmit retries?
+ * ifspeed interface speed: 10000000 for 10BaseT
+ * duplex "half" or "full"
+ * media e.g. "PHY/MII"
+ * promisc promiscuous mode (e.g. "off")
+ * first_collisions
+ * multi_collisions
+ * sqe_errors
+ * toolong_errors
+ */
+
+typedef struct {
+ char *Name;
+ short flags;
+ unsigned long ipackets;
+ unsigned long OLDipackets;
+ unsigned long opackets;
+ unsigned long OLDopackets;
+ unsigned long ierrors;
+ unsigned long OLDierrors;
+ unsigned long oerrors;
+ unsigned long OLDoerrors;
+ unsigned long collisions;
+ unsigned long OLDcollisions;
+ unsigned long multixmt;
+ unsigned long OLDmultixmt;
+ unsigned long multircv;
+ unsigned long OLDmultircv;
+ unsigned long brdcstxmt;
+ unsigned long OLDbrdcstxmt;
+ unsigned long brdcstrcv;
+ unsigned long OLDbrdcstrcv;
+} NetDevInfo;
+
+
+#define NBUFFERS 64
+#define MAXNETDEVS 64
+static NetDevInfo IfInfo[MAXNETDEVS];
+
+static int NetDevCount;
+
+/*
+ * insertnetdev() -- insert device name & flags into our list
+ */
+int insertnetdev( const char *name, const short flags ) {
+
+ int i = 0;
+
+ /*
+ * interface "aliases" don't seem to have
+ * separate kstat statistics, so we skip them
+ */
+ if( strchr( name, (int) ':' ) != NULL )
+ return( 0 );
+
+ while( (i < NetDevCount) && (strcmp( IfInfo[i].Name, name ) != 0) ) {
+ if( strcmp( IfInfo[i].Name, name ) == 0 )
+ return( 0 );
+ i++;
+ }
+
+ /*
+ * init new slot
+ */
+ IfInfo[i].Name = strdup( name );
+ IfInfo[i].flags = flags;
+ IfInfo[i].ipackets = 0L;
+ IfInfo[i].OLDipackets = 0L;
+ IfInfo[i].opackets = 0L;
+ IfInfo[i].OLDopackets = 0L;
+ IfInfo[i].ierrors = 0L;
+ IfInfo[i].OLDierrors = 0L;
+ IfInfo[i].oerrors = 0L;
+ IfInfo[i].OLDoerrors = 0L;
+ IfInfo[i].collisions = 0L;
+ IfInfo[i].OLDcollisions = 0L;
+ IfInfo[i].multixmt = 0L;
+ IfInfo[i].OLDmultixmt = 0L;
+ IfInfo[i].multircv = 0L;
+ IfInfo[i].OLDmultircv = 0L;
+ IfInfo[i].brdcstxmt = 0L;
+ IfInfo[i].OLDbrdcstxmt = 0L;
+ IfInfo[i].brdcstrcv = 0L;
+ IfInfo[i].OLDbrdcstrcv = 0L;
+ NetDevCount = ++i;
+
+ /* XXX: need sanity checks! */
+ return( 0 );
+}
+
+/*
+ * getnetdevlist() -- get a list of all "up" interfaces
+ */
+int getnetdevlist( void ) {
+
+ int fd;
+ int buffsize;
+ int prevsize;
+ int prevCount;
+ struct ifconf ifc;
+ struct ifreq *ifr;
+
+ if( (fd = socket( PF_INET, SOCK_DGRAM, 0 )) < 0 ) {
+ return( -1 );
+ }
+
+ /*
+ * get the interface list via iotl( SIOCGIFCONF )
+ * the following algorithm based on ideas from W.R. Stevens'
+ * "UNIX Network Programming", Vol. 1:
+ * Since the ioctl may return 0, indicating success, even if the
+ * ifreq buffer was too small, we have to make sure, it didn't
+ * get truncated by comparing our initial size guess with the
+ * actual returned size.
+ */
+ prevsize = 0;
+ buffsize = NBUFFERS * sizeof( struct ifreq );
+ while( 1 ) {
+ if( (ifc.ifc_buf = malloc( buffsize )) == NULL )
+ return( -1 );
+
+ ifc.ifc_len = buffsize;
+ if( ioctl( fd, SIOCGIFCONF, &ifc ) < 0 ) {
+ if( errno != EINVAL || prevsize != 0 ) {
+ free( ifc.ifc_buf );
+ return( -1 );
+ }
+ } else {
+ if( ifc.ifc_len == prevsize )
+ /* success */
+ break;
+ prevsize = ifc.ifc_len;
+ }
+ /*
+ * initial buffer guessed too small, allocate a bigger one
+ */
+ free( ifc.ifc_buf );
+ buffsize = (NBUFFERS + 10) * sizeof( struct ifreq );
+ }
+
+ /*
+ * get the names for all interfaces which are configured "up"
+ * we're not interested in the ifc data (address), so we reuse the
+ * same structure (with ifc.len set) for the next ioctl()
+ */
+ prevCount = NetDevCount;
+ for( ifr = (struct ifreq *) ifc.ifc_buf;
+ ifr < (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
+ ifr++ ) {
+ if( ioctl( fd, SIOCGIFFLAGS, ifr ) < 0 ) {
+ free( ifc.ifc_buf );
+ return( -1 );
+ }
+ if( ifr->ifr_flags & IFF_UP )
+ insertnetdev( ifr->ifr_name, ifr->ifr_flags );
+ }
+ free( ifc.ifc_buf );
+ close( fd );
+
+ if( (prevCount > 0) && (prevCount != NetDevCount) ) {
+ print_error( "RECONFIGURE\n" );
+ prevCount = NetDevCount;
+ }
+
+ return( NetDevCount );
+}
+
+void initNetDev( struct SensorModul* sm ) {
+#ifdef HAVE_KSTAT
+ char mon[128];
+ int i;
+
+ getnetdevlist();
+ for( i = 0; i < NetDevCount; i++ ) {
+ sprintf( mon, "network/%s/ipackets", IfInfo[i].Name );
+ registerMonitor( mon, "integer",
+ printIPackets, printIPacketsInfo, sm );
+ sprintf( mon, "network/%s/opackets", IfInfo[i].Name );
+ registerMonitor( mon, "integer",
+ printOPackets, printOPacketsInfo, sm );
+ /*
+ * if this isn't a loopback interface,
+ * register additional monitors
+ */
+ if( ! (IfInfo[i].flags & IFF_LOOPBACK) ) {
+ /*
+ * recv errors
+ */
+ sprintf( mon, "network/%s/ierrors",
+ IfInfo[i].Name );
+ registerMonitor( mon, "integer",
+ printIErrors, printIErrorsInfo, sm );
+ /*
+ * xmit errors
+ */
+ sprintf( mon, "network/%s/oerrors",
+ IfInfo[i].Name );
+ registerMonitor( mon, "integer",
+ printOErrors, printOErrorsInfo, sm );
+ /*
+ * collisions
+ */
+ sprintf( mon, "network/%s/collisions",
+ IfInfo[i].Name );
+ registerMonitor( mon, "integer",
+ printCollisions, printCollisionsInfo, sm );
+ /*
+ * multicast xmits
+ */
+ sprintf( mon, "network/%s/multixmt",
+ IfInfo[i].Name );
+ registerMonitor( mon, "integer",
+ printMultiXmits, printMultiXmitsInfo, sm );
+ /*
+ * multicast recvs
+ */
+ sprintf( mon, "network/%s/multircv",
+ IfInfo[i].Name );
+ registerMonitor( mon, "integer",
+ printMultiRecvs, printMultiRecvsInfo, sm );
+ /*
+ * broadcast xmits
+ */
+ sprintf( mon, "network/%s/brdcstxmt",
+ IfInfo[i].Name );
+ registerMonitor( mon, "integer",
+ printBcastXmits, printBcastXmitsInfo, sm );
+ /*
+ * broadcast recvs
+ */
+ sprintf( mon, "network/%s/brdcstrcv",
+ IfInfo[i].Name );
+ registerMonitor( mon, "integer",
+ printBcastRecvs, printBcastRecvsInfo, sm );
+ }
+ }
+#endif
+}
+
+void exitNetDev( void ) {
+}
+
+int updateNetDev( void ) {
+
+#ifdef HAVE_KSTAT
+ kstat_ctl_t *kctl;
+ kstat_t *ksp;
+ kstat_named_t *kdata;
+ int i;
+
+ /*
+ * get a kstat handle and update the user's kstat chain
+ */
+ if( (kctl = kstat_open()) == NULL )
+ return( 0 );
+ while( kstat_chain_update( kctl ) != 0 )
+ ;
+
+ for( i = 0; i < NetDevCount; i++ ) {
+ char *name;
+ char *ptr;
+
+ /*
+ * chop off the trailing interface no
+ */
+ name = strdup( IfInfo[i].Name );
+ ptr = name + strlen( name ) - 1;
+ while( (ptr > name) && isdigit( (int) *ptr ) ) {
+ *ptr = '\0';
+ ptr--;
+ }
+
+ /*
+ * traverse the kstat chain
+ * to find the appropriate statistics
+ */
+ if( (ksp = kstat_lookup( kctl,
+ name, 0, IfInfo[i].Name )) == NULL ) {
+ free( name );
+ return( 0 );
+ }
+ if( kstat_read( kctl, ksp, NULL ) == -1 ) {
+ free( name );
+ return( 0 );
+ }
+ free( name );
+
+ /*
+ * lookup & store the data
+ */
+ kdata = (kstat_named_t *) kstat_data_lookup( ksp, "ipackets" );
+ if( kdata != NULL ) {
+ IfInfo[i].OLDipackets = IfInfo[i].ipackets;
+ IfInfo[i].ipackets = kdata->value.ul;
+ }
+ kdata = (kstat_named_t *) kstat_data_lookup( ksp, "opackets" );
+ if( kdata != NULL ) {
+ IfInfo[i].OLDopackets = IfInfo[i].opackets;
+ IfInfo[i].opackets = kdata->value.ul;
+ }
+ kdata = (kstat_named_t *) kstat_data_lookup( ksp, "ierrors" );
+ if( kdata != NULL ) {
+ IfInfo[i].OLDierrors = IfInfo[i].ierrors;
+ IfInfo[i].ierrors = kdata->value.ul;
+ }
+ kdata = (kstat_named_t *) kstat_data_lookup( ksp, "oerrors" );
+ if( kdata != NULL ) {
+ IfInfo[i].OLDoerrors = IfInfo[i].oerrors;
+ IfInfo[i].oerrors = kdata->value.ul;
+ }
+ kdata = (kstat_named_t *) kstat_data_lookup( ksp, "collisions" );
+ if( kdata != NULL ) {
+ IfInfo[i].OLDcollisions = IfInfo[i].collisions;
+ IfInfo[i].collisions = kdata->value.ul;
+ }
+ kdata = (kstat_named_t *) kstat_data_lookup( ksp, "multixmt" );
+ if( kdata != NULL ) {
+ IfInfo[i].OLDmultixmt = IfInfo[i].multixmt;
+ IfInfo[i].multixmt = kdata->value.ul;
+ }
+ kdata = (kstat_named_t *) kstat_data_lookup( ksp, "multircv" );
+ if( kdata != NULL ) {
+ IfInfo[i].OLDmultircv = IfInfo[i].multircv;
+ IfInfo[i].multircv = kdata->value.ul;
+ }
+ kdata = (kstat_named_t *) kstat_data_lookup( ksp, "brdcstxmt" );
+ if( kdata != NULL ) {
+ IfInfo[i].OLDbrdcstxmt = IfInfo[i].brdcstxmt;
+ IfInfo[i].brdcstxmt = kdata->value.ul;
+ }
+ kdata = (kstat_named_t *) kstat_data_lookup( ksp, "brdcstrcv" );
+ if( kdata != NULL ) {
+ IfInfo[i].OLDbrdcstrcv = IfInfo[i].brdcstrcv;
+ IfInfo[i].brdcstrcv = kdata->value.ul;
+ }
+ }
+
+ kstat_close( kctl );
+#endif /* ! HAVE_KSTAT */
+
+ return( 0 );
+}
+
+void printIPacketsInfo( const char *cmd ) {
+ fprintf(CurrentClient, "Received Packets\t0\t0\tPackets\n" );
+}
+
+void printIPackets( const char *cmd ) {
+
+ char *cmdcopy = strdup( cmd );
+ char *name, *ptr;
+ int i;
+
+ ptr = strchr( cmdcopy, (int) '/' );
+ name = ++ptr;
+ ptr = strchr( name, (int) '/' );
+ *ptr = '\0';
+
+ for( i = 0; i < NetDevCount; i++ ) {
+ if( (IfInfo[i].OLDipackets > 0)
+ && (strcmp( IfInfo[i].Name, name ) == 0) ) {
+ fprintf(CurrentClient, "%ld\n",
+ IfInfo[i].ipackets - IfInfo[i].OLDipackets);
+ free( cmdcopy );
+ return;
+ }
+ }
+ free( cmdcopy );
+ fprintf(CurrentClient, "0\n" );
+}
+
+void printOPacketsInfo( const char *cmd ) {
+ fprintf(CurrentClient, "Transmitted Packets\t0\t0\tPackets\n" );
+}
+
+void printOPackets( const char *cmd ) {
+
+ char *cmdcopy = strdup( cmd );
+ char *name, *ptr;
+ int i;
+
+ ptr = strchr( cmdcopy, (int) '/' );
+ name = ++ptr;
+ ptr = strchr( name, (int) '/' );
+ *ptr = '\0';
+
+ for( i = 0; i < NetDevCount; i++ ) {
+ if( (IfInfo[i].OLDopackets > 0)
+ && (strcmp( IfInfo[i].Name, name ) == 0) ) {
+ fprintf(CurrentClient, "%ld\n",
+ IfInfo[i].opackets - IfInfo[i].OLDopackets );
+ free( cmdcopy );
+ return;
+ }
+ }
+ free( cmdcopy );
+ fprintf(CurrentClient, "0\n" );
+}
+
+void printIErrorsInfo( const char *cmd ) {
+ fprintf(CurrentClient, "Input Errors\t0\t0\tPackets\n" );
+}
+
+void printIErrors( const char *cmd ) {
+
+ char *cmdcopy = strdup( cmd );
+ char *name, *ptr;
+ int i;
+
+ ptr = strchr( cmdcopy, (int) '/' );
+ name = ++ptr;
+ ptr = strchr( name, (int) '/' );
+ *ptr = '\0';
+
+ for( i = 0; i < NetDevCount; i++ ) {
+ if( (IfInfo[i].OLDierrors > 0)
+ && (strcmp( IfInfo[i].Name, name ) == 0) ) {
+ fprintf(CurrentClient, "%ld\n",
+ IfInfo[i].ierrors - IfInfo[i].OLDierrors );
+ free( cmdcopy );
+ return;
+ }
+ }
+ free( cmdcopy );
+ fprintf(CurrentClient, "0\n" );
+}
+
+void printOErrorsInfo( const char *cmd ) {
+ fprintf(CurrentClient, "Output Errors\t0\t0\tPackets\n" );
+}
+
+void printOErrors( const char *cmd ) {
+
+ char *cmdcopy = strdup( cmd );
+ char *name, *ptr;
+ int i;
+
+ ptr = strchr( cmdcopy, (int) '/' );
+ name = ++ptr;
+ ptr = strchr( name, (int) '/' );
+ *ptr = '\0';
+
+ for( i = 0; i < NetDevCount; i++ ) {
+ if( (IfInfo[i].OLDoerrors > 0)
+ && (strcmp( IfInfo[i].Name, name ) == 0) ) {
+ fprintf(CurrentClient, "%ld\n",
+ IfInfo[i].oerrors - IfInfo[i].OLDoerrors );
+ free( cmdcopy );
+ return;
+ }
+ }
+ free( cmdcopy );
+ fprintf(CurrentClient, "0\n" );
+}
+
+void printCollisionsInfo( const char *cmd ) {
+ fprintf(CurrentClient, "Collisions\t0\t0\tPackets\n" );
+}
+
+void printCollisions( const char *cmd ) {
+
+ char *cmdcopy = strdup( cmd );
+ char *name, *ptr;
+ int i;
+
+ ptr = strchr( cmdcopy, (int) '/' );
+ name = ++ptr;
+ ptr = strchr( name, (int) '/' );
+ *ptr = '\0';
+
+ for( i = 0; i < NetDevCount; i++ ) {
+ if( (IfInfo[i].OLDcollisions > 0)
+ && (strcmp( IfInfo[i].Name, name ) == 0) ) {
+ fprintf(CurrentClient, "%ld\n",
+ IfInfo[i].collisions - IfInfo[i].OLDcollisions );
+ free( cmdcopy );
+ return;
+ }
+ }
+ free( cmdcopy );
+ fprintf(CurrentClient, "0\n" );
+}
+
+void printMultiXmitsInfo( const char *cmd ) {
+ fprintf(CurrentClient, "Multicasts Sent\t0\t0\tPackets\n" );
+}
+
+void printMultiXmits( const char *cmd ) {
+
+ char *cmdcopy = strdup( cmd );
+ char *name, *ptr;
+ int i;
+
+ ptr = strchr( cmdcopy, (int) '/' );
+ name = ++ptr;
+ ptr = strchr( name, (int) '/' );
+ *ptr = '\0';
+
+ for( i = 0; i < NetDevCount; i++ ) {
+ if( (IfInfo[i].OLDmultixmt > 0)
+ && (strcmp( IfInfo[i].Name, name ) == 0) ) {
+ fprintf(CurrentClient, "%ld\n",
+ IfInfo[i].multixmt - IfInfo[i].OLDmultixmt );
+ free( cmdcopy );
+ return;
+ }
+ }
+ free( cmdcopy );
+ fprintf(CurrentClient, "0\n" );
+}
+
+void printMultiRecvsInfo( const char *cmd ) {
+ fprintf(CurrentClient, "Multicasts Received\t0\t0\tPackets\n" );
+}
+
+void printMultiRecvs( const char *cmd ) {
+
+ char *cmdcopy = strdup( cmd );
+ char *name, *ptr;
+ int i;
+
+ ptr = strchr( cmdcopy, (int) '/' );
+ name = ++ptr;
+ ptr = strchr( name, (int) '/' );
+ *ptr = '\0';
+
+ for( i = 0; i < NetDevCount; i++ ) {
+ if( (IfInfo[i].OLDmultircv > 0)
+ && (strcmp( IfInfo[i].Name, name ) == 0) ) {
+ fprintf(CurrentClient, "%ld\n",
+ IfInfo[i].multircv - IfInfo[i].OLDmultircv );
+ free( cmdcopy );
+ return;
+ }
+ }
+ free( cmdcopy );
+ fprintf(CurrentClient, "0\n" );
+}
+
+void printBcastXmitsInfo( const char *cmd ) {
+ fprintf(CurrentClient, "Broadcasts Sent\t0\t0\tPackets\n" );
+}
+
+void printBcastXmits( const char *cmd ) {
+
+ char *cmdcopy = strdup( cmd );
+ char *name, *ptr;
+ int i;
+
+ ptr = strchr( cmdcopy, (int) '/' );
+ name = ++ptr;
+ ptr = strchr( name, (int) '/' );
+ *ptr = '\0';
+
+ for( i = 0; i < NetDevCount; i++ ) {
+ if( (IfInfo[i].OLDbrdcstxmt > 0)
+ && (strcmp( IfInfo[i].Name, name ) == 0) ) {
+ fprintf(CurrentClient, "%ld\n",
+ IfInfo[i].brdcstxmt - IfInfo[i].OLDbrdcstxmt );
+ free( cmdcopy );
+ return;
+ }
+ }
+ free( cmdcopy );
+ fprintf(CurrentClient, "0\n" );
+}
+
+void printBcastRecvsInfo( const char *cmd ) {
+ fprintf(CurrentClient, "Broadcasts Received\t0\t0\tPackets\n" );
+}
+
+void printBcastRecvs( const char *cmd ) {
+
+ char *cmdcopy = strdup( cmd );
+ char *name, *ptr;
+ int i;
+
+ ptr = strchr( cmdcopy, (int) '/' );
+ name = ++ptr;
+ ptr = strchr( name, (int) '/' );
+ *ptr = '\0';
+
+ for( i = 0; i < NetDevCount; i++ ) {
+ if( (IfInfo[i].OLDbrdcstrcv > 0)
+ && (strcmp( IfInfo[i].Name, name ) == 0) ) {
+ fprintf(CurrentClient, "%ld\n",
+ IfInfo[i].brdcstrcv - IfInfo[i].OLDbrdcstrcv );
+ free( cmdcopy );
+ return;
+ }
+ }
+ free( cmdcopy );
+ fprintf(CurrentClient, "0\n" );
+}