/*---------------------------------------------------------------
                             deepfile

 Il programma stampa tutte le informazioni relative al file forni-
 to come parametro.  L'unica informazione che non si riesce ad ot-
 tenere correttamente e' quella relativa ai link.


      Messaggistica

 group xxxx error
      il gruppo xxxx e' ignoto

 stat error
      la system call e' errata

 uid xxxx error
      l'userid xxxx e' ignoto

 uso: deepfile file
      il programma va chiamato con 1 argomento
---------------------------------------------------------------*/

#include <grp.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>

int main (int argc, char **argv)
{
  void          prtdate (time_t);
  void          prtmask (unsigned long);
  void          prtsize (long);
  void          prttype (unsigned long);
  struct group  *groupdata;
  struct passwd *pwdata;
  struct stat   fileinfo;

  if (argc != 2)
    {
      fprintf (stderr, "uso: %s file|directory|link\n", argv [0]);
      exit (EXIT_FAILURE);
    }
  if (stat (argv [1], &fileinfo) < 0)
    {
      fprintf (stderr, "stat error\n");
      exit (EXIT_FAILURE);
    }
  if ((groupdata = getgrgid (fileinfo.st_gid)) == NULL)
    {
      fprintf (stderr, "group %d error\n", fileinfo.st_gid);
      exit (EXIT_FAILURE);
    }
  if ((pwdata = getpwuid (fileinfo.st_uid)) == NULL)
    {
      fprintf (stderr, "uid %d error\n", fileinfo.st_uid);
      exit (EXIT_FAILURE);
    }
  printf ("\t%s\n", argv [1]);
  printf ("accesso   "), prtdate (fileinfo.st_atime);
  printf ("creazione "), prtdate (fileinfo.st_ctime);
  printf ("modifica  "), prtdate (fileinfo.st_mtime);
  printf ("type      "), prttype (fileinfo.st_mode);
  printf ("mode      "), prtmask (fileinfo.st_mode);
  printf ("size      "), prtsize ((long) fileinfo.st_size);
  printf ("i-node    %d\n", (int) fileinfo.st_ino);
  printf ("ownership %d (%s) %d (%s)\n",
    fileinfo.st_uid, pwdata->pw_name,
    fileinfo.st_gid, groupdata->gr_name);
  printf ("# link    %d\n", (int) fileinfo.st_nlink);
  exit (EXIT_SUCCESS);
}

void prtdate (time_t filesec)
{
  char *nome [] = 
    {
      "Jan", "Feb", "Mar", "Apr", "May", "Jun",
      "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
    };
  struct tm *filetime;

  filetime = localtime (&filesec);
  printf ("%02d %s %d %02d:%02d:%02d\n",
    filetime->tm_mday, nome [filetime->tm_mon], filetime->tm_year + 1900, 
    filetime->tm_hour, filetime->tm_min, filetime->tm_sec);
}

void prtmask (unsigned long mode)
{
  char  m1 [] = "xrw", *m2 [] = {"setuid ", " setgid", " sticky"};
  int   i,
        mask1 [] =
          {S_IRUSR, S_IWUSR, S_IXUSR,
           S_IRGRP, S_IWGRP, S_IXGRP,
           S_IROTH, S_IWOTH, S_IXOTH},
        mask2 [] = {S_ISUID, S_ISGID, S_ISVTX};
  for (i = 0; i < sizeof mask1 / sizeof mask1 [0]; i++)
    if (mode & mask1 [i])
      printf ("%c", m1 [(i+1)%3]);
    else
      printf ("-");
  printf (" (");
  for (i = 0; i < sizeof mask2 / sizeof mask2 [0]; i++)
    if (mode & mask2 [i])
      printf ("%s ON", m2 [i]);
    else
      printf ("%s OFF", m2 [i]);
  printf (")\n");
}

void prtsize (long len)
{
  char  *s1, tmp [15];
  int   i, j, k;

  s1 = tmp;
  sprintf (tmp, "%ld", len);
  j = strlen (tmp);
  i = j / 3;
  k = j % 3;
  if (k)
    i++;
  else
    k = 3;
  for (j = 0; j < i; j++)
    {
      if (j)
        printf (".");
      printf ("%*.*s", k, k, s1);
      s1 += k;
      k = 3;
    }
  printf ("\n");
}

void prttype (unsigned long type)
{
  if (S_ISREG (type))
    { printf ("regular file\n"); return; }
  if (S_ISDIR (type))
    { printf ("directory\n");    return; }
/* peccato che non funzioni */
  if (S_ISLNK (type))
    { printf ("soft link\n");    return; }
  if (S_ISBLK (type))
    { printf ("block device\n"); return; }
  if (S_ISCHR (type))
    { printf ("char device\n");  return; }
  if (S_ISFIFO (type))
    { printf ("FIFO\n");         return; }
  if (S_ISSOCK (type))
    { printf ("socket\n");       return; }
}