/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* $Id$ */ /* Copyright (C) 1998-99 Martin Baulig This file is part of LibGTop 1.0. Contributed by Martin Baulig , October 1998. LibGTop is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. LibGTop 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 LibGTop; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include #include #include #include #include #if !defined (_LIBC) && defined (__GNU_LIBRARY__) && __GNU_LIBRARY__ > 1 /* GNU LibC */ #include #include #include #include #include #include #include #include #else /* Libc 5 */ #include #include #include #include #include #include #include #endif static const unsigned long _glibtop_sysdeps_ppp = (1L << GLIBTOP_PPP_STATE) + (1L << GLIBTOP_PPP_BYTES_IN) + (1L << GLIBTOP_PPP_BYTES_OUT); #ifdef SIOCDEVPRIVATE static int ip_socket; #endif /* Init function. */ int glibtop_init_ppp_s (glibtop *server) { server->sysdeps.ppp = _glibtop_sysdeps_ppp; #ifdef SIOCDEVPRIVATE /* open ip socket */ if ((ip_socket = socket (AF_INET, SOCK_DGRAM, 0)) < 0) return -GLIBTOP_ERROR_NO_KERNEL_SUPPORT; /* should never happen */ #endif return 0; } static int get_ISDN_stats (glibtop *server, int *in, int *out) { unsigned long *isdn_stats, *ptr; int fd, i; *in = *out = 0; isdn_stats = glibtop_calloc_r (server, ISDN_MAX_CHANNELS * 2, sizeof (unsigned long)); fd = open ("/dev/isdninfo", O_RDONLY); if (fd < 0) { glibtop_free_r (server, isdn_stats); return FALSE; } if ((ioctl (fd, IIOCGETCPS, isdn_stats) < 0) && (errno != 0)) { glibtop_free_r (server, isdn_stats); close (fd); return FALSE; } for (i = 0, ptr = isdn_stats; i < ISDN_MAX_CHANNELS; i++) { *in += *ptr++; *out += *ptr++; } glibtop_free_r (server, isdn_stats); close (fd); return TRUE; } static int is_ISDN_on (glibtop *server, int device, int *online) { FILE *f = 0; char buffer [BUFSIZ], *p; int i; /* Perhaps I should try to explain this code a little bit. * * ------------------------------------------------------------ * This is from the manpage of isdninfo(4): * * DESCRIPTION * /dev/isdninfo is a character device with major number 45 * and minor number 255. It delivers status information from * the Linux ISDN subsystem to user level. * * DATA FORMAT * When reading from this device, the current status of the * Linux ISDN subsystem is delivered in 6 lines of text. Each * line starts with a tag string followed by a colon and * whitespace. After that the status values are appended sep- * arated by whitespace. * * flags is the tag of line 5. In this line for every driver * slot, it's B-Channel status is shown. If no driver * is registered in a slot, a ? is shown. For every * established B-Channel of the driver, a bit is set * in the shown value. The driver's first channel is * mapped to bit 0, the second channel to bit 1 and so * on. * ------------------------------------------------------------ * * So we open /dev/isdninfo, discard the first four lines of text * and then check whether we have something that is not `0' or `?' * in one of the flags fields. * * Sounds complicated, but I don't see any other way to check whether * we are connected. Also, this is the method some other ISDN tools * for Linux use. * * Martin */ f = fopen ("/dev/isdninfo", "r"); if (!f) return FALSE; for (i = 0; i < 5; i++) { if (fgets (buffer, BUFSIZ, f) == NULL) { fclose (f); return FALSE; } } if (strncmp (buffer, "flags:", 6)) { fclose (f); return FALSE; } p = buffer+6; for (i = 0; i <= device; i++) { char *end = p; while (isspace (*p)) p++; for (end = p; *end && !isspace (*end); end++) ; if (*end == 0) break; else *end++ = 0; if (i < device) { p = end; continue; } fclose (f); if (strlen (p) != 1) return FALSE; if (*p == '0') { *online = FALSE; return TRUE; } else if (*p == '1') { *online = TRUE; return TRUE; } return FALSE; } fclose (f); return FALSE; } static int is_Modem_on (glibtop *server, int device) { gchar buf[64], lock_file [BUFSIZ]; pid_t pid = -1; FILE *f = 0; sprintf (lock_file, LIBGTOP_MODEM_LOCKFILE, device); f = fopen (lock_file, "r"); if(!f) return FALSE; if (fgets (buf, sizeof(buf), f) == NULL) { fclose (f); return FALSE; } fclose (f); pid = (pid_t) strtol (buf, NULL, 10); if (pid < 1 || (kill (pid, 0) == -1 && errno != EPERM)) return FALSE; return TRUE; } static int get_Modem_stats (int device, int *in, int *out) { struct ifreq ifreq; struct ppp_stats stats; char device_name [IFNAMSIZ]; sprintf (device_name, "ppp%d", device); memset (&ifreq, 0, sizeof(ifreq)); strncpy (ifreq.ifr_ifrn.ifrn_name, device_name, IFNAMSIZ); ifreq.ifr_ifru.ifru_data = (caddr_t)&stats; #ifdef SIOCDEVPRIVATE /* open ip socket */ if ((ip_socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { g_print("could not open an ip socket\n"); return 1; } if ((ioctl (ip_socket, SIOCDEVPRIVATE, (caddr_t)&ifreq) < 0)) { *in = *out = 0; /* failure means ppp is not up */ return FALSE; } else { *in = stats.p.ppp_ibytes; *out = stats.p.ppp_obytes; return TRUE; } #else /* not SIOCDEVPRIVATE */ *in = *out = 0; return FALSE; #endif /* not SIOCDEVPRIVATE */ } /* Provides PPP/ISDN information. */ int glibtop_get_ppp_s (glibtop *server, glibtop_ppp *buf, unsigned short device, unsigned short use_isdn) { int in, out, online; glibtop_init_s (&server, GLIBTOP_SYSDEPS_PPP, 0); memset (buf, 0, sizeof (glibtop_ppp)); if (use_isdn) { /* ISDN */ if (is_ISDN_on (server, device, &online)) { buf->state = online ? GLIBTOP_PPP_STATE_ONLINE : GLIBTOP_PPP_STATE_HANGUP; buf->flags |= (1L << GLIBTOP_PPP_STATE); } if (get_ISDN_stats (server, &in, &out)) { buf->bytes_in = in; buf->bytes_out = out; buf->flags |= (1L << GLIBTOP_PPP_BYTES_IN) | (1L << GLIBTOP_PPP_BYTES_OUT); } } else { /* Modem */ buf->state = is_Modem_on (server, device) ? GLIBTOP_PPP_STATE_ONLINE : GLIBTOP_PPP_STATE_HANGUP; buf->flags |= (1L << GLIBTOP_PPP_STATE); if (get_Modem_stats (device, &in, &out)) { buf->bytes_in = in; buf->bytes_out = out; buf->flags |= (1L << GLIBTOP_PPP_BYTES_IN) | (1L << GLIBTOP_PPP_BYTES_OUT); } } return 0; }