/************************************************************************/ /* */ /* ***** ***** */ /* ***** ***** */ /* ***** ***** */ /* ***** ***** */ /* *************** *************** */ /* ***************** ***************** */ /* *************** *************** */ /* ***** ***** TheNetNode */ /* ***** ***** Portable */ /* ***** ***** Network */ /* ***** ***** Software */ /* */ /* File os/linux/linux.c (maintained by: DF6LN) */ /* */ /* This file is part of "TheNetNode" - Software Package */ /* */ /* Copyright (C) 1998 - 2008 NORD>= 'A') && (*s <= 'Z')) *s += 'a'-'A'; s++; } return(p); } /* String in Grossbuchstaben umwandeln - aus DJGPP GNU-Paket fuer MS-DOS von D.J. Delorie */ char * strupr(char *s) { char *p = s; while (*s) { if ((*s >= 'a') && (*s <= 'z')) *s += 'A'-'a'; s++; } return(p); } /************************************************************************/ /* */ /* Als Ersatz fuer die Funktionen "findfirst" und "findnext" (bei DOS) */ /* werden die Funktionen "xfindfirst" und "xfindnext" verwendet. Hier */ /* wird nur der fuer TNN benoetigte Teil in die Struktur ffblk einge- */ /* tragen. Der zuletzt gefundene Filename muss in ffblk->ff_name erhal- */ /* ten bleiben, weil dieser beim Aufruf von "xfindnext" gesucht wird. */ /* */ /************************************************************************/ int xfindfirst(const char *pathname, struct ffblk *ffblk, int attrib) { char *fnpoi; DIR *dp; struct dirent *dirp; int retval; strcpy(ffblk->ff_path, pathname); /* Filename incl. Pfad */ normfname(ffblk->ff_path); /* '\\' -> '/' */ fnpoi = strrchr(ffblk->ff_path, '/'); /* Pfad angegeben? */ if (fnpoi == NULL) /* - nein .. */ { strcpy(ffblk->ff_find, ffblk->ff_path); /* Filename kopieren */ strcpy(ffblk->ff_path, textpath); /* default: textpath */ } else /* mit Pfad */ { if (fnpoi == ffblk->ff_path+strlen(ffblk->ff_path)) /* ohne Name */ return(-1); /* Unsinn */ strcpy(ffblk->ff_find, ++fnpoi); /* nur Filename */ *fnpoi = NUL; /* Filename im Pfad loeschen */ } if ((dp = opendir(ffblk->ff_path)) == NULL) /* Directory vorhanden? */ return(-1); retval = -1; /* default: nix gefunden */ while ((dirp = readdir(dp)) != NULL) /* Eintrag vorhanden? */ { if ((fnmatch(ffblk->ff_find, dirp->d_name, FNM_PATHNAME|FNM_PERIOD) != 0)) continue; strcpy(ffblk->ff_name, dirp->d_name); setfiletime(ffblk); retval = 0; break; } closedir(dp); return(retval); } /************************************************************************/ /* */ /* Erst den zuletzt gefundenen Eintrag suchen (steht in ffblk->ff_name) */ /* und den darauffolgenden passenden Eintrag zurueckmelden. */ /* */ /************************************************************************/ int xfindnext(struct ffblk *ffblk) { DIR *dp; struct dirent *dirp; int retval; if ((dp = opendir(ffblk->ff_path)) == NULL) return(-1); retval = -1; /* default: nix gefunden */ while ((dirp = readdir(dp)) != NULL) { if ((fnmatch(ffblk->ff_name, dirp->d_name, FNM_PATHNAME|FNM_PERIOD) != 0)) continue; retval = 1; break; } if (retval == 1) { retval = -1; /* default: nix gefunden */ while ((dirp = readdir(dp)) != NULL) { if ((fnmatch(ffblk->ff_find, dirp->d_name, FNM_PATHNAME|FNM_PERIOD) != 0)) continue; strcpy(ffblk->ff_name, dirp->d_name); setfiletime(ffblk); retval = 0; break; } } closedir(dp); return(retval); } /************************************************************************/ /* */ /* Bei xfindfirst und xfindnext Datum und Uhrzeit im Fileblock setzen */ /* */ /************************************************************************/ static void setfiletime(struct ffblk *ffblk) { struct stat filestat; struct tm *filetime; char fn[MAXPATH]; sprintf(fn, "%s%s", ffblk->ff_path, ffblk->ff_name); stat(fn, &filestat); filetime = gmtime(&filestat.st_mtime); ffblk->ff_ftime = ((filetime->tm_sec / 2) & 0x1f) + ((filetime->tm_min & 0x3f) << 5) + ((filetime->tm_hour & 0x1f) << 11); ffblk->ff_fdate = (filetime->tm_mday & 0x1f) + (((filetime->tm_mon & 0x0f) + 1) << 5) + (((filetime->tm_year - 80) & 0x7f) << 9); } /************************************************************************/ /* */ /* Temporaeren Filenamen generieren und pruefen auf Verwendbarkeit, */ /* d.h. Grossbuchstaben sind nicht erlaubt, damit die Datei bei ccpread */ /* gefunden wird. */ /* */ /* 31.3.02 DG9OBU auf Verwendung von mkstemp() umgestellt */ /************************************************************************/ char * xtempnam(const char *directory, const char *prefix) { char *fn = NULL; size_t i; register int x; const char* sixx = "XXXXXX\000"; char namebuf[PATH_MAX]; char xe[128]; /* den Dateinamen erstellen, prefix und sechs X fuer mkstemp() */ memset(xe, 0, sizeof(xe)); strcpy(xe, prefix); strcat(xe, sixx); /* solange bis brauchbarer Filename gefunden */ while (fn == NULL) { /* Namen zusammenbauen */ memset(namebuf, 0, sizeof(namebuf)); strcpy(namebuf, directory); strcat(namebuf, xe); /* File generieren */ if ((x = mkstemp(&namebuf[0])) > 0) { /* und gleich wieder schliessen und loeschen */ close(x); unlink(&namebuf[0]); /* Namen pruefen */ for (i = 0; i < strlen(&namebuf[0]); ++i) /* Filenamen untersuchen */ if (namebuf[i] != tolower(namebuf[i])) /* Grossbuchstabe geht nicht */ break; /* wenn Namenspruefung erfolgreich war, dann Namen melden */ if (i == strlen(namebuf)) { fn = malloc(PATH_MAX); strcpy(fn, &namebuf[0]); return(fn); } } else break; } /* nicht erfolgreich */ return(NULL); } /************************************************************************/ /* */ /* Ermitteln des freien Festplattenplatzes in Bytes. */ /* */ /* Damit es fuer grosse Festplatten keinen Ueberlauf gibt (Rueckgabe */ /* ist vom Typ LONG), wird ab 1GB freiem Speicher immer 1GB zurueck- */ /* gemeldet - sieht da jemand Probleme? */ /* */ /************************************************************************/ LONG getdiskfree(char *path) { FILE *fp; char str[100]; ULONG frei = 0L; sprintf(str, "df %s", path); if ((fp = popen(str, "r")) != NULL) { fgets(str, 100, fp); fgets(str, 100, fp); pclose(fp); sscanf(str, "%*s %*s %*s %lu", &frei); if (frei >= 1024 * 1024 * 1024) frei = (1024 * 1024 * 1024); else frei = (frei * 1024); } return (frei); } /************************************************************************/ /* */ /* Fuer das erweiterte AUTOBIN-Protokoll wird die File-Zeit in einem */ /* Bitfeld gespeichert (s. Doku zu DPBOX), wie es BC++ bei dem Befehl */ /* getftime verwendet. Hier wird die Linux-Zeit der letzten Aenderung */ /* verwendet. */ /* */ /************************************************************************/ int getftime(int handle, struct ftime *ftimep) { struct stat filestat; struct tm *filetime; if (fstat(handle, &filestat) == -1) return(-1); filetime = gmtime(&filestat.st_mtime); ftimep->ft_tsec = filetime->tm_sec / 2; ftimep->ft_min = filetime->tm_min; ftimep->ft_hour = filetime->tm_hour; ftimep->ft_day = filetime->tm_mday; ftimep->ft_month = filetime->tm_mon + 1; ftimep->ft_year = filetime->tm_year - 80; return(0); } /************************************************************************/ /* */ /* Fuer DOS-Kompatibilitaet - Programm starten und Exit-Code des */ /* Programms zurueckgeben */ /* */ /************************************************************************/ int spawnl(int mode, const char *path, const char *arg0, const char *arg1, const char *arg2, const char *arg3, const char *arg4, const char *arg5) { pid_t pid; int status; if (mode != P_WAIT) { errno = EINVAL; return (-1); } if ((pid = fork()) < 0) { errno = ENOMEM; return (-1); } else { if (pid == 0) { if (execl(path, arg0, arg1, arg2, arg3, arg4, arg5, NULL) == -1) { exit(-1); } } } waitpid(pid, &status, 0); return(status); } /************************************************************************/ /* */ /* Groesse des freien RAM feststellen (wenig aussagekraeftig durch */ /* SWAP-Partition). Schlaegt der Aufruf fehl, wird 0 gemeldet. */ /* */ /************************************************************************/ ULONG coreleft(void) { FILE *fp; char str[100]; ULONG frei = 0L; if ((fp = popen("free -b", "r")) != NULL) { fgets(str, 100, fp); fgets(str, 100, fp); pclose(fp); sscanf(str, "%*s %*s %*s %lu", &frei); } return(frei); } /************************************************************************/ /* */ /* Befehlszeile auf Zeichen pruefen, die von der Shell ausgewertet */ /* werden. Diese werden entwertet durch ein vorangesetztes '\\'. */ /* */ /************************************************************************/ void security_check(char *cmd) { char *cmdpoi = cmd; char tmpcmd[MAXPATH]; register int i = 0; char ch; for (; i < MAXPATH - 2; ++i) { ch = *cmdpoi++; if (ch == NUL) break; if (strchr("*?\\|&;()<>$'`{}[]^#\"", ch) != NULL) tmpcmd[i++] = '\\'; tmpcmd[i] = ch; } tmpcmd[i] = NUL; strcpy(cmd, tmpcmd); } /************************************************************************/ /* */ /* 10ms-Ticker updaten */ /* */ /************************************************************************/ void update_timer(void) { fd_set rmask; struct timeval timevalue; int max_fd = 0; int count; register int i; int len; char buffer[1024]; socklen_t clilen; struct sockaddr_un cli_addr; static UWORD roundcounter = 1; #ifndef NO_WATCHDOG int lasttic10 = tic10; #endif #ifdef KERNELIF int kif_fd = -1; #endif gettimeofday(&tv, &tz); tic10 = (tv.tv_sec - tv_old.tv_sec) * 100 + (tv.tv_usec - tv_old.tv_usec) / 10000; #ifndef NO_WATCHDOG if (tic10 - lasttic10) if (write(watch_dog[1], "\0", 1) != 1) { exit(1); } #endif FD_ZERO(&rmask); /* Behandlung der Konsole bzw. Socket-Verbindung */ switch (console_type) { /* Ein/Ausgabe ueber normales Terminal */ case CONS_TERM_RUNNING: FD_SET(0, &rmask); /* Eingabe Console */ max_fd = 1; break; /* Ein/Ausgabe ueber Socket, aber noch nicht verbunden */ case CONS_SOCKET_WAITING: FD_SET(sockfd, &rmask); if (sockfd > max_fd - 1) max_fd = sockfd + 1; break; /* Ein/Ausgabe ueber verbundenen Socket */ case CONS_SOCKET_CONNECTED: FD_SET(consockfd, &rmask); if (consockfd > max_fd - 1) max_fd = consockfd + 1; break; /* Alles andere ... */ default: break; } /* if (!use_socket) { FD_SET(0, &rmask); max_fd = 1; } else { if (!soc_con) { FD_SET(sockfd, &rmask); if (sockfd > max_fd - 1) max_fd = sockfd + 1; } else { FD_SET(consockfd, &rmask); if (consockfd > max_fd - 1) max_fd = consockfd + 1; } } */ if (kiss_active) { for (i = 0; i < L1PNUM; ++i) { if (l1port[i].kisslink < 0) continue; #ifdef VANESSA if (l1port[i].kisstype == KISS_VAN) continue; #endif #ifdef AX_IPX if (l1port[i].kisstype == KISS_IPX) continue; #endif #ifdef AX25IP if (l1port[i].kisstype == KISS_AXIP) continue; #endif #ifdef KERNELIF if ( (l1port[i].kisstype == KISS_KAX25) || (l1port[i].kisstype == KISS_KAX25KJD)) continue; #endif #ifdef SIXPACK if (l1port[i].kisstype == KISS_6PACK) continue; #endif if (l1port[i].port_active) { FD_SET(l1port[i].kisslink, &rmask); if (l1port[i].kisslink > max_fd -1) max_fd = l1port[i].kisslink + 1; } } } #ifdef KERNELIF /* IP-Interface Filedescriptor ermitteln */ if ((kif_fd = ifip_active()) != -1) /* ein aktives Kernelinterface */ { FD_SET(kif_fd, &rmask); if (kif_fd > max_fd - 1) max_fd = kif_fd + 1; } #endif /* fuer alle Interfaces die benutzten Filedescriptoren fuer select() */ /* ermitteln und eintragen */ for (i = 0; i < L1PNUM; ++i) { /* nur aktive Ports bearbeiten */ if ( (l1port[i].kisslink < 0) || (l1port[i].port_active != TRUE) #ifdef SIXPACK || (l1port[i].kisstype == KISS_6PACK) /* der hat hier nichts zu suchen */ #endif ) continue; /* Interfacetypen durchgehen */ if ( #ifdef KERNELIF (l1port[i].kisstype == KISS_KAX25) || (l1port[i].kisstype == KISS_KAX25KJD) #endif #if defined(KERNELIF) && defined(AX_IPX) || #endif #ifdef AX_IPX (l1port[i].kisstype == KISS_IPX) #endif ) { FD_SET(l1port[i].kisslink, &rmask); if (l1port[i].kisslink > max_fd -1) max_fd = l1port[i].kisslink + 1; } } /* for(...) */ timevalue.tv_usec = 10000; timevalue.tv_sec = 0; if (++roundcounter < maxrounds) /* schon genug Runden vergangen? */ timevalue.tv_usec = 0; else roundcounter = 0; /* Durchlaufzaehler ruecksetzen */ count = select(max_fd, &rmask, NULL, NULL, &timevalue); if (count == -1) return; /* Konsolen/Socketverbindung bearbeiten */ switch (console_type) { /* Konsole ist ein Terminal */ case CONS_TERM_RUNNING: /* Zeichen auf der Standardeingabe ? */ if (FD_ISSET(0, &rmask)) { if ((len = read(0, buffer, 1024)) != -1) host_to_queue(buffer, len); else { /* Oh, oh, Fehler beim Lesen von der Konsole */ /* Es werden nun weitere Konsolenoperationen */ /* unterdrueckt. */ console_type = CONS_NO_CONSOLE; } } break; /* Socket wartet auf Verbindung */ case CONS_SOCKET_WAITING: /* Wartende Verbindung annehmen */ if (FD_ISSET(sockfd, &rmask)) { clilen = sizeof(cli_addr); consockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen); if (consockfd >= 0) console_type = CONS_SOCKET_CONNECTED; } break; /* Daten von verbundenem Socket */ case CONS_SOCKET_CONNECTED: if (FD_ISSET(consockfd, &rmask)) { len = read(consockfd, buffer, 1024); if ((len == -1) || (len == 0)) { close(consockfd); consockfd = -1; console_type = CONS_SOCKET_WAITING; } else host_to_queue(buffer, len); } break; default: break; } /* if (!use_socket) { if (FD_ISSET(0, &rmask)) if ((len = read(0, buffer, 1024)) != 0) host_to_queue(buffer, len); } else { if (!soc_con) { if (FD_ISSET(sockfd, &rmask)) { clilen = sizeof(cli_addr); consockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen); if (consockfd >= 0) soc_con = TRUE; } } else if (FD_ISSET(consockfd, &rmask)) { len = read(consockfd, buffer, 1024); if ((len == -1) || (len == 0)) { close(consockfd); soc_con = FALSE; } else host_to_queue(buffer, len); } } */ #ifdef KERNELIF /* IP-Interface RX */ if ((kif_fd != -1) && (FD_ISSET(kif_fd, &rmask))) ifip_frame_to_router(); #endif /* alle Ports durchgehen */ for (i = 0; i < L1PNUM; ++i) { /* unbenutzte Ports nicht bearbeiten */ if ( (l1port[i].kisslink < 0) || (l1port[i].port_active != TRUE) #ifdef SIXPACK || (l1port[i].kisstype == KISS_6PACK) /* der hat hier nichts zu suchen */ #endif ) continue; /* pruefen ob dieser Port einen lesbaren Filedescriptor hat */ if (FD_ISSET(l1port[i].kisslink, &rmask)) { /* je nach Interfacetyp den richtigen RX aufrufen */ switch (l1port[i].kisstype) { #ifdef KERNELIF /* Kernel-AX25-Port RX */ case KISS_KAX25 : case KISS_KAX25KJD : ifax_rx(l1port[i].kisslink); break; #endif #ifdef AX_IPX /* AXIPX-RX */ case KISS_IPX : axipx_recv(); break; #endif default : continue; } } } if (kiss_active) { for (i = 0; i < L1PNUM; ++i) { if (l1port[i].kisslink == -1) continue; #ifdef VANESSA if (l1port[i].kisstype == KISS_VAN) continue; #endif #ifdef AX_IPX if (l1port[i].kisstype == KISS_IPX) continue; #endif #ifdef AX25IP if (l1port[i].kisstype == KISS_AXIP) continue; #endif #ifdef KERNELIF if ( (l1port[i].kisstype == KISS_KAX25) || (l1port[i].kisstype == KISS_KAX25KJD)) continue; #endif #ifdef SIXPACK if (l1port[i].kisstype == KISS_6PACK) continue; #endif if (l1port[i].port_active) if (FD_ISSET(l1port[i].kisslink, &rmask)) if ((len = read(l1port[i].kisslink, buffer, 1024)) != 0) framedata_to_queue(i, buffer, len); } } } /************************************************************************/ /* */ /* Rechner neu starten */ /* */ /************************************************************************/ void reboot_system(void) { exit_all(); sync(); /* CRASH(); */ /*system("/sbin/shutdown -r now");*/ /* Hierher wird man wohl nur kommen, wenn tnn nicht als root gestartet */ /* wurde. Nun gibt es 2 Moeglichkeiten: entweder wir starten von vorne, */ /* weil die Resourcen ja breits freigegeben wurden, oder aber wir */ /* beenden das Programm, weil das ja mehr oder weniger gefordert wurde. */ /* Sinnvoller ist es wohl, wenn wir das Programm verlassen, in der */ /* Hoffnung, dass es danach regulaer von einem Batch erneut gestartet */ /* wird. Das ist jedenfalls besser, als nix zu tun. */ exit(1); } /************************************************************************/ /* */ /* Shell-Befehl - Linux-spezifischer Teil: */ /* Das gewuenschte Programm wird als Hintergrundprozess gestartet. */ /* */ /************************************************************************/ BOOLEAN tnnshell(char *cmdline) { char sysline[MAXPATH + 1]; char cFirstArg[MAXPATH + 1]; char *pFirstArg = NULL; MBHEAD* mbp; struct termios term; /* In TNB-Files darf die interaktive Shell nicht verwendet werden */ if ((tnnb_aktiv == TRUE) && (strlen(cmdline) == 0)) { putmsg("Interactive shell is not allowed in tnb-files !\r"); return (FALSE); } /* Haben wir eine Shell ? */ if (cShell[0] == 0) { putmsg("No shell set, use 'setshell' to set one !\r"); return (FALSE); } /* Initialisieren */ memset(sysline, 0, MAXPATH); memset(cFirstArg, 0, MAXPATH); memset(&term, 0, sizeof(struct termios)); term.c_iflag = ICRNL | IXOFF; term.c_oflag = OPOST | ONOCR; /* ONLCR */ term.c_cflag = CS8 | CREAD | CLOCAL; term.c_lflag = ISIG | ICANON; /* term.c_iflag = IGNCR | IXOFF; term.c_oflag = OPOST | ONLCR | ONLRET | OCRNL; term.c_cflag = CS8 | CREAD | CLOCAL; term.c_lflag = ISIG | ICANON; */ term.c_cc[VINTR] = 3; /* ^C */ term.c_cc[VSUSP] = 26; /* ^Z */ term.c_cc[VQUIT] = 28; term.c_cc[VERASE] = 8; /* ^H */ term.c_cc[VKILL] = 24; /* ^X */ term.c_cc[VEOF] = 4; /* ^D */ strncpy(sysline, cmdline, MAXPATH); sysline[MAXPATH] = NUL; /* Sicher ist sicher ... */ /* Das erste Argument fuer exec bestimmen */ if ((pFirstArg = strrchr(cShell, '/')) == NULL) { pFirstArg = cShell; } else { ++pFirstArg; /* wir wollen das erste Zeichen hinter dem "/" */ } if (strlen(cmdline) == 0) cFirstArg[0] = '-'; strcat(cFirstArg, pFirstArg); /* neue Shell abforken */ if ((userpo->child_pid = forkpty(&userpo->child_fd, NULL, &term, NULL)) == -1) { /* forkpty() nicht moeglich */ userpo->child_pid = 0; putmsg("Can't fork child process !\r"); return(FALSE); } else { if (userpo->child_pid == 0) /* Kind-Prozess (die Shell) */ { if (strlen(cmdline) == 0) { execl(cShell, cFirstArg, NULL); } else { execl(cShell, cFirstArg, "-c", cmdline, NULL); } /* Wenn wir hier ankommen, dann ist wirklich was nicht ok ... */ exit(-1); } else /* Hauptprogramm */ { /* Timeout und Interaktivitaet setzen je nach Shell-Typ */ /* Achtung, Timeout in 100ms-Schritten ! */ if (strlen(cmdline) == 0) { mbp = getmbp(); putprintf(mbp, "Invoking shell, type 'exit' to end your session.\r"); seteom(mbp); userpo->child_timeout = 30000; /* 5 Min. Timeout */ userpo->child_iactive = TRUE; /* interaktive Shell */ } else { userpo->child_timeout = 6000; /* 1 Min. Timeout */ userpo->child_iactive = FALSE; /* keine interaktive Shell */ } userpo->status = US_EXTP; /* externes Programm laeuft */ return(TRUE); } } return(TRUE); } /************************************************************************/ /* */ /* Pruefen, ob Kind-Prozesse beendet sind (vom Sysop gestartete externe */ /* Programme). Bei Zeitueberschreitung wird das Programm mit einer */ /* entsprechenden Fehlermeldung abgebrochen. */ /* */ /************************************************************************/ void shellsrv(void) { pid_t c_pid; MBHEAD* mbp; for (userpo = (USRBLK *) usccpl.head; userpo != (USRBLK *) &usccpl; userpo = (USRBLK *) userpo->unext) { if (userpo->status != US_EXTP) /* externer Prozess aktiv? */ continue; /* nein .. */ if (userpo->child_pid == 0) /* externer Prozess aktiv? */ continue; /* nein .. */ c_pid = waitpid(userpo->child_pid, /* dieser Prozess beendet? */ NULL, WNOHANG); /* Prozess noch nicht beendet */ if (c_pid == 0) /* noch nicht fertig? */ { /* Timeout-Warnung fuer interaktive Shell */ if ((userpo->child_iactive == TRUE) && (userpo->child_timeout <= 6000)) { MBHEAD* mbp; switch (userpo->child_timeout) { case 1000 : case 2000 : case 3000 : case 6000 : mbp = putals("WARNING: Your shell times out in "); putprintf(mbp, "%u seconds !!!\r", (userpo->child_timeout / 100)); seteom(mbp); break; default : break; } } /* Shell-Timeout */ if (--userpo->child_timeout == 0) /* zu lange inaktiv? */ { kill(-(userpo->child_pid), SIGKILL); /* Abbruch (Watchdog) */ c_pid = waitpid(userpo->child_pid, /* Prozess-Status holen */ NULL, 0); /* sonst gips 'n Zombie */ userpo->child_pid = 0; putmsg("SHELL SESSION ABORTED (TIMEOUT)\r"); break; } else { shell_to_user(); continue; } } /* Shell ist geschlossen */ if (userpo->child_fd != -1) { if (c_pid > 0) shell_to_user(); /* Letzte Daten abholen */ /* Shell nun schon geschlossen ? */ if (userpo->child_fd != -1) { close(userpo->child_fd); userpo->child_fd = -1; } } userpo->child_pid = 0; /* Prozess ist fertig */ userpo->child_timeout = 0; userpo->child_iactive = FALSE; userpo->status = US_CCP; /* und ab die Post ... */ mbp = getmbp(); prompt(mbp); seteom(mbp); } } /************************************************************************/ /* */ /* Daten von der Shell abholen und zum User bringen */ /* */ /************************************************************************/ void shell_to_user(void) { fd_set rset; struct timeval tvalue; int i; UBYTE usrtype; /* nur gueltige Descriptoren */ if (userpo->child_fd == -1) return; /* Pruefen, ob die Verbindung noch Daten aufnehmen kann, ist eine L2/L4- */ /* Verbindung zu voll, dann keine neuen Pakete generieren. An die Hostkonsole wird */ /* ungebremst ausgegeben. */ usrtype = g_utyp(userpo->uid); if ( ((usrtype == L2_USER) || (usrtype == L4_USER)) && (((LNKBLK *)g_ulink(userpo->uid))->tosend > 100) ) return; FD_ZERO(&rset); FD_SET(userpo->child_fd, &rset); tvalue.tv_usec = 0; tvalue.tv_sec = 0; /* Daten holen */ if ((i = select((userpo->child_fd + 1), &rset, NULL, NULL, &tvalue)) < 0) { putmsg("ERROR while select()-ing descriptor !!!\r"); close(userpo->child_fd); userpo->child_fd = -1; userpo->child_timeout = 1; /* Aufraeumen macht shellsrv() */ } else { /* Daten Shell -> User */ if ((i > 0) && (FD_ISSET(userpo->child_fd, &rset))) { unsigned char data[8192]; unsigned int uZaehler; ssize_t rd; MBHEAD* mbp; if ((rd = read(userpo->child_fd, data, 8192)) == -1) { /* Ist der abgearbeitete Befehl ohne jegliche Rueckgabe, dann wird der Fehler 5 */ /* erzeugt. Im nicht-interaktiven Modus unterdruecken wir die Fehlermeldung, im */ /* interaktiven Modus wird er normal angezeigt. */ if ((errno == EIO) && (userpo->child_iactive == TRUE)) { mbp = putals(""); putprintf(mbp, "ERROR %u while read()-ing descriptor !!! Shell terminated !\r", errno); seteom(mbp); } close(userpo->child_fd); userpo->child_fd = -1; userpo->child_timeout = 1; /* Aufraeumen macht shellsrv() */ } if (rd > 0) { mbp = getmbp(); for (uZaehler = 0; uZaehler < rd; ++uZaehler) { if (data[uZaehler] == 0x0D) continue; if (data[uZaehler] == 0x0A) { putchr(0x0D, mbp); continue; } putchr(data[uZaehler], mbp); } seteom(mbp); /* Timeout ruecksetzen */ if (userpo->child_iactive == TRUE) userpo->child_timeout = 30000; } } } } /************************************************************************/ /* */ /* User-Eingabe in mhdp verarbeiten */ /* */ /************************************************************************/ BOOLEAN l7tosh(MBHEAD *mhdp) { if (userpo->status == US_EXTP) /* externer Prozess aktiv? */ { if (userpo->child_iactive == FALSE) { dealmb(mhdp); /* Abbruchzeile ignorieren */ userpo->mbhd = NULL; kill(-(userpo->child_pid), SIGKILL); /* Abbruch (Watchdog) */ waitpid(userpo->child_pid, /* Prozess-Status holen */ NULL, 0); /* sonst gips 'n Zombie */ putmsg("SHELL ABORTED by User\r"); userpo->child_pid = 0; /* Prozess ist fertig */ userpo->child_fd = -1; userpo->child_iactive = FALSE; userpo->child_timeout = 0; userpo->status = US_CCP; return(TRUE); } else { struct timeval tvalue; int i; fd_set wset; FD_ZERO(&wset); FD_SET(userpo->child_fd, &wset); tvalue.tv_usec = 0; tvalue.tv_sec = 0; if ((i = select((userpo->child_fd + 1), NULL, &wset, NULL, &tvalue)) < 0) { putmsg("ERROR while select()-ing descriptor !!!)\r"); userpo->child_fd = -1; userpo->child_timeout = 1; /* Aufraeumen macht shellsrv() */ } else { /* Daten User -> Shell */ if ((i > 0) && (FD_ISSET(userpo->child_fd, &wset) && (mhdp->mbgc < mhdp->mbpc))) { unsigned char data[1024]; unsigned int uBufSize = 0; while (mhdp->mbgc < mhdp->mbpc) data[uBufSize++] = getchr(mhdp); /* Daten zum Shell-Child schicken */ if (write(userpo->child_fd, data, uBufSize) < 0) { /* Oh oh, das hat nicht geklappt */ userpo->child_fd = -1; userpo->child_timeout = 1; /* Aufraeumen macht shellsrv() */ } else { /* Timeout ruecksetzen */ if (userpo->child_iactive == TRUE) userpo->child_timeout = 30000; } dealmb(mhdp); userpo->mbhd = NULL; } } } return (TRUE); } return (FALSE); } /************************************************************************/ /* */ /* Filenamen pruefen */ /* */ /************************************************************************/ BOOLEAN good_file_name(const char *file) { if ( (strncmp("/bin/", file, 5) == 0) || (strncmp("/dev/", file, 5) == 0) || (strncmp("/proc/", file, 6) == 0) || (strncmp("/sbin/", file, 6) == 0) || (strncmp("/usr/bin/", file, 9) == 0) || (strncmp("/usr/sbin/", file, 10) == 0) || (strncmp("/usr/local/bin/", file, 16) == 0) || (strncmp("/usr/local/sbin/", file, 17) == 0)) return(FALSE); return(TRUE); } /************************************************************************/ /* */ /* */ /************************************************************************/ void tnnexec(char *file_name) { if (access(file_name, X_OK) == 0) /* nur ausfuehrbares Programm */ { exit_all(); /* Resourcen freigeben */ execl(file_name, NULL, NULL); /* Programm starten */ /* Hierher darf man eigentlich nicht kommen! Daher verlassen wir das */ /* Programm in der Hoffnung, dass es danach regulaer von einem Batch */ /* erneut gestartet wird. */ exit(1); } } /************************************************************************/ /* */ /* */ /************************************************************************/ void init_console(void) { #ifdef L1TCPIP /* Interface Initialisieren. */ InitIFC(); #endif /* L1TCPIP */ if (console_type == CONS_TERM_DO_SETUP) { setvbuf(stdout, NULL, _IONBF, 0); /* Ausgabe ungepuffert */ tcgetattr(fileno(stdin), &oconin_termios); tcgetattr(fileno(stdout), &oconout_termios); nconin_termios = oconin_termios; nconin_termios.c_cc[VTIME] = 0; nconin_termios.c_cc[VMIN] = 1; nconin_termios.c_cc[VSTART] = -1; nconin_termios.c_cc[VSTOP] = -1; nconin_termios.c_iflag = IGNBRK; nconin_termios.c_oflag = OPOST|ONLCR; nconin_termios.c_lflag = 0; nconin_termios.c_cflag = (CS8|CREAD|CLOCAL); tcsetattr(fileno(stdin), TCSADRAIN, &nconin_termios); nconout_termios = oconout_termios; nconout_termios.c_cc[VTIME] = 0; nconout_termios.c_cc[VMIN] = 1; nconout_termios.c_cc[VSTART] = -1; nconout_termios.c_cc[VSTOP] = -1; nconout_termios.c_iflag = IGNBRK|ICRNL; nconout_termios.c_oflag = OPOST|ONLCR|ONLRET|OCRNL; nconout_termios.c_lflag = 0; nconout_termios.c_cflag = (CS8|CREAD|CLOCAL); tcsetattr(fileno(stdout), TCSAFLUSH, &nconout_termios); consfile = stdout; console_type = CONS_TERM_RUNNING; } else consfile = NULL; hostq_root = NULL; hostq_last = NULL; hostq_len = 0; } /************************************************************************/ /* */ /* */ /************************************************************************/ void exit_console(void) { struct hostqueue *hostq_ptr; while (hostq_root != NULL) { hostq_ptr = hostq_root; hostq_root = hostq_ptr->next; free(hostq_ptr); } hostq_last = NULL; hostq_len = 0; exit_proc(); if (console_type != CONS_TERM_RUNNING) return; tcsetattr(1, TCSADRAIN, &oconout_termios); tcsetattr(0, TCSADRAIN, &oconin_termios); console_type = CONS_NO_CONSOLE; } /************************************************************************/ /* */ /* */ /************************************************************************/ static void alloc_hostqbuf(void) { struct hostqueue *hostq_ptr; hostq_ptr = (struct hostqueue *) malloc(sizeof(struct hostqueue)); if (hostq_ptr == NULL) { exit_all(); exit(1); } hostq_ptr->first = 0; hostq_ptr->last = 0; hostq_ptr->next = NULL; if (hostq_root == NULL) { hostq_root = hostq_ptr; } else { hostq_last->next = hostq_ptr; hostq_last = hostq_ptr; } hostq_last = hostq_ptr; } /* put one character in host-queue */ static void puthostq(char ch) { struct hostqueue *hostq_ptr; if (hostq_root == NULL) alloc_hostqbuf(); hostq_ptr = hostq_last; if (hostq_ptr->last >= HOSTQ_BUFLEN) { alloc_hostqbuf(); hostq_ptr = hostq_last; } hostq_ptr->buffer[hostq_ptr->last] = ch; hostq_ptr->last++; hostq_len++; } /* get one character out of host-queue */ static char gethostq(void) { struct hostqueue *hostq_ptr; char ch; if ((hostq_len == 0) || (hostq_root == NULL)) /* sanity check */ return(0); hostq_ptr = hostq_root; ch = hostq_ptr->buffer[hostq_ptr->first]; hostq_ptr->first++; hostq_len--; if ( (hostq_ptr->first == hostq_ptr->last) || (hostq_ptr->first == HOSTQ_BUFLEN)) { if (hostq_ptr->next == NULL) { hostq_root = NULL; hostq_last = NULL; } else hostq_root = hostq_ptr->next; free(hostq_ptr); } return(ch); } /************************************************************************/ /* */ /* */ /************************************************************************/ void hputc(char c) { int res; if (tnb_ch) { if (consfile != NULL) fputc(c, consfile); return; } switch (console_type) { case CONS_SOCKET_CONNECTED: res = write(consockfd, &c, 1); if (res == -1) { close(consockfd); consockfd = -1; console_type = CONS_SOCKET_WAITING; } break; case CONS_TERM_RUNNING: if ((c == '\n') || (c == '\r')) putchar(LF); else putchar(c); break; default: break; } } /* return if character available */ BOOLEAN ishget(void) { return(hostq_len != 0); } /* return if output to console is stopped */ BOOLEAN ishput(void) { return(FALSE); } /* get one character from console */ char hgetc(void) { char ch = gethostq(); if (console_type == CONS_TERM_RUNNING) if (ch == LF) ch = CR; return (ch); } /* put received characters in hostbuffer */ static void host_to_queue(char *buffer, int len) { char *bufptr; register int i = 0; bufptr = buffer; while (i < len) { puthostq(*bufptr); ++i; bufptr++; } } /************************************************************************/ /* */ /* */ /************************************************************************/ BOOLEAN init_hardware(int argc, char *argv[]) { char *pEnvShell = NULL; int scanned = 1; umask(0); time(&sys_time); /* Kommandozeilenparameter auswerten */ /* Den Verbose-Modus schon hier feststellen */ while (scanned < argc) { /* Parameter "-v" (ausfuehrlichere Meldungen) */ if (strcmp(argv[scanned], "-v") == 0) { bVerbose = TRUE; } ++scanned; } VMSG("--- Verbose logging started !\n"); /* Shell loeschen */ memset(cShell, 0, sizeof(cShell)); VMSG("--- Determining shell-program ...\n"); /* Shell aus dem Environment holen */ if ((pEnvShell = getenv("SHELL")) == NULL) fprintf(stderr, "Warning: SHELL not set, can't use external programs !!!\n"); else { /* Shell kopieren */ strncpy(cShell, pEnvShell, sizeof(cShell)); /* und sicherheitshalber abschliessen */ cShell[sizeof(cShell)] = 0; VMSG("--- Shell is '%s'\n", cShell); } VMSG("--- Reading ini-file ...\n"); if (read_init_file(argc, argv)) return(TRUE); VMSG("--- Entering pid-file checks ...\n"); if (!init_proc()) exit(1); /* if (tnn_errfile[0] != NUL) { } */ VMSG("--- Allocating mem for %ld buffers ...\n", tnn_buffers); RAMBOT = (char *)malloc(tnn_buffers * sizeof(MAX_BUFFER)); RAMTOP = RAMBOT + tnn_buffers * sizeof(MAX_BUFFER); if (RAMBOT == NULL) { VMSG("!!! Allocation mem for %ld buffers failed, trying to allocate for %u buffers now ...\n", tnn_buffers, TNN_BUFFERS); RAMBOT = (char *)malloc(TNN_BUFFERS * sizeof(MAX_BUFFER)); RAMTOP = RAMBOT + TNN_BUFFERS * sizeof(MAX_BUFFER); if (RAMBOT == NULL) { fprintf(stderr, "malloc for buffers failed\n"); exit(1); } else tnn_buffers = TNN_BUFFERS; } if (kiss_active) { VMSG("--- Initializing KISS-interfaces ...\n"); if (init_kisslink()) { free(RAMBOT); exit(1); } } if (console_type == CONS_SOCKET_DO_SETUP) { VMSG("--- Initializing UNIX-socket interface ...\n"); if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { fprintf(stderr, "Can't open socket !\n"); fprintf(stderr, "Error %u : %s\n", errno, strerror(errno)); fprintf(stderr, "Exiting.\n"); close(sockfd); free(RAMBOT); if (kiss_active) exit_kisslink(); exit(1); } memset((char *) &serv_addr, 0, sizeof(serv_addr)); serv_addr.sun_family = AF_UNIX; strcpy(serv_addr.sun_path, tnn_socket); servlen = strlen(serv_addr.sun_path) + sizeof(serv_addr.sun_family); unlink(serv_addr.sun_path); if (bind(sockfd, (struct sockaddr *) &serv_addr, servlen) < 0) { fprintf(stderr, "Can't bind socket !\n"); fprintf(stderr, "Error %u : %s\n", errno, strerror(errno)); fprintf(stderr, "Exiting.\n"); close(sockfd); free(RAMBOT); if (kiss_active) exit_kisslink(); exit(1); } if (listen(sockfd, 5) < 0) { fprintf(stderr, "Can't listen to socket !\n"); fprintf(stderr, "Error %u : %s\n", errno, strerror(errno)); fprintf(stderr, "Exiting.\n"); free(RAMBOT); if (kiss_active) exit_kisslink(); exit(1); } console_type = CONS_SOCKET_WAITING; if (getppid() != 1) { if (fork() != 0) { /* Parent */ exit_proc(); /* eigenes PID-File loeschen */ exit(0); } else { sleep(1); /* warten, dass Parent sein PID-File loescht */ /* Child */ if (!init_proc()) exit(1); } } } #ifndef NO_WATCHDOG VMSG("--- Initializing watchdog ...\n"); watchdog_init(); #endif VMSG("--- Installing signal-handlers ...\n"); #ifdef DEBUG_MODUS signal(SIGSEGV, sigsegv); signal(SIGTERM, sigterm); #endif signal(SIGHUP, SIG_IGN); signal(SIGTSTP, SIG_IGN); signal(SIGTTIN, SIG_IGN); signal(SIGTTOU, SIG_IGN); signal(SIGPIPE, SIG_IGN); gettimeofday(&tv, &tz); tv_old = tv; return(FALSE); } #ifndef NO_WATCHDOG /************************************************************************/ /* */ /* Watchdog - ein vom TNN-Hauptprogramm unabhaengiger Prozess muss */ /* regelmaessig vom Hauptprogramm Daten erhalten. Bleiben diese Daten */ /* laenger als 60s aus, wird TNN beendet. */ /* */ /************************************************************************/ static void watchdog_init(void) { pid_t pid; time_t wdzeit; time_t zeit; int num; int status; char buf[1000]; VMSG("--- Initializing watchdog ...\n"); if (pipe(watch_dog) < 0) { fprintf(stderr, "Error %u while creating watchdog's pipe: %s\n", errno, strerror(errno)); fprintf(stderr, "Exiting.\n"); exit(1); } /* Descriptoren auf non-blocking einstellen */ num = fcntl(watch_dog[0], F_GETFL, 0); num |= O_NONBLOCK; fcntl(watch_dog[0], F_SETFL, num); num = fcntl(watch_dog[1], F_GETFL, 0); num |= O_NONBLOCK; fcntl(watch_dog[1], F_SETFL, num); /* Forken */ if ((pid = fork()) < 0) { fprintf(stderr, "Error %u while fork()-ing in watchdog: %s\n", errno, strerror(errno)); fprintf(stderr, "Exiting.\n"); exit(1); } else { /* Na wer sind wir denn ... */ if (pid == 0) { /* wir sind Child (das Hauptprogramm) */ wdpid[0] = getpid(); close(watch_dog[0]); sleep(1); return; } else { /* und wir sind Parent (der Watchdog) */ wdpid[0] = pid; /* Child */ wdpid[1] = getpid(); /* Parent */ close(watch_dog[1]); VMSG(" +-> main loop has pid %u\n", wdpid[0]); VMSG(" +-> watchdog has pid %u\n", wdpid[1]); signal(SIGHUP, SIG_IGN); signal(SIGTSTP, SIG_IGN); signal(SIGTTIN, SIG_IGN); signal(SIGTTOU, SIG_IGN); signal(SIGSEGV, sigsegv); time(&zeit); time(&wdzeit); LOOP { /* Hat sich das Child beendet ? */ if (waitpid(wdpid[0], &status, WNOHANG)) { /* Child hat sich beendet */ /* Es gibt nichts mehr zu killen, pid wegwerfen */ wdpid[0] = 0; VMSG("!!! watchdog: child has exited !\n"); if (bVerbose == TRUE) { if (WIFEXITED(status)) VMSG(" +-> child exited with code %u\n", WEXITSTATUS(status)); if (WIFSIGNALED(status)) { VMSG(" +-> child exited because of signal %u\n", WTERMSIG(status)); if (WCOREDUMP(status)) VMSG(" +-> child wrote a core dump !\n"); } } break; } /* Child sollte laufen, dann schauen, ob es was geschickt hat */ num = read(watch_dog[0], &buf, sizeof(buf)); if ( (num == 0) /* schreibendes Ende der Pipe geschlossen */ || ((num < 0) && (errno != EWOULDBLOCK))) /* sonstige Fehler */ break; if (num > 0) { time(&wdzeit); continue; } time(&zeit); if ((zeit - wdzeit) > 60) break; sleep(1); } time(&wdzeit); close(watch_dog[0]); if (wdpid[0] != 0) { VMSG("!!! watchdog: child has exited abnormally !\n"); kill(-wdpid[0], SIGSEGV); /* Falls aus irgendeinem Grund SIGSEGV nicht zum Programmende fuehrt, */ /* kommt ein SIGKILL hinterher. Damit wird sichergestellt, dass der */ /* Childprozess beendet wird. */ sleep(1); kill(-wdpid[0], SIGKILL); } /* Hauptprogramm beenden */ exit(0); } } } #endif /************************************************************************/ /* */ /* */ /************************************************************************/ void exit_hardware(void) { free(RAMBOT); if (kiss_active) exit_kisslink(); } #ifdef DEBUG_MODUS /************************************************************************/ /* Signalbehandlungsfunktion fuer das Signal SIGTERM */ /************************************************************************/ static void sigterm(int signo) { signal(SIGTERM, SIG_IGN); printf("sigterm\n"); quit_program(-1); } void sigsegv(int signo) { signal(SIGSEGV, SIG_IGN); #ifdef DEBUG_MODUS printf("\nTheNetNode verursachte einen unbekannten Systemfehler!!!\n"); printf("Letzte Funktion war: %s\n", lastfunc); #endif quit_program(-1); } #endif /************************************************************************/ /* */ /* */ /************************************************************************/ int exit_all(void) { exit_mh(); /* MH-Liste sichern */ save_stat(); save_configuration(); personalmanager(SAVE, NULL, NULL); /* Pers. Daten fuer Convers */ /* noch laufende Shells killen */ for (userpo = (USRBLK *) usccpl.head; userpo != (USRBLK *) &usccpl; userpo = (USRBLK *) userpo->unext) { if (userpo->status != US_EXTP) /* externer Prozess aktiv? */ continue; kill(-(userpo->child_pid), SIGKILL); /* Abbruch */ waitpid(userpo->child_pid, NULL, 0); /* Prozess-Status holen */ } /* Buffer freigeben */ free(RAMBOT); /* Ab hier stehen keine Buffer mehr zur Verfuegung, alles was mit Buffern */ /* zu tun hat, gibt nun nen Segfault ! */ if (console_type == CONS_SOCKET_CONNECTED) { close(consockfd); consockfd = -1; console_type = CONS_SOCKET_WAITING; } if (console_type == CONS_SOCKET_WAITING) { close(sockfd); sockfd = -1; } else exit_console(); if (kiss_active) exit_kisslink(); exit_proc(); printf("\r\n"); return(0); } /************************************************************************/ /* */ /* Systembelastung durch TNN berechnen */ /* diese Routine muss alle 10 Sekunden aufgerufen werden */ /* */ /************************************************************************/ void calculate_load(void) { static long clktck = 0; static int oldtime; static float oldjiffies[2]; static pid_t tnnpid; FILE *fp; int utime; int stime; register int gtime; char proc_name[80]; /* im ersten Durchlauf alles aufraeumen */ if (clktck == 0) { clktck = sysconf(_SC_CLK_TCK); tnnpid = getpid(); oldjiffies[0] = 0; oldjiffies[1] = 0; oldtime = 0; load[0] = 0; load[1] = 0; load[2] = 0; } sprintf(proc_name , "/proc/%d/stat", tnnpid); /* stat-Datei von TNN oeffnen */ if ((fp = fopen(proc_name, "r"))) { fscanf(fp, "%*d %*s %*c %*d %*d %*d %*d " "%*d %*u %*u %*u %*u %*u %d %d", &utime, &stime); fclose(fp); /* User- & System-Time addieren und in Sekunden umrechnen */ gtime = (utime + stime) - oldtime; /* die letzten Zeiten fuer neue Berechnung merken */ oldtime = utime + stime; /* Prozente ausrechnen */ tnn_load = ((gtime * 100) / (10 * clktck)); } else tnn_load = -1; /* Fehler ! */ /* Systemload aus /proc/loadavg lesen */ if ((fp = fopen("/proc/loadavg", "r"))) { fscanf(fp, "%f %f %f %*s %*s", &load[0], &load[1], &load[2]); fclose(fp); } else load[0] = -1; /* gesamte Systembelastung im letzten Messintervall errechnen */ if ((fp = fopen("/proc/uptime", "r"))) { float actjiffies[2]; fscanf(fp, "%f %f", &actjiffies[0], &actjiffies[1]); fclose(fp); if (oldjiffies[0] != 0 && oldjiffies[1] != 0) sys_load = 100 * (1 - ((actjiffies[1] - oldjiffies[1]) / (actjiffies[0] - oldjiffies[0]))); oldjiffies[0] = actjiffies[0]; oldjiffies[1] = actjiffies[1]; } else sys_load = -1; } /************************************************************************/ /* */ /* Load-Werte ausgeben */ /* */ /************************************************************************/ void print_load(MBHEAD *mbp) { ULONG user = 0; ULONG sys = 0; struct rusage sysusage; if (tnn_load >= 0) putprintf(mbp, "\r TNN-Load: %i%%", tnn_load); else putprintf(mbp, "\r TNN-Load: can't read from /proc !"); if (sys_load >= 0) putprintf(mbp, "\r Sysload: %.2f%%", sys_load); else putprintf(mbp, "\r Sysload: can't read from /proc !"); /* IO-Last ausgeben (siehe auch man proc) */ if (load[0] >= 0) putprintf(mbp, "\r Loadavg: %.2f %.2f %.2f", load[0], load[1], load[2]); else /* mhh...Kernel ohne /proc-System compiliert ? */ putprintf(mbp, "\r Loadavg: can't read from /proc/loadavg !"); /* verbrauchte Systemzeit ausgeben, wenn moeglich */ if (getrusage(RUSAGE_SELF, &sysusage) == 0) { user = (ULONG)sysusage.ru_utime.tv_sec * 1000L + sysusage.ru_utime.tv_usec / 1000L; sys = (ULONG)sysusage.ru_stime.tv_sec * 1000L + sysusage.ru_stime.tv_usec / 1000L; if (getrusage(RUSAGE_CHILDREN, &sysusage) == 0) { user += (ULONG) sysusage.ru_utime.tv_sec * 1000L + sysusage.ru_utime.tv_usec / 1000L; sys += (ULONG) sysusage.ru_stime.tv_sec * 1000L + sysusage.ru_stime.tv_usec / 1000L; } if (user > 1000000L || sys > 1000000L) putprintf(mbp, "\r CPU time used: user %lus, system %lus", user / 1000L, sys / 1000L); else putprintf(mbp, "\r CPU time used: user %lums, system %lums", user, sys); } } /* ermoeglicht das Setzen einer anderen Shell */ void ccpsetshell(void) { MBHEAD *mbp; char cBuf[512]; const size_t tBufSize = sizeof(cBuf); register size_t tCmdlen = 0; struct stat tFileStat; /* Sysop will aendern und noch was in der Zeile da ? */ if (issyso()) { /* Sind noch Usereingaben da ? */ if (skipsp(&clicnt, &clipoi)) { /* Frischer Buffer */ memset(cBuf, 0, tBufSize); /* Zeile lesen */ for (; tCmdlen < tBufSize; ++tCmdlen) { if ((!clicnt) || (*clipoi == ' ')) break; clicnt--; cBuf[tCmdlen] = (*clipoi++); } } else /* Syntax anzeigen */ { mbp = putals("usage:\r'setshell /path/to/shell' to set a new shell\r"); putprintf(mbp, "'setshell ?' to get the current setting\r"); prompt(mbp); seteom(mbp); return; } } else /* kein Sysop */ { invmsg(); return; } /* Aktuelle Einstellung anzeigen */ if ((tCmdlen == 1) && (cBuf[0] == '?')) { mbp = putals(""); putprintf(mbp, "current shell is : %s\r", cShell); prompt(mbp); seteom(mbp); return; } /* Neue Shell grob ueberpruefen */ if (access(cBuf, F_OK) == -1) /* gibt es das File ? */ { mbp = putals(""); putprintf(mbp, "error accessing file '%s': %s\r", cBuf, strerror(errno)); prompt(mbp); seteom(mbp); return; } /* Nur regulaere Dateien und Links erlaubt */ if (stat(cBuf, &tFileStat) == -1) { mbp = putals(""); putprintf(mbp, "can't get stats for '%s': %s\r", cBuf, strerror(errno)); prompt(mbp); seteom(mbp); return; } else { /* Pruefung */ if ( ((tFileStat.st_mode & S_IFDIR) == S_IFDIR) /* directory */ || ((tFileStat.st_mode & S_IFSOCK) == S_IFSOCK) /* socket */ || ((tFileStat.st_mode & S_IFBLK) == S_IFBLK) /* block device */ || ((tFileStat.st_mode & S_IFCHR) == S_IFCHR) /* character device */ || ((tFileStat.st_mode & S_IFIFO) == S_IFIFO) /* fifo */ ) { mbp = putals(""); putprintf(mbp, "'%s' is not a file, can't use !\r", cBuf); prompt(mbp); seteom(mbp); return; } } /* Ausfuehrbar muss es auch noch sein */ if (access(cBuf, X_OK) == -1) /* nur ausfuehrbares Programm */ { mbp = putals(""); putprintf(mbp, "file '%s' is NOT marked executable, not accepted !!!\r", cBuf); prompt(mbp); seteom(mbp); return; } /* Uebernehmen */ strncpy(cShell, cBuf, min(sizeof(cShell), tBufSize)); mbp = putals(""); putprintf(mbp, "shell changed to : %s\r", cShell); prompt(mbp); seteom(mbp); return; } #ifdef L1TCPIP /* Pruefe auf TCPIP-Port's */ int CheckPortTCP(int port) { switch(kissmode(port)) { #ifdef L1TELNET case KISS_TELNET : return(TRUE); #endif /* L1TELNET */ #ifdef L1HTTPD case KISS_HTTPD : return(TRUE); #endif /* L1HTTPD */ #ifdef L1IPCONV case KISS_IPCONV : return(TRUE); #endif /* L1IPCONV */ #ifdef L1IRC case KISS_IRC : return(TRUE); #endif /* L1IRC */ default : return(FALSE); } return(FALSE); } #endif /* L1TCPIP */ /* Dummy-Funktionen */ void init_timer(void) {} void DIinc(void) {} void decEI(void) {} void exit_timer(void) {} void init_rs232(void) {} /* End of os/linux/linux.c */