1 /* 2 * CDDL HEADER START 3 * 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. 8 * 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. 13 * 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] 19 * 20 * CDDL HEADER END 21 */ 22 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 23 /* All Rights Reserved */ 24 25 26 #ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.15 */ 27 28 /* 29 news foo prints /var/news/foo 30 news -a prints all news items, latest first 31 news -n lists names of new items 32 news -s tells count of new items only 33 news prints items changed since last news 34 */ 35 36 #include <stdio.h> 37 #include <sys/types.h> 38 #include <stdlib.h> 39 #include <unistd.h> 40 #include <sys/stat.h> 41 #include <setjmp.h> 42 #include <signal.h> 43 #include <dirent.h> 44 #include <pwd.h> 45 #include <time.h> 46 #include <locale.h> 47 48 #define INDENT 3 49 #define RD_WR_ALL (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) 50 51 #define DATE_FMT "%a %b %e %H:%M:%S %Y" 52 /* 53 * %a abbreviated weekday name 54 * %b abbreviated month name 55 * %e day of month 56 * %H hour (24-hour clock) 57 * %M minute 58 * %S second 59 * %Y year 60 */ 61 /* 62 The following items should not be printed. 63 */ 64 char *ignore[] = { 65 "core", 66 NULL 67 }; 68 69 struct n_file { 70 long n_time; 71 char n_name[MAXNAMLEN]; 72 } *n_list; 73 74 char NEWS[] = "/var/news"; /* directory for news items */ 75 76 int aopt = 0; /* 1 say -a specified */ 77 int n_count; /* number of items in NEWS directory */ 78 int number_read; /* number of items read */ 79 int nopt = 0; /* 1 say -n specified */ 80 int optsw; /* for getopt */ 81 int opt = 0; /* number of options specified */ 82 int sopt = 0; /* 1 says -s specified */ 83 char stdbuf[BUFSIZ]; 84 char time_buf[50]; /* holds date and time string */ 85 86 jmp_buf save_addr; 87 88 main (argc, argv) 89 int argc; 90 char **argv; 91 { 92 int print_item(), notify(), count(),i; 93 94 (void)setlocale(LC_ALL, ""); 95 setbuf (stdout, stdbuf); 96 initialize(); 97 read_dir(); 98 99 if (argc <= 1) { 100 late_news (print_item, 1); 101 ck_num(); 102 } 103 else while ((optsw = getopt(argc, argv, "ans")) != EOF) 104 switch(optsw) { 105 case 'a': 106 aopt++; 107 opt++; 108 break; 109 110 case 'n': 111 nopt++; 112 opt++; 113 break; 114 115 case 's': 116 sopt++; 117 opt++; 118 break; 119 120 default: 121 fprintf (stderr, "usage: news [-a] [-n] [-s] [items]\n"); 122 exit (1); 123 } 124 125 if (opt > 1) { 126 fprintf(stderr, "news: options are mutually exclusive\n"); 127 exit(1); 128 } 129 130 if (opt > 0 && argc > 2) { 131 fprintf(stderr, "news: options are not allowed with file names\n"); 132 exit(1); 133 } 134 135 if (aopt) { 136 all_news(); 137 ck_num(); 138 exit(0); 139 } 140 141 if (nopt) { 142 late_news (notify, 0); 143 ck_num(); 144 exit(0); 145 } 146 147 if (sopt) { 148 late_news (count, 0); 149 exit(0); 150 } 151 152 for (i=1; i<argc; i++) print_item (argv[i]); 153 154 exit(0); 155 } 156 157 /* 158 * read_dir: get the file names and modification dates for the 159 * files in /var/news into n_list; sort them in reverse by 160 * modification date. We assume /var/news is the working directory. 161 */ 162 163 read_dir() 164 { 165 struct dirent *nf, *readdir(); 166 struct stat sbuf; 167 char fname[MAXNAMLEN]; 168 DIR *dirp; 169 int i, j; 170 171 /* Open the current directory */ 172 if ((dirp = opendir(".")) == NULL) { 173 fprintf (stderr, "Cannot open %s\n", NEWS); 174 exit (1); 175 } 176 177 /* Read the file names into n_list */ 178 n_count = 0; 179 while (nf = readdir(dirp)) { 180 strncpy (fname, nf->d_name, (unsigned) strlen(nf->d_name) + 1); 181 if (nf->d_ino != (ino_t)0 && stat (fname, &sbuf) >= 0 182 && (sbuf.st_mode & S_IFMT) == S_IFREG) { 183 register char **p; 184 p = ignore; 185 while (*p && strncmp (*p, nf->d_name, MAXNAMLEN)) 186 ++p; 187 if (!*p) { 188 if (n_count++ > 0) 189 n_list = (struct n_file *) 190 realloc ((char *) n_list, 191 (unsigned) 192 (sizeof (struct n_file) 193 * n_count)); 194 else 195 n_list = (struct n_file *) malloc 196 ((unsigned) 197 (sizeof (struct n_file) * 198 n_count)); 199 if (n_list == NULL) { 200 fprintf (stderr, "No storage\n"); 201 exit (1); 202 } 203 n_list[n_count-1].n_time = sbuf.st_mtime; 204 strncpy (n_list[n_count-1].n_name, 205 nf->d_name, MAXNAMLEN); 206 } 207 } 208 } 209 210 /* Sort the elements of n_list in decreasing time order */ 211 for (i=1; i<n_count; i++) 212 for (j=0; j<i; j++) 213 if (n_list[j].n_time < n_list[i].n_time) { 214 struct n_file temp; 215 temp = n_list[i]; 216 n_list[i] = n_list[j]; 217 n_list[j] = temp; 218 } 219 220 /* Clean up */ 221 closedir(dirp); 222 } 223 224 initialize() 225 { 226 if (signal (SIGQUIT, SIG_IGN) != (void(*)())SIG_IGN) 227 signal (SIGQUIT, _exit); 228 umask (((~(S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)) & S_IAMB)); 229 if (chdir (NEWS) < 0) { 230 fprintf (stderr, "Cannot chdir to %s\n", NEWS); 231 exit (1); 232 } 233 } 234 235 all_news() 236 { 237 int i; 238 239 for (i=0; i<n_count; i++) 240 print_item (n_list[i].n_name); 241 } 242 243 print_item (f) 244 char *f; 245 { 246 FILE *fd; 247 char fname[MAXNAMLEN+1]; 248 static int firstitem = 1; 249 void onintr(); 250 struct passwd *getpwuid(); 251 252 if (f == NULL) { 253 return; 254 } 255 strncpy (fname, f, MAXNAMLEN); 256 fname[MAXNAMLEN] = '\0'; 257 if ((fd = fopen (fname, "r")) == NULL) 258 printf ("Cannot open %s/%s\n", NEWS, fname); 259 else { 260 register int c, ip, op; 261 struct stat sbuf; 262 struct passwd *pw; 263 264 fstat (fileno (fd), &sbuf); 265 if (firstitem) { 266 firstitem = 0; 267 putchar ('\n'); 268 } 269 if (setjmp(save_addr)) 270 goto finish; 271 if (signal(SIGINT, SIG_IGN) != (void(*)())SIG_IGN) 272 signal(SIGINT, onintr); 273 printf ("%s ", fname); 274 pw = getpwuid (sbuf.st_uid); 275 if (pw) 276 printf ("(%s)", pw->pw_name); 277 else 278 printf ("....."); 279 cftime(time_buf, DATE_FMT, &sbuf.st_mtime); 280 printf (" %s\n", time_buf); 281 op = 0; 282 ip = INDENT; 283 while ((c = getc (fd)) != EOF) { 284 switch (c) { 285 286 case '\r': 287 case '\n': 288 putchar (c); 289 op = 0; 290 ip = INDENT; 291 break; 292 293 case ' ': 294 ip++; 295 break; 296 297 case '\b': 298 if (ip > INDENT) 299 ip--; 300 break; 301 302 case '\t': 303 ip = ((ip - INDENT + 8) & -8) + INDENT; 304 break; 305 306 default: 307 while (ip < op) { 308 putchar ('\b'); 309 op--; 310 } 311 while ((ip & -8) > (op & -8)) { 312 putchar ('\t'); 313 op = (op + 8) & -8; 314 } 315 while (ip > op) { 316 putchar (' '); 317 op++; 318 } 319 putchar (c); 320 ip++; 321 op++; 322 break; 323 } 324 } 325 fflush (stdout); 326 finish: 327 putchar ('\n'); 328 fclose (fd); 329 number_read++; 330 if (signal(SIGINT, SIG_IGN) != (void(*)())SIG_IGN) 331 signal(SIGINT, SIG_DFL); 332 } 333 } 334 335 late_news (emit, update) 336 int (*emit)(), update; 337 { 338 long cutoff; 339 int i; 340 char fname[50], *cp; 341 struct stat newstime; 342 int fd; 343 struct { 344 long actime, modtime; 345 } utb; 346 extern char *getenv(); 347 348 /* Determine the time when last called */ 349 cp = getenv ("HOME"); 350 if (cp == NULL) { 351 fprintf (stderr, "Cannot find HOME variable\n"); 352 exit (1); 353 } 354 strcpy (fname, cp); 355 strcat (fname, "/"); 356 strcat (fname, ".news_time"); 357 cutoff = stat (fname, &newstime) < 0? 0: newstime.st_mtime; 358 359 /* Print the recent items */ 360 for (i=0; i<n_count && n_list[i].n_time > cutoff; i++) { 361 (*emit) (n_list[i].n_name); 362 number_read++; 363 } 364 (*emit) ((char *) NULL); 365 fflush (stdout); 366 367 if (update) { 368 /* Re-create the file and refresh the update time */ 369 if (n_count > 0 && (fd = creat (fname, RD_WR_ALL)) >= 0) { 370 utb.actime = utb.modtime = n_list[0].n_time; 371 close (fd); 372 utime (fname, &utb); 373 } 374 } 375 } 376 377 notify (s) 378 char *s; 379 { 380 static int first = 1; 381 382 if (s) { 383 if (first) { 384 first = 0; 385 printf ("news:", NEWS); 386 } 387 printf (" %.14s", s); 388 } else if (!first) 389 putchar ('\n'); 390 } 391 392 /*ARGSUSED*/ 393 count (s) 394 char *s; 395 { 396 static int nitems = 0; 397 398 if (s) 399 nitems++; 400 else { 401 if (nitems) { 402 printf ("%d news item", nitems); 403 if (nitems != 1) 404 putchar ('s'); 405 printf (".\n"); 406 } 407 else printf("No news.\n"); 408 } 409 } 410 411 void 412 onintr() 413 { 414 sleep(2); 415 longjmp(save_addr, 1); 416 } 417 ck_num() 418 { 419 if (sopt && !number_read) printf("No news.\n"); 420 return(0); 421 } 422 423