[comp.os.minix] A mkproto

cagney@chook.ua.oz (Andrew Cagney - aka Noid) (11/11/89)

Below is a version of mkproto (make prototype file) written earlier this year.
It works on both unix (SUNOS, UMAX) and MINIX. (For minix modify the Makefile
to not define -DUNIX). This tool avoids the hassles of creating prototype
files by hand.

BTW Is any one interrested in modifying mkfs so that the line below works?
	mkproto -b20000 -s /user | mkfs /dev/hd1 -
    :-)    

					Andrew Cagney

------------------------------------------------------------- Chomp
echo x - Makefile
sed '/^X/s///' > Makefile << '/'
X
XBIN= /usr/etc
XO=s
X
X
Xmkproto : mkproto.c
X	cc -DUNIX mkproto.c -o mkproto
X
Xall : mkproto mkproto.doc
X
Xinstall : mkproto
X	rm -rf $(BIN)/mkproto
X	cp mkproto $(BIN)
X
Xmkproto.doc : mkproto.man
X	nroff -man mkproto.man | col -b > mkproto.doc
X
Xclean : 
X	rm -rf mkproto mkproto.$(O)
X
/
echo x - mkproto.c
sed '/^X/s///' > mkproto.c << '/'
X/*
X * Mkproto: create a prototype file
X *
X */
X
X#ifdef __STDC__
X#define _PROTO(p)    p
X#else
X#define _PROTO(p)    ()
X#endif
X
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#ifdef UNIX
X#include <sys/dir.h>
X#else
X#include <dirent.h>
X#endif 
X
X/* for getopt */
Xextern int getopt _PROTO((int argc, char **argv, char *opts));
Xextern int optind;
Xextern char *optarg;
X
X#define PLEN    256     /* maximum path length; overflows are not detected */
X
X/* the default values for the prototype file */
X
X#define DEF_UID		2	/*bin*/
X#define DEF_GID		1	/*daemon group*/
X#define DEF_PROT	0555	/*a=re*/
X#define DEF_BLOCKS	360
X#define DEF_INODES	63
X#define DEF_INDENTSTR	"\t"
X
Xint count, origlen, tabs;
Xint gid, uid, prot, same_uid, same_gid, same_prot, blocks, inodes;
Xint block_given, inode_given, dprot;
Xchar *indentstr;
Xchar *proto_file, *top;
XFILE *outfile;
X
Xmain(argc, argv)
X     int argc;
X     char *argv[];
X{
X  int   i;
X  register char *ptr;                   /* Ptr to *argv in use */
X  char *dir;
X  struct stat st;
X  char op;
X  
X  gid = DEF_GID;
X  uid = DEF_UID;
X  prot = DEF_PROT;  
X  blocks = DEF_BLOCKS;
X  inodes = DEF_INODES;
X  indentstr = DEF_INDENTSTR;
X  inode_given = 0;
X  block_given = 0;
X  top = 0;
X  same_uid = 0;
X  same_gid = 0;
X  same_prot = 0;
X  while ((op = getopt(argc, argv, "b:g:i:p:t:u:d:s")) != EOF) {
X    switch (op) {
X      case 'b' :
X	blocks = atoi(optarg);
X	block_given = 1;
X	break;
X      case 'g' :
X	gid = atoi(optarg);
X	if (gid == 0) usage(argv[0]);
X	same_gid = 0;
X	break;
X      case 'i' :
X	inodes = atoi(optarg);
X	inode_given = 1;
X	break;
X      case 'p' :
X	sscanf(optarg, "%o" , &prot);
X	if (prot == 0) usage(argv[0]);
X	same_prot = 0;
X	break;
X      case 's' :
X	same_prot = 1;
X	same_uid = 1;
X	same_gid = 1;
X	break;
X      case 't' :
X	top = optarg;
X	break;
X      case 'u' :
X	uid = atoi(optarg);
X	if (uid == 0) usage(argv[0]);
X	same_uid = 0;
X	break;
X      case 'd' :
X	indentstr = optarg;
X	break;
X      default :               /* Illegal options */
X	usage(argv[0]);
X    }
X  }
X  
X  if (optind >= argc) {
X    usage(argv[0]);
X  }
X  else {
X    dir = argv[optind];
X    optind++;
X    proto_file = argv[optind];
X  }
X  if (!top) top = dir;
X  open_outfile();
X  if (block_given && !inode_given) inodes = (blocks/3) + 8;
X  if (!block_given && inode_given) usage(argv[0]);
X  count=1;
X  tabs = 0;
X  origlen = strlen(dir);
X  
X  /* check that it really is a directory */
X  stat(dir, &st);
X  if ((st.st_mode&S_IFMT) != S_IFDIR) {
X    fprintf(stderr,"mkproto: %s must be a directory\n", dir);
X    usage(argv[0]);
X  }
X  fprintf(outfile,"boot\n%d %d\n",blocks,inodes);
X  display_attrib("", &st);
X  fprintf(outfile,"\n");
X  descend(dir);
X  fprintf(outfile,"$\n");
X}
X
X
X/*
X * Output the prototype spec for this directory.
X */
X
Xdescend(dirname)
X     char *dirname;
X{
X#ifdef UNIX
X  struct direct *dp;
X#else
X  struct dirent *dp;
X#endif
X  DIR *dirp;
X  char *bs, *name, *newdir, *temp, *tempend;
X  int i;
X  struct stat st;
X  unsigned short mode;
X  
X  dirp = opendir(dirname);
X  if (dirp == NULL) {
X    fprintf(stderr, "unable to open directory %s\n",dirname);
X    return;
X  }
X
X  tabs++;
X  temp = (char *)malloc(sizeof(char)*strlen(dirname)+1 + PLEN );
X  strcpy(temp,dirname);
X  strcat(temp,"/");
X  tempend = &temp[strlen(temp)];
X
X  for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
X    name = dp->d_name;
X
X    count++;
X    strcpy(tempend,name);
X
X    if (stat(temp, &st) == -1) {
X      fprintf(stderr,"cant get status of '%s' \n",temp);
X      continue;
X    }
X  
X    if (name[0] == '.' && (name[1] == 0 || name[1] == '.' && name[2] == 0)) {
X      continue;
X    }
X
X    display_attrib (name, &st);
X
X    mode = st.st_mode&S_IFMT;
X    if (mode == S_IFDIR) {
X      fprintf(outfile,"\n");
X      descend(temp);
X      for (i=0; i<tabs;i++) {
X	fprintf(outfile,indentstr);
X      }
X      fprintf(outfile,"$\n");
X      continue;
X    }
X    if (mode == S_IFBLK || mode == S_IFCHR) {
X      fprintf(outfile," %d %d\n",major(st.st_rdev),minor(st.st_rdev));
X      continue;
X    }
X#ifdef S_IFLNK
X    if (mode == S_IFLNK) {
X      fprintf(outfile, "The file that is linked to goes here.\n");
X      continue;
X    }
X#endif
X#ifdef S_IFSOCK
X    if (mode == S_IFSOCK) {
X      fprintf(outfile," This is ment to be a socket.\n");
X      continue;
X    }
X#endif
X    if (mode == S_IFREG) {
X      i = origlen;
X      fprintf(outfile,"%s%s",indentstr,top);
X      while( temp[i] != '\0') {
X	fputc(temp[i],outfile);
X	i++;
X      }
X      fprintf(outfile,"\n");
X      continue;
X    }
X    fprintf(outfile, " /dev/null");
X    fprintf(stderr, "File\n\t%s\n is of an invalid mode, made empty.\n", temp);
X  }
X  closedir(dirp);
X  free(temp);
X  tabs--;
X}
X
X
X/*
X * Output the specification for a single file
X */
X
Xdisplay_attrib (name,st)
X     char *name;
X     struct stat *st;
X{
X  int i;
X
X  if (same_uid) 
X    uid = st->st_uid;
X  if (same_gid)
X    gid = st->st_gid;
X  if (same_prot)
X    prot = st->st_mode&0777;  /***** This one is a bit shady *****/
X  for (i=0; i<tabs; i++)
X    fprintf(outfile,indentstr);
X  fprintf(outfile,"%s%s%c%c%c%3o %d %d",
X	  name,
X	  *name == '\0' ? "" : indentstr, /* stop the tab for a null name */
X	  (st->st_mode&S_IFMT) == S_IFDIR ? 'd' :
X	  (st->st_mode&S_IFMT) == S_IFCHR ? 'c' :
X	  (st->st_mode&S_IFMT) == S_IFBLK ? 'b' :
X#ifdef LINKS
X	  (st->st_mode&S_IFMT) == S_IFLNK ? 'l' :
X#endif
X#ifdef SOCKETS
X	  (st->st_mode&S_IFMT) == S_IFSOCK ? 's' :
X#endif
X	  '-', /*file type*/
X	  (st->st_mode&S_ISUID) ? 'u' : '-', /*set uid*/
X	  (st->st_mode&S_ISGID) ? 'g' : '-', /*set gid*/
X	  prot,
X	  uid,
X	  gid);
X}
X
Xusage(binname)
X     char *binname;
X{
X  fprintf(stderr,"usage : %s [options] directory [prot file]\n",binname);
X  fprintf(stderr,"options:\n");
X  fprintf(stderr,"\t-s\t\tuse the same uid, gid and prot as directory\n");
X  fprintf(stderr,"\t-u nnn\t\tuse nnn as the uid on all files (default %d)\n",DEF_UID);
X  fprintf(stderr,"\t-g nnn\t\tuse nnn as the gid on all files (default %d)\n",DEF_GID);
X  fprintf(stderr,"\t-p nnn\t\tuse nnn as the protection on all file (default %o)\n",DEF_PROT);
X  fprintf(stderr,"\t-t ROOT\t\tsupply the path for each entry\n");
X  fprintf(stderr,"\t-b nnn\t\tset the number of blocks to nnn for file system\n\t\t\t(default %d)\n",DEF_BLOCKS);
X  fprintf(stderr,"\t-i nnn\t\tset the number of inodes to nnn for file system\n\t\t\t(default %d)\n",DEF_INODES);
X  fprintf(stderr,"\t-d STRING\tdefine the indentation characters (default %s)\n", DEF_INDENTSTR);
X  exit(1);
X}
X
Xopen_outfile()
X{
X  if (proto_file == NULL)
X    outfile = stdout;
X  else if ((outfile = fopen(proto_file, "w")) == NULL)
X    fprintf(stderr, "Cannot create %s\n ", proto_file);
X}
/
echo x - mkproto.doc
sed '/^X/s///' > mkproto.doc << '/'
X
X
X
Xmkproto(1)               USER COMMANDS                 mkproto(1)
X
X
X
XNAME
X     Mkproto - create a minix prototype file
X
XSYNOPSIS
X     mkproto [options] source-directory [proto-file]
X
XDESCRIPTION
X     Mkproto creates a mkfs(1) prototype file for  the  specified
X     source-directory.  The  prototype  file is either written to
X     standard output or, if specified, the proto-file.
X
XOPTIONS
X     -s        Use the same uid, gid and protection as the  files
X               in the source directory.
X
X     -uN       Use N as the uid on all files and directories.
X
X     -gN       Use N as the gid for all files and directories.
X
X     -pOOO     Use OOO (octal) as the protection  for  all  files
X               and directories.
X
X     -tROOT    use the string ROOT as the  start  to  every  file
X               name.  Normally the names of the files is based on
X               the CWD.
X
X     -bN       Use N as the number of blocks  for  the  prototype
X               file.  The  number  of  i-nodes will be calculated
X               using this block value. This is passed to mkfs.
X
X     -iN       Use N as the number of i-nodes in the file system.
X               This is passed to mkfs.
X
X     -dSTR     Indent the prototype file using STR instead  of  a
X               tab character.
X
XSEE ALSO
X     mkfs(1)
X
XAUTHORS
X     John Warburton & Andrew Cagney
X
XBUGS
X
X
X
X
X
X
X
X
X
XSun Release 4.0           Last change:                          1
X
X
X
X
X
X
/
echo x - mkproto.man
sed '/^X/s///' > mkproto.man << '/'
X.TH mkproto 1
X.SH NAME
XMkproto \- create a minix prototype file
X.SH SYNOPSIS
X.B mkproto
X.I [options] source-directory [proto-file]
X.SH DESCRIPTION
X.B Mkproto
Xcreates a mkfs(1) prototype file for the specified
X.I source-directory.
XThe prototype file is either written to standard output or, if specified,
Xthe
X.I proto-file.
X.SH OPTIONS
X.TP 10
X.BI -s
XUse the same uid, gid and protection as the files in the source directory.
X.TP 10
X.BI -u N
XUse
X.I N
Xas the uid on all files and directories.
X.TP 10
X.BI -g N
XUse
X.I N
Xas the gid for all files and directories.
X.TP 10
X.BI -p OOO
XUse
X.I OOO
X(octal) as the protection for all files and directories.
X.TP 10
X.BI -t ROOT
Xuse the string
X.I ROOT
Xas the start to every file name. Normally the names of the files is based
Xon the CWD.
X.TP 10
X.BI -b N
XUse
X.I N
Xas the number of blocks for the prototype file. The number of i-nodes will be
Xcalculated using this block value. This is passed to mkfs.
X.TP 10
X.BI -i N
XUse
X.I N
Xas the number of i-nodes in the file system. This is passed to mkfs.
X.TP 10
X.BI -d STR
XIndent the prototype file using
X.I STR
Xinstead of a tab character.
X.SH "SEE ALSO"
Xmkfs(1)
X.SH AUTHORS
XJohn Warburton & Andrew Cagney
X.SH "BUGS"
X
/