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