Lecture #9: UNIX System Calls Reading: none Handouts: 2cat.c 1. Greetings and felicitations 2. File descriptors Ö stdio analogues: open, close, read, write, lseek 3. File status information Ö attributes of file Ö getting them 4. Time Ö internal representation of time Ö converting time to printable format 5. Users and groups Ö what information is stored and where Ö 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 #include #include /* * 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 #include #include #include #include #include /* * 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); } Lecture Notes ECS 40 ‚ FALL 1996 Page 1 2cat.c ECS 40 ‚ FALL 1996 Page 4 user.c ECS 40 ‚ FALL 1996 Page 8