Xref: utzoo comp.bugs.4bsd:1672 comp.std.c:4190 comp.lang.c:35503 Path: utzoo!utgpu!watserv1!watmath!att!emory!swrinde!zaphod.mps.ohio-state.edu!julius.cs.uiuc.edu!apple!well!jef From: jef@well.sf.ca.us (Jef Poskanzer) Newsgroups: comp.bugs.4bsd,comp.std.c,comp.lang.c Subject: Re: Safe coding practices (was Re: Bug in users command) Message-ID: <22878@well.sf.ca.us> Date: 25 Jan 91 03:51:49 GMT References: <1991Jan25.021929.10512@tkou02.enet.dec.com> Reply-To: Jef Poskanzer Organization: Paratheo-Anametamystikhood Of Eris Esoteric, Ada Lovelace Cabal Lines: 233 In the referenced message, diamond@jit345.enet@tkou02.enet.dec.com (Norman Diamond) wrote: }>Gosh, in ten years, if every trend in computer usage magically reverses }>itself, I'll get a message telling me to change the number from 1000 to }>10000. } }Suppose someone starts logging NFS clients? Or the clients of some other }service? 1000 would already be a bit small for that. Huh? In the users command? What are you talking about? Stick to the given problem domain. }>Yes, it does check for overflow. } }Uh, you mean that it doesn't abort on overflow, but only gives inaccurate }answers. OK, so your example does about 1/4 of what a good example would do. No, of course that's not what I mean. It checks for overflow, tells you that it needs to be recompiled on overflow, and aborts on overflow. Why is that so hard to understand? Complete source is appended, so that we will have no more creative misunderstandings. Note that it does a few more things than the usual users command. Anyway, if you don't like the fixed-size array answer or the doubling-realloc answer or the read it twice answer, then let's see what you *do* like. Time to sling some code, dude. --- Jef Jef Poskanzer jef@well.sf.ca.us {apple, ucbvax, hplabs}!well!jef INSPECTED BY #6 /* ** users - show users, with those on a list highlighted ** ** version of 10oct90 ** ** Copyright (C) 1990 by Jef Poskanzer. ** ** Permission to use, copy, modify, and distribute this software and its ** documentation for any purpose and without fee is hereby granted, provided ** that the above copyright notice appear in all copies and that both that ** copyright notice and this permission notice appear in supporting ** documentation. This software is provided "as is" without express or ** implied warranty. */ #include #include #include #include #ifndef UT_NAMESIZE #define UT_NAMESIZE 8 #endif #ifndef _PATH_UTMP #define _PATH_UTMP "/etc/utmp" #endif #define TBUFSIZE 1024 #define MAXNAMES 1000 #define LINEWIDTH 79 extern char* getenv(); extern char* tgetstr(); int cmp(); int inlist(); void putch(); main( argc, argv ) int argc; char* argv[]; { char* term; char* strptr; char* soptr; char* septr; int smart; char buf[TBUFSIZE]; static char strbuf[TBUFSIZE]; struct utmp u; FILE* fp; static char friends[MAXNAMES][UT_NAMESIZE+1]; static char users[MAXNAMES][UT_NAMESIZE+1]; int i, nfriends, nusers; int wid; /* Check args. */ if ( argc == 1 ) ; else if ( argc == 3 && strcmp( argv[1], "-h" ) == 0 ) { /* Read the friends list. */ fp = fopen( argv[2], "r" ); if ( fp == NULL ) { perror( argv[2] ); exit( 1 ); } nfriends = 0; while ( fgets( buf, sizeof(buf), fp ) != NULL ) { if ( buf[strlen(buf)-1] == '\n' ) buf[strlen(buf)-1] = '\0'; if ( nfriends >= MAXNAMES ) { (void) fprintf( stderr, "Oops, too many names in the friends file. Gotta increase MAXNAMES.\n" ); exit( 1 ); } (void) strncpy( friends[nfriends], buf, UT_NAMESIZE ); friends[nfriends][UT_NAMESIZE] = '\0'; ++nfriends; } (void) fclose( fp ); /* qsort( friends, nfriends, sizeof(friends[0]), cmp ); */ } else { (void) fprintf( stderr, "usage: %s [-h highlightlist]\n", argv[0] ); exit( 1 ); } /* Initialize termcap stuff. */ if ( isatty( fileno( stdout ) ) == 0 ) smart = 0; else { term = getenv( "TERM" ); if ( term == 0 ) smart = 0; else if ( tgetent( buf, term ) <= 0 ) smart = 0; else { strptr = strbuf; soptr = tgetstr( "so", &strptr ); septr = tgetstr( "se", &strptr ); if ( soptr == NULL || septr == NULL ) smart = 0; else smart = 1; } } /* Open utmp and read the users. */ fp = fopen( _PATH_UTMP, "r" ); if ( fp == NULL ) { perror( "utmp" ); exit( 1 ); } nusers = 0; while ( fread( (char*) &u, sizeof(u), 1, fp ) == 1 ) { if ( u.ut_name[0] != '\0' ) { if ( nusers >= MAXNAMES ) { (void) fprintf( stderr, "Oops, too many users logged in. Gotta increase MAXNAMES.\n" ); exit( 1 ); } (void) strncpy( users[nusers], u.ut_name, UT_NAMESIZE ); users[nusers][UT_NAMESIZE] = '\0'; ++nusers; } } (void) fclose( fp ); qsort( users, nusers, sizeof(users[0]), cmp ); /* Show the users. */ wid = 0; for ( i = 0; i < nusers; ++i ) { if ( wid + strlen( users[i] ) + 3 > LINEWIDTH ) { putchar( '\n' ); wid = 0; } if ( wid > 0 ) { putchar( ' ' ); ++wid; } if ( inlist( users[i], friends, nfriends ) ) { if ( smart ) tputs( soptr, 1, putch ); else putchar( '<' ); fputs( users[i], stdout ); if ( smart ) tputs( septr, 1, putch ); else putchar( '>' ); if ( ! smart ) wid += 2; } else fputs( users[i], stdout ); wid += strlen( users[i] ); } putchar( '\n' ); exit( 0 ); } int cmp( a, b ) char* a; char* b; { return strcmp( a, b ); } int inlist( str, list, nlist ) char* str; char list[MAXNAMES][UT_NAMESIZE+1]; int nlist; { int i; /* (This could be made into a binary search.) */ for ( i = 0; i < nlist; ++i ) if ( strcmp( str, list[i] ) == 0 ) return 1; return 0; } void putch( ch ) char ch; { putchar( ch ); }