comm: add -Wall
[unleashed.git] / usr / src / cmd / news / news.c
blob55bfe40304e63090dc74d5f5268c6e578be7cf48
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
20 * CDDL HEADER END
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
30 #pragma ident "%Z%%M% %I% %E% SMI"
33 news foo prints /var/news/foo
34 news -a prints all news items, latest first
35 news -n lists names of new items
36 news -s tells count of new items only
37 news prints items changed since last news
40 #include <stdio.h>
41 #include <sys/types.h>
42 #include <stdlib.h>
43 #include <unistd.h>
44 #include <sys/stat.h>
45 #include <fcntl.h>
46 #include <setjmp.h>
47 #include <signal.h>
48 #include <string.h>
49 #include <dirent.h>
50 #include <pwd.h>
51 #include <time.h>
52 #include <locale.h>
53 #include <utime.h>
55 #define INDENT 3
56 #define RD_WR_ALL (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)
58 #define DATE_FMT "%a %b %e %H:%M:%S %Y"
60 * %a abbreviated weekday name
61 * %b abbreviated month name
62 * %e day of month
63 * %H hour (24-hour clock)
64 * %M minute
65 * %S second
66 * %Y year
69 The following items should not be printed.
71 char *ignore[] = {
72 "core",
73 NULL
76 struct n_file {
77 long n_time;
78 char n_name[MAXNAMLEN];
79 } *n_list;
81 char NEWS[] = "/var/news"; /* directory for news items */
83 int aopt = 0; /* 1 say -a specified */
84 int n_count; /* number of items in NEWS directory */
85 int number_read; /* number of items read */
86 int nopt = 0; /* 1 say -n specified */
87 int optsw; /* for getopt */
88 int opt = 0; /* number of options specified */
89 int sopt = 0; /* 1 says -s specified */
90 char stdbuf[BUFSIZ];
91 char time_buf[50]; /* holds date and time string */
93 jmp_buf save_addr;
95 void all_news(void);
96 int ck_num(void);
97 void count(char *);
98 void initialize(void);
99 void late_news(void(*)(), int);
100 void notify(char *);
101 void print_item(char *);
102 void read_dir(void);
105 main(int argc, char **argv)
107 int i;
109 (void)setlocale(LC_ALL, "");
110 setbuf (stdout, stdbuf);
111 initialize();
112 read_dir();
114 if (argc <= 1) {
115 late_news (print_item, 1);
116 ck_num();
118 else while ((optsw = getopt(argc, argv, "ans")) != EOF)
119 switch(optsw) {
120 case 'a':
121 aopt++;
122 opt++;
123 break;
125 case 'n':
126 nopt++;
127 opt++;
128 break;
130 case 's':
131 sopt++;
132 opt++;
133 break;
135 default:
136 fprintf (stderr, "usage: news [-a] [-n] [-s] [items]\n");
137 exit (1);
140 if (opt > 1) {
141 fprintf(stderr, "news: options are mutually exclusive\n");
142 exit(1);
145 if (opt > 0 && argc > 2) {
146 fprintf(stderr, "news: options are not allowed with file names\n");
147 exit(1);
150 if (aopt) {
151 all_news();
152 ck_num();
153 exit(0);
156 if (nopt) {
157 late_news (notify, 0);
158 ck_num();
159 exit(0);
162 if (sopt) {
163 late_news (count, 0);
164 exit(0);
167 for (i=1; i<argc; i++) print_item (argv[i]);
169 return (0);
173 * read_dir: get the file names and modification dates for the
174 * files in /var/news into n_list; sort them in reverse by
175 * modification date. We assume /var/news is the working directory.
178 void
179 read_dir(void)
181 struct dirent *nf, *readdir();
182 struct stat sbuf;
183 char fname[MAXNAMLEN];
184 DIR *dirp;
185 int i, j;
187 /* Open the current directory */
188 if ((dirp = opendir(".")) == NULL) {
189 fprintf (stderr, "Cannot open %s\n", NEWS);
190 exit (1);
193 /* Read the file names into n_list */
194 n_count = 0;
195 while (nf = readdir(dirp)) {
196 strncpy (fname, nf->d_name, (unsigned) strlen(nf->d_name) + 1);
197 if (nf->d_ino != (ino_t)0 && stat (fname, &sbuf) >= 0
198 && (sbuf.st_mode & S_IFMT) == S_IFREG) {
199 register char **p;
200 p = ignore;
201 while (*p && strncmp (*p, nf->d_name, MAXNAMLEN))
202 ++p;
203 if (!*p) {
204 if (n_count++ > 0)
205 n_list = (struct n_file *)
206 realloc ((char *) n_list,
207 (unsigned)
208 (sizeof (struct n_file)
209 * n_count));
210 else
211 n_list = (struct n_file *) malloc
212 ((unsigned)
213 (sizeof (struct n_file) *
214 n_count));
215 if (n_list == NULL) {
216 fprintf (stderr, "No storage\n");
217 exit (1);
219 n_list[n_count-1].n_time = sbuf.st_mtime;
220 strncpy (n_list[n_count-1].n_name,
221 nf->d_name, MAXNAMLEN);
226 /* Sort the elements of n_list in decreasing time order */
227 for (i=1; i<n_count; i++)
228 for (j=0; j<i; j++)
229 if (n_list[j].n_time < n_list[i].n_time) {
230 struct n_file temp;
231 temp = n_list[i];
232 n_list[i] = n_list[j];
233 n_list[j] = temp;
236 /* Clean up */
237 closedir(dirp);
240 void
241 initialize(void)
243 if (signal (SIGQUIT, SIG_IGN) != (void(*)())SIG_IGN)
244 signal (SIGQUIT, _exit);
245 umask (((~(S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)) & S_IAMB));
246 if (chdir (NEWS) < 0) {
247 fprintf (stderr, "Cannot chdir to %s\n", NEWS);
248 exit (1);
252 void
253 all_news(void)
255 int i;
257 for (i=0; i<n_count; i++)
258 print_item (n_list[i].n_name);
261 void
262 print_item(char *f)
264 FILE *fd;
265 char fname[MAXNAMLEN+1];
266 static int firstitem = 1;
267 void onintr();
268 struct passwd *getpwuid();
270 if (f == NULL) {
271 return;
273 strncpy (fname, f, MAXNAMLEN);
274 fname[MAXNAMLEN] = '\0';
275 if ((fd = fopen (fname, "r")) == NULL)
276 printf ("Cannot open %s/%s\n", NEWS, fname);
277 else {
278 register int c, ip, op;
279 struct stat sbuf;
280 struct passwd *pw;
282 fstat (fileno (fd), &sbuf);
283 if (firstitem) {
284 firstitem = 0;
285 putchar ('\n');
287 if (setjmp(save_addr))
288 goto finish;
289 if (signal(SIGINT, SIG_IGN) != (void(*)())SIG_IGN)
290 signal(SIGINT, onintr);
291 printf ("%s ", fname);
292 pw = getpwuid (sbuf.st_uid);
293 if (pw)
294 printf ("(%s)", pw->pw_name);
295 else
296 printf (".....");
297 cftime(time_buf, DATE_FMT, &sbuf.st_mtime);
298 printf (" %s\n", time_buf);
299 op = 0;
300 ip = INDENT;
301 while ((c = getc (fd)) != EOF) {
302 switch (c) {
304 case '\r':
305 case '\n':
306 putchar (c);
307 op = 0;
308 ip = INDENT;
309 break;
311 case ' ':
312 ip++;
313 break;
315 case '\b':
316 if (ip > INDENT)
317 ip--;
318 break;
320 case '\t':
321 ip = ((ip - INDENT + 8) & -8) + INDENT;
322 break;
324 default:
325 while (ip < op) {
326 putchar ('\b');
327 op--;
329 while ((ip & -8) > (op & -8)) {
330 putchar ('\t');
331 op = (op + 8) & -8;
333 while (ip > op) {
334 putchar (' ');
335 op++;
337 putchar (c);
338 ip++;
339 op++;
340 break;
343 fflush (stdout);
344 finish:
345 putchar ('\n');
346 fclose (fd);
347 number_read++;
348 if (signal(SIGINT, SIG_IGN) != (void(*)())SIG_IGN)
349 signal(SIGINT, SIG_DFL);
353 void
354 late_news(void(*emit)(), int update)
356 long cutoff;
357 int i;
358 char fname[50], *cp;
359 struct stat newstime;
360 int fd;
361 struct utimbuf utb;
362 extern char *getenv();
364 /* Determine the time when last called */
365 cp = getenv ("HOME");
366 if (cp == NULL) {
367 fprintf (stderr, "Cannot find HOME variable\n");
368 exit (1);
370 strcpy (fname, cp);
371 strcat (fname, "/");
372 strcat (fname, ".news_time");
373 cutoff = stat (fname, &newstime) < 0? 0: newstime.st_mtime;
375 /* Print the recent items */
376 for (i=0; i<n_count && n_list[i].n_time > cutoff; i++) {
377 (*emit) (n_list[i].n_name);
378 number_read++;
380 (*emit) ((char *) NULL);
381 fflush (stdout);
383 if (update) {
384 /* Re-create the file and refresh the update time */
385 if (n_count > 0 && (fd = creat (fname, RD_WR_ALL)) >= 0) {
386 utb.actime = utb.modtime = n_list[0].n_time;
387 close (fd);
388 utime (fname, &utb);
393 void
394 notify(char *s)
396 static int first = 1;
398 if (s) {
399 if (first) {
400 first = 0;
401 printf ("news:", NEWS);
403 printf (" %.14s", s);
404 } else if (!first)
405 putchar ('\n');
408 /*ARGSUSED*/
409 void
410 count(char *s)
412 static int nitems = 0;
414 if (s)
415 nitems++;
416 else {
417 if (nitems) {
418 printf ("%d news item", nitems);
419 if (nitems != 1)
420 putchar ('s');
421 printf (".\n");
423 else printf("No news.\n");
427 void
428 onintr()
430 sleep(2);
431 longjmp(save_addr, 1);
435 ck_num(void)
437 if (sopt && !number_read) printf("No news.\n");
438 return(0);