Print this page
10120 smatch indenting fixes for usr/src/cmd
Reviewed by: Gergő Doma <domag02@gmail.com>
Portions contributed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/write/write.c
+++ new/usr/src/cmd/write/write.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License, Version 1.0 only
6 6 * (the "License"). You may not use this file except in compliance
7 7 * with the License.
8 8 *
9 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 10 * or http://www.opensolaris.org/os/licensing.
11 11 * See the License for the specific language governing permissions
12 12 * and limitations under the License.
13 13 *
14 14 * When distributing Covered Code, include this CDDL HEADER in each
15 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 16 * If applicable, add the following below this CDDL HEADER, with the
17 17 * fields enclosed by brackets "[]" replaced with your own identifying
18 18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 19 *
↓ open down ↓ |
19 lines elided |
↑ open up ↑ |
20 20 * CDDL HEADER END
21 21 */
22 22 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
23 23 /* All Rights Reserved */
24 24
25 25
26 26 /*
27 27 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
28 28 * Use is subject to license terms.
29 29 * Copyright (c) 2016 by Delphix. All rights reserved.
30 + * Copyright (c) 2018, Joyent, Inc.
30 31 */
31 32
32 33 #pragma ident "%Z%%M% %I% %E% SMI"
33 34
34 35 #include <ctype.h>
35 36 #include <string.h>
36 37 #include <stdio.h>
37 38 #include <signal.h>
38 39 #include <sys/wait.h>
39 40 #include <sys/types.h>
40 41 #include <sys/stat.h>
41 42 #include <sys/utsname.h>
42 43 #include <stdlib.h>
43 44 #include <unistd.h>
44 45 #include <time.h>
45 46 #include <utmpx.h>
46 47 #include <pwd.h>
47 48 #include <fcntl.h>
48 49 #include <stdarg.h>
49 50 #include <locale.h>
50 51 #include <stdlib.h>
51 52 #include <limits.h>
52 53 #include <wctype.h>
53 54 #include <errno.h>
54 55 #include <syslog.h>
55 56
56 57 #define TRUE 1
57 58 #define FALSE 0
58 59 #define FAILURE -1
59 60 #define DATE_FMT "%a %b %e %H:%M:%S"
60 61 #define UTMP_HACK /* work around until utmpx is world writable */
61 62 /*
62 63 * DATE-TIME format
63 64 * %a abbreviated weekday name
64 65 * %b abbreviated month name
65 66 * %e day of month
66 67 * %H hour - 24 hour clock
67 68 * %M minute
68 69 * %S second
69 70 *
70 71 */
71 72
72 73 static int permit1(int);
73 74 static int permit(char *);
74 75 static int readcsi(int, char *, int);
75 76 static void setsignals();
76 77 static void shellcmd(char *);
77 78 static void openfail();
78 79 static void eof();
79 80
80 81 static struct utsname utsn;
81 82
82 83 static FILE *fp; /* File pointer for receipient's terminal */
83 84 static char *rterm, *receipient; /* Pointer to receipient's terminal & name */
84 85 static char *thissys;
85 86
86 87 int
87 88 main(int argc, char **argv)
88 89 {
89 90 int i;
90 91 struct utmpx *ubuf;
91 92 static struct utmpx self;
92 93 char ownname[sizeof (self.ut_user) + 1];
93 94 static char rterminal[sizeof ("/dev/") + sizeof (self.ut_line)] =
94 95 "/dev/";
95 96 extern char *rterm, *receipient;
96 97 char *terminal, *ownterminal, *oterminal;
97 98 short count;
98 99 extern FILE *fp;
99 100 char input[134+MB_LEN_MAX];
100 101 char *ptr;
101 102 time_t tod;
102 103 char time_buf[40];
103 104 struct passwd *passptr;
104 105 char badterm[20][20];
105 106 int bad = 0;
106 107 uid_t myuid;
107 108 char *bp;
108 109 int n;
109 110 wchar_t wc;
110 111 int c;
111 112 int newline;
112 113
113 114 (void) setlocale(LC_ALL, "");
114 115 #if !defined(TEXT_DOMAIN)
115 116 #define TEXT_DOMAIN "SYS_TEST"
116 117 #endif
117 118 (void) textdomain(TEXT_DOMAIN);
118 119
119 120 while ((c = getopt(argc, argv, "")) != EOF)
120 121 switch (c) {
121 122 case '?':
122 123 (void) fprintf(stderr, "Usage: write %s\n",
123 124 gettext("user_name [terminal]"));
124 125 exit(2);
125 126 }
126 127 myuid = geteuid();
127 128 uname(&utsn);
128 129 thissys = utsn.nodename;
129 130
130 131 /* Set "rterm" to location where receipient's terminal will go. */
131 132
132 133 rterm = &rterminal[sizeof ("/dev/") - 1];
133 134 terminal = NULL;
134 135
135 136 if (--argc <= 0) {
136 137 (void) fprintf(stderr, "Usage: write %s\n",
137 138 gettext("user_name [terminal]"));
138 139 exit(1);
139 140 }
140 141 else
141 142 {
142 143 receipient = *++argv;
143 144 }
144 145
145 146 /* Was a terminal name supplied? If so, save it. */
146 147
147 148 if (--argc > 1) {
148 149 (void) fprintf(stderr, "Usage: write %s\n",
149 150 gettext("user_name [terminal]"));
150 151 exit(1);
151 152 } else {
152 153 terminal = *++argv;
153 154 }
154 155
155 156 /* One of the standard file descriptors must be attached to a */
156 157 /* terminal in "/dev". */
157 158
158 159 if ((ownterminal = ttyname(fileno(stdin))) == NULL &&
159 160 (ownterminal = ttyname(fileno(stdout))) == NULL &&
160 161 (ownterminal = ttyname(fileno(stderr))) == NULL) {
161 162 (void) fprintf(stderr,
162 163 gettext("I cannot determine your terminal name."
163 164 " No reply possible.\n"));
164 165 ownterminal = "/dev/???";
165 166 }
166 167
167 168 /*
168 169 * Set "ownterminal" past the "/dev/" at the beginning of
169 170 * the device name.
170 171 */
171 172 oterminal = ownterminal + sizeof ("/dev/")-1;
172 173
173 174 /*
174 175 * Scan through the "utmpx" file for your own entry and the
175 176 * entry for the person we want to send to.
176 177 */
177 178 for (self.ut_pid = 0, count = 0; (ubuf = getutxent()) != NULL; ) {
178 179 /* Is this a USER_PROCESS entry? */
179 180
180 181 if (ubuf->ut_type == USER_PROCESS) {
181 182 /* Is it our entry? (ie. The line matches ours?) */
182 183
183 184 if (strncmp(&ubuf->ut_line[0], oterminal,
184 185 sizeof (ubuf->ut_line)) == 0) self = *ubuf;
185 186
186 187 /* Is this the person we want to send to? */
187 188
188 189 if (strncmp(receipient, &ubuf->ut_user[0],
189 190 sizeof (ubuf->ut_user)) == 0) {
190 191 /* If a terminal name was supplied, is this login at the correct */
191 192 /* terminal? If not, ignore. If it is right place, copy over the */
192 193 /* name. */
193 194
194 195 if (terminal != NULL) {
195 196 if (strncmp(terminal, &ubuf->ut_line[0],
196 197 sizeof (ubuf->ut_line)) == 0) {
197 198 strlcpy(rterm, &ubuf->ut_line[0],
198 199 sizeof (rterminal) - (rterm - rterminal));
199 200 if (myuid && !permit(rterminal)) {
200 201 bad++;
201 202 rterm[0] = '\0';
202 203 }
203 204 }
204 205 }
205 206
206 207 /* If no terminal was supplied, then take this terminal if no */
207 208 /* other terminal has been encountered already. */
208 209
209 210 else
210 211 {
211 212 /* If this is the first encounter, copy the string into */
212 213 /* "rterminal". */
213 214
214 215 if (*rterm == '\0') {
215 216 strlcpy(rterm, &ubuf->ut_line[0],
216 217 sizeof (rterminal) - (rterm - rterminal));
217 218 if (myuid && !permit(rterminal)) {
218 219 if (bad < 20) {
219 220 strlcpy(badterm[bad++], rterm,
220 221 sizeof (badterm[bad++]));
221 222 }
222 223 rterm[0] = '\0';
223 224 } else if (bad > 0) {
224 225 (void) fprintf(stderr,
225 226 gettext(
226 227 "%s is logged on more than one place.\n"
227 228 "You are connected to \"%s\".\nOther locations are:\n"),
228 229 receipient, rterm);
229 230 for (i = 0; i < bad; i++)
230 231 (void) fprintf(stderr, "%s\n", badterm[i]);
231 232 }
232 233 }
233 234
234 235 /* If this is the second terminal, print out the first. In all */
235 236 /* cases of multiple terminals, list out all the other terminals */
236 237 /* so the user can restart knowing what their choices are. */
237 238
238 239 else if (terminal == NULL) {
239 240 if (count == 1 && bad == 0) {
240 241 (void) fprintf(stderr,
241 242 gettext(
242 243 "%s is logged on more than one place.\n"
243 244 "You are connected to \"%s\".\nOther locations are:\n"),
244 245 receipient, rterm);
245 246 }
246 247 fwrite(&ubuf->ut_line[0], sizeof (ubuf->ut_line),
247 248 1, stderr);
248 249 (void) fprintf(stderr, "\n");
249 250 }
250 251
251 252 count++;
252 253 } /* End of "else" */
253 254 } /* End of "else if (strncmp" */
254 255 } /* End of "if (USER_PROCESS" */
255 256 } /* End of "for(count=0" */
256 257
257 258 /* Did we find a place to talk to? If we were looking for a */
258 259 /* specific spot and didn't find it, complain and quit. */
259 260
260 261 if (terminal != NULL && *rterm == '\0') {
261 262 if (bad > 0) {
262 263 (void) fprintf(stderr, gettext("Permission denied.\n"));
263 264 exit(1);
264 265 } else {
265 266 #ifdef UTMP_HACK
266 267 if (strlcat(rterminal, terminal, sizeof (rterminal)) >=
↓ open down ↓ |
227 lines elided |
↑ open up ↑ |
267 268 sizeof (rterminal)) {
268 269 (void) fprintf(stderr,
269 270 gettext("Terminal name too long.\n"));
270 271 exit(1);
271 272 }
272 273 if (self.ut_pid == 0) {
273 274 if ((passptr = getpwuid(getuid())) == NULL) {
274 275 (void) fprintf(stderr,
275 276 gettext("Cannot determine who you are.\n"));
276 277 exit(1);
277 - }
278 - (void) strlcpy(&ownname[0], &passptr->pw_name[0],
279 - sizeof (ownname));
278 + }
279 + (void) strlcpy(&ownname[0], &passptr->pw_name[0],
280 + sizeof (ownname));
280 281 } else {
281 282 (void) strlcpy(&ownname[0], self.ut_user,
282 283 sizeof (self.ut_user));
283 284 }
284 285 if (!permit(rterminal)) {
285 286 (void) fprintf(stderr,
286 287 gettext("%s permission denied\n"), terminal);
287 288 exit(1);
288 289 }
289 290 #else
290 291 (void) fprintf(stderr, gettext("%s is not at \"%s\".\n"),
291 292 receipient, terminal);
292 293 exit(1);
293 294 #endif /* UTMP_HACK */
294 295 }
295 296 }
296 297
297 298 /* If we were just looking for anyplace to talk and didn't find */
298 299 /* one, complain and quit. */
299 300 /* If permissions prevent us from sending to this person - exit */
300 301
301 302 else if (*rterm == '\0') {
302 303 if (bad > 0)
303 304 (void) fprintf(stderr, gettext("Permission denied.\n"));
304 305 else
305 306 (void) fprintf(stderr,
306 307 gettext("%s is not logged on.\n"), receipient);
307 308 exit(1);
308 309 }
309 310
310 311 /* Did we find our own entry? */
311 312
312 313 else if (self.ut_pid == 0) {
313 314 /* Use the user id instead of utmp name if the entry in the */
314 315 /* utmp file couldn't be found. */
315 316
316 317 if ((passptr = getpwuid(getuid())) == (struct passwd *)NULL) {
317 318 (void) fprintf(stderr,
318 319 gettext("Cannot determine who you are.\n"));
319 320 exit(1);
320 321 }
321 322 strncpy(&ownname[0], &passptr->pw_name[0], sizeof (ownname));
322 323 }
323 324 else
324 325 {
325 326 strncpy(&ownname[0], self.ut_user, sizeof (self.ut_user));
326 327 }
327 328 ownname[sizeof (ownname)-1] = '\0';
328 329
329 330 if (!permit1(1))
330 331 (void) fprintf(stderr,
331 332 gettext("Warning: You have your terminal set to \"mesg -n\"."
332 333 " No reply possible.\n"));
333 334 /* Close the utmpx files. */
334 335
335 336 endutxent();
336 337
337 338 /* Try to open up the line to the receipient's terminal. */
338 339
339 340 signal(SIGALRM, openfail);
340 341 alarm(5);
341 342 fp = fopen(&rterminal[0], "w");
342 343 alarm(0);
343 344
344 345 /* Make sure executed subshell doesn't inherit this fd - close-on-exec */
345 346
346 347 if (fcntl(fileno(fp), F_SETFD, FD_CLOEXEC) < 0) {
347 348 perror("fcntl(F_SETFD)");
348 349 exit(1);
349 350 }
350 351
351 352 /* Catch signals SIGHUP, SIGINT, SIGQUIT, and SIGTERM, and send */
352 353 /* <EOT> message to receipient before dying away. */
353 354
354 355 setsignals(eof);
355 356
356 357 /* Get the time of day, convert it to a string and throw away the */
357 358 /* year information at the end of the string. */
358 359
359 360 time(&tod);
360 361 (void) strftime(time_buf, sizeof (time_buf),
361 362 dcgettext(NULL, DATE_FMT, LC_TIME), localtime(&tod));
362 363
363 364 (void) fprintf(fp,
364 365 gettext("\n\007\007\007\tMessage from %s on %s (%s) [ %s ] ...\n"),
365 366 &ownname[0], thissys, oterminal, time_buf);
366 367 fflush(fp);
367 368 (void) fprintf(stderr, "\007\007");
368 369
369 370 /* Get input from user and send to receipient unless it begins */
370 371 /* with a !, when it is to be a shell command. */
371 372 newline = 1;
372 373 while ((i = readcsi(0, &input[0], sizeof (input))) > 0) {
373 374 ptr = &input[0];
374 375 /* Is this a shell command? */
375 376
376 377 if ((newline) && (*ptr == '!'))
377 378 shellcmd(++ptr);
378 379
379 380 /* Send line to the receipient. */
380 381
381 382 else {
382 383 if (myuid && !permit1(fileno(fp))) {
383 384 (void) fprintf(stderr,
384 385 gettext("Can no longer write to %s\n"), rterminal);
385 386 break;
386 387 }
387 388
388 389 /*
389 390 * All non-printable characters are displayed using a special notation:
390 391 * Control characters shall be displayed using the two character
391 392 * sequence of ^ (carat) and the ASCII character - decimal 64 greater
392 393 * that the character being encoded - eg., a \003 is displayed ^C.
393 394 * Characters with the eighth bit set shall be displayed using
394 395 * the three or four character meta notation - e.g., \372 is
395 396 * displayed M-z and \203 is displayed M-^C.
396 397 */
397 398
398 399 newline = 0;
399 400 for (bp = &input[0]; --i >= 0; bp++) {
400 401 if (*bp == '\n') {
401 402 newline = 1;
402 403 putc('\r', fp);
403 404 }
404 405 if (*bp == ' ' ||
405 406 *bp == '\t' || *bp == '\n' ||
406 407 *bp == '\r' || *bp == '\013' ||
407 408 *bp == '\007') {
408 409 putc(*bp, fp);
409 410 } else if (((n = mbtowc(&wc, bp, MB_CUR_MAX)) > 0) &&
410 411 iswprint(wc)) {
411 412 for (; n > 0; --n, --i, ++bp)
412 413 putc(*bp, fp);
413 414 bp--, ++i;
414 415 } else {
415 416 if (!isascii(*bp)) {
416 417 fputs("M-", fp);
417 418 *bp = toascii(*bp);
418 419 }
419 420 if (iscntrl(*bp)) {
420 421 putc('^', fp);
421 422 /* add decimal 64 to the control character */
422 423 putc(*bp + 0100, fp);
423 424 }
424 425 else
425 426 putc(*bp, fp);
426 427 }
427 428 if (*bp == '\n')
428 429 fflush(fp);
429 430 if (ferror(fp) || feof(fp)) {
430 431 printf(gettext(
431 432 "\n\007Write failed (%s logged out?)\n"),
432 433 receipient);
433 434 exit(1);
434 435 }
435 436 } /* for */
436 437 fflush(fp);
437 438 } /* else */
438 439 } /* while */
439 440
440 441 /* Since "end of file" received, send <EOT> message to receipient. */
441 442
442 443 eof();
443 444 return (0);
444 445 }
445 446
446 447
447 448 static void
448 449 setsignals(catch)
449 450 void (*catch)();
450 451 {
451 452 signal(SIGHUP, catch);
452 453 signal(SIGINT, catch);
453 454 signal(SIGQUIT, catch);
454 455 signal(SIGTERM, catch);
455 456 }
456 457
457 458
458 459 static void
459 460 shellcmd(command)
460 461 char *command;
461 462 {
462 463 register pid_t child;
463 464 extern void eof();
464 465
465 466 if ((child = fork()) == (pid_t)FAILURE)
466 467 {
467 468 (void) fprintf(stderr,
468 469 gettext("Unable to fork. Try again later.\n"));
469 470 return;
470 471 } else if (child == (pid_t)0) {
471 472 /* Reset the signals to the default actions and exec a shell. */
472 473
473 474 if (setgid(getgid()) < 0)
474 475 exit(1);
475 476 execl("/usr/bin/sh", "sh", "-c", command, 0);
476 477 exit(0);
477 478 }
478 479 else
479 480 {
480 481 /* Allow user to type <del> and <quit> without dying during */
481 482 /* commands. */
482 483
483 484 signal(SIGINT, SIG_IGN);
484 485 signal(SIGQUIT, SIG_IGN);
485 486
486 487 /* As parent wait around for user to finish spunoff command. */
487 488
488 489 while (wait(NULL) != child);
489 490
490 491 /* Reset the signals to their normal state. */
491 492
492 493 setsignals(eof);
493 494 }
494 495 (void) fprintf(stdout, "!\n");
495 496 }
496 497
497 498 static void
498 499 openfail()
499 500 {
500 501 extern char *rterm, *receipient;
501 502
502 503 (void) fprintf(stderr,
503 504 gettext("Timeout trying to open %s's line(%s).\n"),
504 505 receipient, rterm);
505 506 exit(1);
506 507 }
507 508
508 509 static void
509 510 eof()
510 511 {
511 512 extern FILE *fp;
512 513
513 514 (void) fprintf(fp, "%s\n", gettext("<EOT>"));
514 515 exit(0);
515 516 }
516 517
517 518 /*
518 519 * permit: check mode of terminal - if not writable by all disallow writing to
519 520 * (even the user cannot therefore write to their own tty)
520 521 */
521 522
522 523 static int
523 524 permit(term)
524 525 char *term;
525 526 {
526 527 struct stat buf;
527 528 int fildes;
528 529
529 530 if ((fildes = open(term, O_WRONLY|O_NOCTTY)) < 0)
530 531 return (0);
531 532 /* check if the device really is a tty */
532 533 if (!isatty(fildes)) {
533 534 (void) fprintf(stderr,
534 535 gettext("%s in utmpx is not a tty\n"), term);
535 536 openlog("write", 0, LOG_AUTH);
536 537 syslog(LOG_CRIT, "%s in utmpx is not a tty\n", term);
537 538 closelog();
538 539 close(fildes);
539 540 return (0);
540 541 }
541 542 fstat(fildes, &buf);
542 543 close(fildes);
543 544 return (buf.st_mode & (S_IWGRP|S_IWOTH));
544 545 }
545 546
546 547
547 548
548 549 /*
549 550 * permit1: check mode of terminal - if not writable by all disallow writing
550 551 * to (even the user themself cannot therefore write to their own tty)
551 552 */
552 553
553 554 /* this is used with fstat (which is faster than stat) where possible */
554 555
555 556 static int
556 557 permit1(fildes)
557 558 int fildes;
558 559 {
559 560 struct stat buf;
560 561
561 562 fstat(fildes, &buf);
562 563 return (buf.st_mode & (S_IWGRP|S_IWOTH));
563 564 }
564 565
565 566
566 567 /*
567 568 * Read a string of multi-byte characters from specified file.
568 569 * The requested # of bytes are attempted to read.
569 570 * readcsi() tries to complete the last multibyte character
570 571 * by calling mbtowc(), if the leftovers form mbtowc(),
571 572 * left the last char imcomplete, moves into delta_spool to use later,
572 573 * next called. The caller must reserve
573 574 * nbytereq+MB_LEN_MAX bytes for the buffer. When the attempt
574 575 * is failed, it truncate the last char.
575 576 * Returns the number of bytes that constitutes the valid multi-byte characters.
576 577 */
577 578
578 579
579 580 static int readcsi(d, buf, nbytereq)
580 581 int d;
581 582 char *buf;
582 583 int nbytereq;
583 584 {
584 585 static char delta_pool[MB_LEN_MAX * 2];
585 586 static char delta_size;
586 587 char *cp, *nextp, *lastp;
587 588 int n;
588 589 int r_size;
589 590
590 591 if (delta_size) {
591 592 memcpy(buf, delta_pool, delta_size);
592 593 cp = buf + delta_size;
593 594 r_size = nbytereq - delta_size;
594 595 } else {
595 596 cp = buf;
596 597 r_size = nbytereq;
597 598 }
598 599
599 600 if ((r_size = read(d, cp, r_size)) < 0)
600 601 r_size = 0;
601 602 if ((n = delta_size + r_size) <= 0)
602 603 return (n);
603 604
604 605 /* Scan the result to test the completeness of each EUC characters. */
605 606 nextp = buf;
606 607 lastp = buf + n; /* Lastp points to the first junk byte. */
607 608 while (nextp < lastp) {
608 609 if ((n = (lastp - nextp)) > (unsigned int)MB_CUR_MAX)
609 610 n = (unsigned int)MB_CUR_MAX;
610 611 if ((n = mbtowc((wchar_t *)0, nextp, n)) <= 0) {
611 612 if ((lastp - nextp) < (unsigned int)MB_CUR_MAX)
612 613 break;
613 614 n = 1;
614 615 }
615 616 nextp += n;
616 617 }
617 618 /* How many bytes needed to complete the last char? */
618 619 delta_size = lastp - nextp;
619 620 if (delta_size > 0) {
620 621 if (nextp[delta_size - 1] != '\n') {
621 622 /* the remnants store into delta_pool */
622 623 memcpy(delta_pool, nextp, delta_size);
623 624 } else
624 625 nextp = lastp;
625 626 }
626 627 *nextp = '\0';
627 628 return (nextp-buf); /* Return # of bytes. */
628 629 }
↓ open down ↓ |
339 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX