Subject: news(1)
To: None <tech-userlevel@netbsd.org>
From: Jan Schaumann <jschauma@netmeister.org>
List: tech-userlevel
Date: 09/02/2004 23:00:52
--XMCwj5IQnwKtuyBG
Content-Type: multipart/mixed; boundary="ftEhullJWpWg/VHq"
Content-Disposition: inline


--ftEhullJWpWg/VHq
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable

Hi,

Some unix flavors offer a news(1) program to allow the user to display
system news items created by the sysadmin in /var/news.  We don't have
this tool, but since I find it useful, I wrote one.

If somebody could review the attached two files and make suggestions on
how to improve it and comment on whether or not it should be imported,
I'd appreciate it.

Thanks,
-Jan

--=20
I always said there was something fundamentally wrong with the universe.

--ftEhullJWpWg/VHq
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="news.c"
Content-Transfer-Encoding: quoted-printable

/*	$NetBSD: $ */

/*
 * Copyright (c) 2004 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Jan Schaumann.
 *=20
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMI=
TED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICUL=
AR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF T=
HE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: $");
#endif /* not lint */

#include <sys/types.h>
#include <sys/stat.h>

#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <fts.h>
#include <limits.h>
#include <pwd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

static int compare(const FTSENT **, const FTSENT **);
static int printFile(char *);
static int printFiles(char *[]);
static void printHead(const char *);
static time_t updateTimestamp(const char *);
static void usage(void);
int main(int, char *[]);

#define NEWS_PATH	"/var/news"
#define NEWS_TIME	".news_time"

/* flags */
int f_all;		/* print all items regardless of currency */
int f_name;		/* print names of current items without content */
int f_short;		/* print number of current items */

time_t nf_time;

/*
 * The news utility prints news items stored in /var/news.  When invoked
 * without any arguments, news prints the name and timestamp of each
 * current item followed by its contents, most recent first.
 */
int
main(int argc, char *argv[])
{
	int ch, len;
	char *home, *nf;

	extern int optind;

	f_all =3D f_name =3D f_short =3D 0;

	setprogname(argv[0]);

	while ((ch =3D getopt(argc, argv, "ans")) !=3D -1) {
		switch(ch) {
		case 'a':
			f_all =3D 1;
			break;
		case 'n':
			f_name =3D 1;
			f_short =3D 0;
			break;
		case 's':
			f_short =3D 1;
			f_name =3D 0;
			break;
		case '?':
		default:
			usage();
			/* NOTREACHED */
		}
	}
	argc -=3D optind;
	argv +=3D optind;

	if (*argv && (f_all || f_name || f_short))
		errx(EXIT_FAILURE, "Options are not allowed with file names.");
		/* NOTREACHED */

	if ((home =3D getenv("HOME")) =3D=3D NULL)
		errx(EXIT_FAILURE, "Unable find HOME variable.");
		/* NOTREACHED */

	len =3D strlen(home) + strlen(NEWS_TIME) + 2;
	if ((nf =3D malloc(len)) =3D=3D NULL)
		errx(EXIT_FAILURE, "Unable to allocate memory.");
		/* NOTREACHED */

	if ((snprintf(nf, len, "%s/%s", home, NEWS_TIME)) =3D=3D -1)
		errx(EXIT_FAILURE, "Unable to prepare path.");
		/* NOTREACHED */

	nf_time =3D updateTimestamp(nf);
	free(nf);

	return printFiles(argv);
}

/*
 * print either all files given or all files considered ``current''
 */
int
printFiles(char **files)
{
	int num, retval;

	num =3D retval =3D 0;

	if (chdir(NEWS_PATH) =3D=3D -1)
		err(EXIT_FAILURE, "Unable to access %s", NEWS_PATH);
		/* NOTREACHED */

	if (*files) {
		char *file;

		while ((file =3D *files++) !=3D NULL)
			retval +=3D printFile(file);
	} else {
		FTS *ftsp;
		FTSENT *p;
		char *dirs[2];
		char **retval;

		dirs[0] =3D NEWS_PATH;
		dirs[1] =3D NULL;
		num =3D 0;

		if ((ftsp =3D fts_open(dirs, FTS_PHYSICAL, compare)) =3D=3D NULL)
			err(EXIT_FAILURE, "unable to crawl %s", NEWS_PATH);

		while ((p =3D fts_read(ftsp)) !=3D NULL) {
			if ((p->fts_info =3D=3D FTS_F) &&
					(f_all || (p->fts_statp->st_mtime > nf_time))) {
				if (f_short)
					num++;
				else
					retval +=3D printFile(p->fts_name);
			}
		}
	}

	if (f_short) {
		if (num > 0)
			printf("%d news items.\n", num);
		else
			printf("No news.\n");
		return 0;
	}

	return retval;
}

void
usage()
{
	(void)fprintf(stderr, "usage: news [-ans] [ items ]\n");
	exit(EXIT_FAILURE);
	/* NOTREACHED */
}

int
printFile(char *file)
{
	if (file) {
		char buf[1024];
		FILE *fs;

		if ((fs =3D fopen(file, "r")) =3D=3D NULL) {
			fprintf(stderr, "Cannot open %s%s%s: %s\n",
					file[0] =3D=3D '/' ? "" : NEWS_PATH,
					file[0] =3D=3D '/' ? "" : "/", file,
					strerror(errno));
			return 1;
		}

		printHead(file);

		if (!f_name) {
			while (fgets(buf, 1024, fs) !=3D NULL) {
				if (buf[strlen(buf)-1] =3D=3D '\n')
					printf("   ");
				printf("%s", buf);
			}
			printf("\n");
		}
		fclose(fs);
	}
	return 0;
}

void
printHead(const char *file)
{
	struct stat sb;
	struct passwd *pw;
	char owner[LOGIN_NAME_MAX+2];

	if (stat(file, &sb) =3D=3D -1) {
		warn("unable to stat %s", file);
		return;
	}

	if (((pw =3D getpwuid(sb.st_uid)) =3D=3D NULL))
		(void)snprintf(owner, LOGIN_NAME_MAX+2, "(%d)", sb.st_uid);
	else
		(void)snprintf(owner, LOGIN_NAME_MAX+2, "(%s)", pw->pw_name);

	printf("%s %s %s", file, owner, ctime(&(sb.st_mtime)));
}

time_t
updateTimestamp(const char *nf)
{
	struct stat sb;
	time_t retval;

	if (stat(nf, &sb) =3D=3D -1) {
		int fd;

		/* can't stat .news_time file, so create one and consider all
		 * entries ``current'' */
		f_all =3D 1;

		if ((fd =3D open(nf, O_CREAT |O_EXCL | O_TRUNC | O_WRONLY,
						S_IRUSR | S_IWUSR)) =3D=3D -1)
			warn("unable to create %s", nf);
		else {
			close(fd);
			retval =3D (time_t)0;
		}
	} else
		retval =3D sb.st_mtime;
		=09
	if (utimes(nf, NULL) =3D=3D -1)
		warn("unable to update timestamp");

	return retval;
}

int
compare(const FTSENT **a, const FTSENT **b)
{
	if ((*a)->fts_statp->st_mtime > (*b)->fts_statp->st_mtime)
		return -1;
	else if ((*a)->fts_statp->st_mtime =3D=3D (*b)->fts_statp->st_mtime)
		return 0;
	else
		return 1;
}

--ftEhullJWpWg/VHq
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="news.1"
Content-Transfer-Encoding: quoted-printable

=2E\"	$NetBSD:  $
=2E\"
=2E\" Copyright (c) 2004 The NetBSD Foundation, Inc.
=2E\" All rights reserved.
=2E\"
=2E\" This code is derived from software contributed to The NetBSD Foundati=
on
=2E\" by Jan Schaumann.
=2E\"
=2E\" Redistribution and use in source and binary forms, with or without
=2E\" modification, are permitted provided that the following conditions
=2E\" are met:
=2E\" 1. Redistributions of source code must retain the above copyright
=2E\"    notice, this list of conditions and the following disclaimer.
=2E\" 2. Redistributions in binary form must reproduce the above copyright
=2E\"    notice, this list of conditions and the following disclaimer in the
=2E\"    documentation and/or other materials provided with the distributio=
n.
=2E\" 3. Neither the name of the University nor the names of its contributo=
rs
=2E\"    may be used to endorse or promote products derived from this softw=
are
=2E\"    without specific prior written permission.
=2E\"
=2E\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBU=
TORS
=2E\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT L=
IMITED=20
=2E\" TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTIC=
ULAR
=2E\" PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTOR=
S BE
=2E\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
=2E\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
=2E\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSIN=
ESS
=2E\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER =
IN
=2E\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWIS=
E)
=2E\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED O=
F THE
=2E\" POSSIBILITY OF SUCH DAMAGE.
=2E\"
=2E\"
=2EDd September 2, 2004
=2EDt NEWS 1
=2EOs
=2ESh NAME
=2ENm news
=2ENd print news items
=2ESh SYNOPSIS
=2ENm
=2EOp Fl ans
=2EOp Ar items
=2ESh DESCRIPTION
The
=2ENm
utility prints news items stored in
=2EPa /var/news .
When invoked without any arguments,
=2ENm
prints the name and timestamp of each current item followed by its contents,
most recent first.
An item is considered ``current'' if it has a modification time newer than =
the
file
=2EPa ~/.news_time ,
a file that
=2ENm
creates if it does not exist.
If that file does exist,
=2ENm
will update the timestamp on that file each time it is run.
=2EPp
Any
=2EAr items
passed to
=2ENm
are interpreted as filenames (either relative to
=2EPa /var/news
or absolute) to display.
=2EPp
The following options are available:
=2EBl -tag -width Fl
=2EIt Fl a
All available items are displayed, regardless of their ``currency''.
=2EIt Fl n
Only the names and modification times of the current items are displayed.
Overrides
=2EFl s .
=2EIt Fl s
Report only how many news items are current.  Overrides
=2EFl n .
=2EEl
=2ESh AUTHORS
The
=2ENm
utility was written by Jan Schaumann <jschauma@NetBSD.org> following the
manual page from an IRIX system.
=2ESh HISTORY
The
=2ENm
utility has been available on various Unix flavors for a long time.  It fir=
st
appeared in NetBSD in 2.1.

--ftEhullJWpWg/VHq--

--XMCwj5IQnwKtuyBG
Content-Type: application/pgp-signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.3 (NetBSD)

iD8DBQFBN95kfFtkr68iakwRAv6QAJ9+L/KAfiOS44RkhVyWvwtyVYgYnACg9oa0
zvlRFIIHHbIrbpJ9GEGsCEM=
=rh4J
-----END PGP SIGNATURE-----

--XMCwj5IQnwKtuyBG--