/*
 *  Machtype: determine machine type & display type
 *
 * RCS Info
 *	$Id: machtype_lin.c,v 1.6 1997/11/25 22:18:51 svalente Exp $
 *	$Locker:  $
 *
 *   Ported to Linux by Sal Valente <svalente@mit.edu>
 *
 */

#define _POSIX_SOURCE 1

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/utsname.h>
#include <sys/wait.h>

int verbose = 0;

void usage (char *name);
void do_cpu (void);
void do_dpy (void);
void do_disk (void);
void do_memory (void);

int main(int argc, char *argv[])
{
    int i;
    int cpuflg = 0, dpyflg = 0, raflg = 0, memflg = 0;
    int doathenaV = 0;
    int dosyspV = 0;
    int dolocalV = 0;
    int dobosN = 0;
    int dobosV = 0;
    int dosysnam = 0;
    FILE *f;

    for (i = 1; i < argc; i++) {
	if (argv[i][0] != '-')
	  usage(argv[0]);

	switch (argv[i][1]) {
	case 'c':
	    cpuflg++;
	    break;
	case 'd':
	    dpyflg++;
	    break;
	case 'r':
	    raflg++;
	    break;
	case 'M':
	    memflg++;
	    break;
	case 'v':
	    verbose++;
	    break;
        case 'A':
	    doathenaV = 1;
	    break;
        case 'P':
	    dosyspV = 1;
	    break;
        case 'L':
	    dolocalV = 1;
	    break;
	case 'N':
	    dobosN = 1;
	    break;
	case 'E':
	    dobosV = 1;
	    break;
	case 'S':
	    dosysnam = 1;
	    break;
	default:
	    usage(argv[0]);
	}
    }


    if ((argc == 1) || ((argc == 2) && verbose)) {
#if defined(i386)
      puts("linux");
#elif defined(sparc)
	puts("sparc-linux");
#elif defined(__alpha__)
	puts("linux-axp");
#elif defined(__powerpc__)
	puts("linux-ppc");
#else
	puts("linux-unknown");
#endif
      exit(0);
    }

	/* Print out version of Athena machtype compiled against */
    if (doathenaV) {
#ifdef ATHMAJV
      if (verbose)
	printf("Machtype version: %s.%s\n",ATHMAJV,ATHMINV);
      else
	printf("%s.%s\n",ATHMAJV,ATHMINV);
#else
      puts ("???");
#endif
    }

    /* Print out version of attached packs */
    if (dosyspV) {
      char buf[256],rvd_version[256], *p;
      if ((f = fopen("/srvd/.rvdinfo","r")) == NULL) {
	printf("Syspack information unavailable\n");
      } else {
	fgets(buf,256,f);
	fclose(f);
	
	/* If it is verbose, give the whole line, else just the vers # */
	if (verbose) {
	  printf(buf);
	} else {
	  p = strchr(buf,' '); /* skip "Athena" */
	  p = strchr(p+1,' '); /* skip "RVD" */
	  p = strchr(p+1,' '); /* Skip "RSAIX" */
	  p = strchr(p+1,' '); /* skip "version" */
	  strncpy(rvd_version,p+1,256);
	  p = strchr(rvd_version,' ');
	  *p = '\0';
	  printf("%s\n",rvd_version);
	}
      }
    }
	
    /* Print out local version from /etc/athena/version */
    if (dolocalV) {
      char buf[256],loc_version[256], *p;
      if ((f = fopen("/etc/athena/version","r")) == NULL) {
	printf("Local version information unavailable\n");
      } else {
	fseek(f,-100,2);
	while (fgets(buf,256,f) != NULL)
	  ;
	fclose(f);
	
	if (verbose) {
	  printf(buf);
	} else {
	  p = strchr(buf,' '); /* skip "Athena" */
	  p = strchr(p+1,' '); /* skip "Workstation/Server" */
	  p = strchr(p+1,' '); /* Skip "RSAIX" */
	  p = strchr(p+1,' '); /* skip "version" */
	  strncpy(loc_version,p+1,256);
	  p = strchr(loc_version,' ');
	  *p = '\0';
	  printf("%s\n",loc_version);
	}
      }
    }

    /* Print out vendor OS name */
    if (dobosN) {
	struct utsname uts;
	if (uname (&uts) < 0) puts ("???");
	else {
	    if (verbose) printf ("%s %s\n", uts.sysname, uts.release);
	    else puts (uts.sysname);
	}
    }

    /* Print out vendor OS version */
    if (dobosV) {
	struct utsname uts;
	if (uname (&uts) < 0) puts ("???");
	else puts (uts.release);
    }

    if (dosysnam) {
#ifdef ATHSYS
	puts(ATHSYS);
#else
	puts("???");
#endif
    }

    if (cpuflg)
	do_cpu();
    if (dpyflg)
	do_dpy();
    if (raflg)
	do_disk();
    if (memflg)
	do_memory();
    exit(0);
}



void usage(char *name)
{
    fprintf(stderr, "usage: %s [-c] [-d] [-r] [-M] [-v] [-A] [-P] ",name);
    fprintf(stderr, "[-L] [-N] [-E] [-S]\n");
    exit(1);
}


void do_cpu(void)
{
    /* for linux: simply print i386 or i486 or i586 */
    struct utsname uts;

    if (uname (&uts) < 0) puts ("???");
    else puts (uts.machine);
}

void do_dpy(void)
{
    /*
     *  Some ideas:
     *  Check the DISPLAY environment variable to see if X is running.
     *  If it is, run "xdpyinfo" and extract some interesting data.
     *  Or, check which X server /usr/X11/bin/X points to.
     *  If X is not running, check the TERM environment variable.
     *  Or, output some stty-like information.
     */
    puts ("linux");
}

void do_disk(void)
{
    /*  the floppys are autodetected at boot-up.
	i'm using "dmesg" to read the autodetection message.
	there _must_ be a better way to do this!  */

    int status, piped[2], found;
    char buf[256], *dev, *size, *next;
    FILE *fp;

    found = 0;
    /*  create a pipe.  write to piped[1], read from piped[0].  */
    if (pipe (piped) < 0) {
	if (verbose) perror ("pipe");
	puts ("???");
	return;
    }
    switch (fork ()){
    case -1:
	if (verbose) perror ("fork");
	break;
    case 0:
	close (piped[0]);
	dup2 (piped[1], STDOUT_FILENO);
	dup2 (piped[1], STDERR_FILENO);
	close (piped[1]);
	execl ("/bin/dmesg", "dmesg", NULL);
	exit (-1);
    default:
	close (piped[1]);
	fp = fdopen (piped[0], "r");
	while (fgets (buf, sizeof (buf), fp) != NULL) {
	    if (strncmp (buf, "Floppy drive(s): ", 17))
		continue;
	    if (buf[strlen (buf) - 1] == '\n')
		buf[strlen (buf) - 1] = 0;
	    found = 1;
	    /* format: fd0 is 1.44M, fd1 is 1.2M */
	    dev = buf + 17;
	    while (1) {
		next = strchr (dev, ' ');
		*next = 0;
		size = strchr (next + 1, ' ') + 1;
		next = strchr (size, ',');
		if (next) *next = 0;
		printf ("%s: %s\n", dev, size);
		if (! next) break;
		dev = next + 2;
	    }
	    break;
	}
	fclose (fp);
	close (piped[0]);
	wait (&status);
	break;
    }
    if (! found) puts ("???");
}

void do_memory (void)
{
    FILE *fp;
    char buf[80];
    int mem, swap;

    mem = swap = 0;
    fp = fopen ("/proc/meminfo", "r");
    if (! fp) {
	if (verbose) perror ("/proc/meminfo");
	puts ("???");
	return;
    }
    while (fgets (buf, sizeof (buf), fp) != NULL) {
	if (! strncmp (buf, "Mem:", 4))
	    mem = atoi (buf + 4);
	if (! strncmp (buf, "Swap:", 5))
	    swap = atoi (buf + 5);
    }
    fclose (fp);
    if (mem > 0) {
	if (verbose) {
	    printf ("Memory: %dk", (mem / 1024));
	    if (swap > 0) printf (", %dk swap", (swap / 1024));
	    printf ("\n");
	}
	else printf ("%d\n", (mem / 1024));
    }
    else puts ("???");
}
