Lecture #9: UNIX System Calls

Reading: none
Handouts: 2cat.c, user.c
  1. Greetings and felicitations
  2. File descriptors
    1. stdio analogues: open, close, read, write, lseek
  3. File status information
    1. attributes of file
    2. getting them
  4. Time
    1. internal representation of time
    2. converting time to printable format
  5. Users and groups
    1. what information is stored and where
    2. getpwent, getgrent, etc.

2cat.c

/*
 * 2cat -- a program to print a file twice
 * This demonstrates the use of file descriptors
 *
 * Matt Bishop, bishop@cs.ucdavis.edu	11/9/96
 */
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>

/*
 * macros
 */
#define BUFSIZ	1024	/* size of buffer for file I/O */

/*
 * forward declarations
 */
void perror(char *);	/* print system error message */

/*
 * print the file with the given file descriptor
 * returns 0 on success, -1 on error
 * does not print any error message
 */
int cat(int fd)
{
	register int n;	/* number of bytes read */
	char buf[BUFSIZ];	/* buffer for file I/O */

	/*
	 * grab BUFSIZ bytes and dump them to
	 * the standard output
	 */
	while((n = read(fd, buf, BUFSIZ)) > 0)
		/* if error, end this function at once */
		if (write(1, buf, n) != n)
			return(-1);

	/* if read failed, return error; else okay */
	return(n < 0 ? -1 : 0);
}

/*
 * print the named file twice
 * returns 0 on success, 1 on error
 * prints system error message if there is a problem
 */
int twocat(char *name)
{
	register int fd;		/* file's descriptor */
	register int retval = 0;	/* value to return */

	/*
	 * open the file
	 */
	if ((fd = open(name, O_RDONLY)) < 0){
		perror(name);
		return(-1);
	}
	/*
	 * display the file, rewind it, and redisplay it
	 * if there's an error, print the system error
	 * message and quit
	 */
	if (cat(fd) < 0 || lseek(fd, 0L, 0) != 0 || cat(fd) < 0){
		perror(name);
		retval = 1;
	}
	/*
	 * close it up and return status
	 */
	(void) close(fd);
	return(retval);
}

/*
 * main routine
 */
int main(int argc, char *argv[])
{
	register int i;		/* counter in a for loop */
	register int estat = 0;	/* exit status */

	/*
	 * bad usage message
	 */
	if (argc == 1){
		(void) write(2, "Usage: ", strlen("Usage: "));
		(void) write(2, argv[0], strlen(argv[0]));
		(void) write(2, " file [ ... ]\n",
					strlen(" file [ ... ]\n"));
		return(1);
	}

	/*
	 * print each file twice as you go
	 */
	for(i = 1; i < argc; i++)
		estat += twocat(argv[i]);

	/*
	 * return number of failures
	 */
	return(estat);
}


user.c

/*
 * program to print information about named user(s)
 * demonstrates mapping user name (etc.) and date
 *
 * Matt Bishop, bishop@cs.ucdavis.edu	11/9/96
 */
#include <ctype.h>
#include <stdio.h>
#include <grp.h>
#include <pwd.h>
#include <sys/time.h>
#include <time.h>

/*
 * forward declarations
 */
void setgrent(void);	/* initialize group file -- not in grp.h!!! */
void endgrent(void);	/* clean up group file -- not in grp.h!!! */
int gettimeofday(struct timeval *, struct timezone *);	/* get time of day */

/*
 * prints the current time of day
 */
int prdate(void)
{
	struct timeval tod;	/* time of day */
	struct timezone tz;	/* time zone */
	char *atod;		/* date as a string */

	/*
	 * get the time of day
	 */
	if (gettimeofday(&tod, &tz) < 0)
		return(1);
	/*
	 * convert it to a string and print it
	 */
	if ((atod = ctime((time_t *)&tod.tv_sec)) == NULL)
		atod = "Time not available\n";
	printf("%s", atod);
	return(0);
}

/*
 * print secondary group list
 * this is a list of groups the user is in
 * name is name of user, gid is his/her GID
 * if empty list, print *none*
 */
void prsgid(char *name, int gid)
{
	register struct group *gp;	/* points to group info */
	register char **p;		/* walks user list of group */
	register int count = 0;	/* how many groups printed */

	/*
	 * initialize group file for scan
	 */
	setgrent();

	/*
	 * loop through groups, looking for this user
	 * in its member list
	 */
	while ((gp = getgrent()) != NULL){
		for(p = gp->gr_mem; *p; p++)
			if (strcmp(*p, name) == 0){
				/* bingo! */
				printf(" %s(%d)", gp->gr_name,
							gp->gr_gid);
				count++;
				break;
			}
	}

	/*
	 * clean up and leave
	 */
	endgrent();
	if (count == 0)
		printf(" *none*");
}

/*
 * given a GID gid, print the group name or *unknown* if none
 * also the GID.
 */
void grname(int gid)
{
	struct group *gp;		/* points to group info */

	/*
	 * if you find it, print it; else say *unknown*
	 */
	if ((gp = getgrgid(gid)) == NULL)
		printf("*unknown*(%d)\n", gid);
	else
		printf("%s(%d)\n", gp->gr_name, gid);
}
		
/*
 * print user information about user name; if name is number,
 * take as UID
 */
void getuinfo(char *name)
{
	register int n = 0;	/* UID if name is UID */
	register char *s;	/* used to check if name is UID or name */
	struct passwd *pw;	/* points to user info */

	/*
	 * get the user information structure
	 */
	for(s = name; *s && isdigit(*s); s++)
		n = n * 10 + *s - '0';
	if (!*s){
		/* it's an integer */
		pw = getpwuid(n);
	}
	else{
		/* it's not an integer */
		pw = getpwnam(name);
	}

	/*
	 * check for bad name/UID
	 */
	if (pw == NULL){
		printf("%s: unknown %s\n", name, *s ? "name" : "UID");
		return;
	}

	/*
	 * now dump the user information
	 */
	printf("user name: %s\n", pw->pw_name);
	printf("hashed password: %s\n", pw->pw_passwd);
	printf("UID: %d\n", pw->pw_uid);
	/* do the principle GID as groupname(gid) */
	printf("principle GID: ");
	grname(pw->pw_gid);
	/* do the secondary GID as a list of groupname(gid)s */
	printf("secondary GIDs:");
	prsgid(pw->pw_name, pw->pw_gid);
	putchar('\n');
	printf("GECOS field: %s\n", pw->pw_gecos);
	printf("home directory: %s\n", pw->pw_dir);
	printf("login shell: %s\n", pw->pw_shell);
}

/*
 * the main routine
 */
int main(int argc, char *argv[])
{
	register int i;		/* used to walk argument list */

	/*
	 * print the date
	 */
	if (prdate()){
		perror(argv[0]);
		return(1);
	}
	/*
	 * print the user info one user at a time
	 * with a separating header
	 */
	for(i = 1; i < argc; i++){
		printf("========== %s ==========\n", argv[i]);
		getuinfo(argv[i]);
	}
	return(0);
}
>
You can also see this document as an RTF document, a Postscript document, or a plain ASCII text document.
Send email to cs40@csif.cs.ucdavis.edu.

Department of Computer Science
University of California at Davis
Davis, CA 95616-8562



Page last modified on 11/11/97