xref: /openbsd-src/bin/ps/print.c (revision 1a8dbaac879b9f3335ad7fb25429ce63ac1d6bac)
1 /*	$OpenBSD: print.c,v 1.75 2020/08/03 00:09:01 deraadt Exp $	*/
2 /*	$NetBSD: print.c,v 1.27 1995/09/29 21:58:12 cgd Exp $	*/
3 
4 /*-
5  * Copyright (c) 1990, 1993, 1994
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 
33 #include <sys/param.h>	/* MAXCOMLEN PZERO NODEV */
34 #include <sys/types.h>
35 #include <sys/proc.h>
36 #include <sys/stat.h>
37 
38 #include <sys/sysctl.h>
39 #define PLEDGENAMES
40 #include <sys/pledge.h>
41 
42 #include <err.h>
43 #include <grp.h>
44 #include <kvm.h>
45 #include <math.h>
46 #include <nlist.h>
47 #include <stddef.h>
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <string.h>
51 #include <unistd.h>
52 #include <limits.h>
53 #include <pwd.h>
54 
55 #include "ps.h"
56 
57 extern kvm_t *kd;
58 extern int needenv, needcomm, neednlist, commandonly;
59 
60 int mbswprint(const char *, int, int);  /* utf8.c */
61 
62 static char *cmdpart(char *);
63 
64 #define	min(a,b)	((a) < (b) ? (a) : (b))
65 
66 static char *
67 cmdpart(char *arg0)
68 {
69 	char *cp;
70 
71 	return ((cp = strrchr(arg0, '/')) != NULL ? cp + 1 : arg0);
72 }
73 
74 void
75 printheader(void)
76 {
77 	VAR *v;
78 	struct varent *vent;
79 
80 	if (!needheader)
81 		return;
82 	for (vent = vhead; vent; vent = vent->next) {
83 		v = vent->var;
84 		if (v->flag & LJUST) {
85 			if (vent->next == NULL)	/* last one */
86 				(void)printf("%s", v->header);
87 			else
88 				(void)printf("%-*s", v->width, v->header);
89 		} else
90 			(void)printf("%*s", v->width, v->header);
91 		if (vent->next != NULL)
92 			(void)putchar(' ');
93 	}
94 	(void)putchar('\n');
95 }
96 
97 void
98 command(const struct kinfo_proc *kp, VARENT *ve)
99 {
100 	VAR *v;
101 	int left, wantspace = 0;
102 	char **p;
103 
104 	/*
105 	 * Determine the available number of display columns.
106 	 * Always decrement and check after writing.
107 	 * No check is needed before mbswprint()
108 	 * and after writing the last data, though.
109 	 */
110 
111 	v = ve->var;
112 	if (ve->next != NULL || termwidth != UNLIMITED) {
113 		if (ve->next == NULL) {
114 			left = termwidth - (totwidth - v->width);
115 			if (left < 1) /* already wrapped, just use std width */
116 				left = v->width;
117 		} else
118 			left = v->width;
119 	} else
120 		left = INT_MAX;
121 
122 	if (needenv && kd != NULL) {
123 		char **envp = kvm_getenvv(kd, kp, termwidth);
124 		if ((p = envp) != NULL) {
125 			while (*p) {
126 				if (wantspace) {
127 					putchar(' ');
128 					left--;
129 				}
130 				left -= mbswprint(*p, left, 0);
131 				if (left == 0)
132 					return;
133 				p++;
134 				wantspace = 1;
135 			}
136 		}
137 	}
138 
139 	if (needcomm) {
140 		if (!commandonly) {
141 			char **argv = NULL;
142 
143 			if (kd != NULL) {
144 				argv = kvm_getargv(kd, kp, termwidth);
145 				if ((p = argv) != NULL) {
146 					while (*p) {
147 						if (wantspace) {
148 							putchar(' ');
149 							left--;
150 						}
151 						left -= mbswprint(*p, left, 0);
152 						if (left == 0)
153 							return;
154 						p++;
155 						wantspace = 1;
156 					}
157 				}
158 			}
159 			if (argv == NULL || argv[0] == NULL ||
160 			    strcmp(cmdpart(argv[0]), kp->p_comm)) {
161 				if (wantspace) {
162 					putchar(' ');
163 					if (--left == 0)
164 						return;
165 				}
166 				putchar('(');
167 				left--;
168 				left -= mbswprint(kp->p_comm, left, 0);
169 				if (left == 0)
170 					return;
171 				putchar(')');
172 				left--;
173 			}
174 		} else {
175 			if (wantspace) {
176 				putchar(' ');
177 				left--;
178 			}
179 			left -= mbswprint(kp->p_comm, left, 0);
180 		}
181 	}
182 	if (ve->next != NULL)
183 		while (left-- > 0)
184 			putchar(' ');
185 }
186 
187 void
188 ucomm(const struct kinfo_proc *kp, VARENT *ve)
189 {
190 	mbswprint(kp->p_comm, ve->var->width, ve->next != NULL);
191 }
192 
193 void
194 curwd(const struct kinfo_proc *kp, VARENT *ve)
195 {
196 	int name[] = { CTL_KERN, KERN_PROC_CWD, kp->p_pid };
197 	char path[PATH_MAX];
198 	size_t pathlen = sizeof path;
199 
200 	if (!kvm_sysctl_only || sysctl(name, 3, path, &pathlen, NULL, 0) != 0)
201 		*path = '\0';
202 
203 	mbswprint(path, ve->var->width, ve->next != NULL);
204 }
205 
206 void
207 logname(const struct kinfo_proc *kp, VARENT *ve)
208 {
209 	VAR *v;
210 
211 	v = ve->var;
212 	if (kp->p_login[0]) {
213 		int n = min(v->width, LOGIN_NAME_MAX);
214 		mbswprint(kp->p_login, n, ve->next != NULL);
215 		if (ve->next != NULL)
216 			while (n++ < v->width)
217 				putchar(' ');
218 	} else
219 		(void)printf("%-*s", v->width, "-");
220 }
221 
222 #define pgtok(a)	(((unsigned long long)(a)*getpagesize())/1024)
223 
224 void
225 printstate(const struct kinfo_proc *kp, VARENT *ve)
226 {
227 	int flag;
228 	char *cp, state = '\0';
229 	VAR *v;
230 	char buf[16];
231 
232 	v = ve->var;
233 	flag = kp->p_flag;
234 	cp = buf;
235 
236 	switch (kp->p_stat) {
237 
238 	case SSTOP:
239 		*cp = 'T';
240 		break;
241 
242 	case SSLEEP:
243 		if (flag & P_SINTR)	/* interruptible (long) */
244 			*cp = kp->p_slptime >= maxslp ? 'I' : 'S';
245 		else
246 			*cp = 'D';
247 		break;
248 
249 	case SRUN:
250 	case SIDL:
251 	case SONPROC:
252 		state = *cp = 'R';
253 		break;
254 
255 	case SDEAD:
256 		*cp = 'Z';
257 		break;
258 
259 	default:
260 		*cp = '?';
261 	}
262 	cp++;
263 
264 	if (kp->p_nice < NZERO)
265 		*cp++ = '<';
266 	else if (kp->p_nice > NZERO)
267 		*cp++ = 'N';
268 	if (kp->p_psflags & PS_TRACED)
269 		*cp++ = 'X';
270 	if ((kp->p_psflags & (PS_EXITING | PS_ZOMBIE)) == PS_EXITING)
271 		*cp++ = 'E';
272 	if (kp->p_psflags & PS_ISPWAIT)
273 		*cp++ = 'V';
274 	if (flag & P_SYSTEM)
275 		*cp++ = 'K';
276 	if ((flag & P_SYSTEM) == 0 &&
277 	    kp->p_rlim_rss_cur / 1024 < pgtok(kp->p_vm_rssize))
278 		*cp++ = '>';
279 	if (kp->p_eflag & EPROC_SLEADER)
280 		*cp++ = 's';
281 	if ((kp->p_psflags & PS_CONTROLT) && kp->p__pgid == kp->p_tpgid)
282 		*cp++ = '+';
283 	if (kp->p_psflags & PS_PLEDGE)
284 		*cp++ = 'p';
285 	if (kp->p_eflag & EPROC_UNVEIL) {
286 		if (kp->p_eflag & EPROC_LKUNVEIL)
287 			*cp++ = 'U';
288 		else
289 			*cp++ = 'u';
290 	}
291 	*cp = '\0';
292 
293 	if (state == 'R' && kp->p_cpuid != KI_NOCPU) {
294 		char pbuf[16];
295 
296 		snprintf(pbuf, sizeof pbuf, "/%llu", kp->p_cpuid);
297 		*++cp = '\0';
298 		strlcat(buf, pbuf, sizeof buf);
299 		cp = buf + strlen(buf);
300 	}
301 
302 	(void)printf("%-*s", v->width, buf);
303 }
304 
305 void
306 printpledge(const struct kinfo_proc *kp, VARENT *ve)
307 {
308 	int flag, i;
309 	char *cp, state = '\0';
310 	VAR *v;
311 	char buf[1024];
312 
313 	v = ve->var;
314 	buf[0] = '\0';
315 
316 	for (i = 0; pledgenames[i].bits != 0; i++) {
317 		if (pledgenames[i].bits & kp->p_pledge) {
318 			if (*buf != '\0')
319 				strlcat(buf, ",", sizeof buf);
320 			strlcat(buf, pledgenames[i].name, sizeof buf);
321 		}
322 	}
323 
324 	(void)printf("%-*s", v->width, buf);
325 }
326 
327 void
328 pri(const struct kinfo_proc *kp, VARENT *ve)
329 {
330 	VAR *v;
331 
332 	v = ve->var;
333 	(void)printf("%*d", v->width, kp->p_priority - PZERO);
334 }
335 
336 void
337 pnice(const struct kinfo_proc *kp, VARENT *ve)
338 {
339 	VAR *v;
340 	v = ve->var;
341 	(void)printf("%*d", v->width, kp->p_nice - NZERO);
342 }
343 
344 void
345 euname(const struct kinfo_proc *kp, VARENT *ve)
346 {
347 	mbswprint(user_from_uid(kp->p_uid, 0), ve->var->width,
348 	    ve->next != NULL);
349 }
350 
351 void
352 runame(const struct kinfo_proc *kp, VARENT *ve)
353 {
354 	mbswprint(user_from_uid(kp->p_ruid, 0), ve->var->width,
355 	    ve->next != NULL);
356 }
357 
358 void
359 gname(const struct kinfo_proc *kp, VARENT *ve)
360 {
361 	mbswprint(group_from_gid(kp->p_gid, 0), ve->var->width,
362 	    ve->next != NULL);
363 }
364 
365 void
366 rgname(const struct kinfo_proc *kp, VARENT *ve)
367 {
368 	mbswprint(group_from_gid(kp->p_rgid, 0), ve->var->width,
369 	    ve->next != NULL);
370 }
371 
372 void
373 tdev(const struct kinfo_proc *kp, VARENT *ve)
374 {
375 	VAR *v;
376 	dev_t dev;
377 
378 	v = ve->var;
379 	dev = kp->p_tdev;
380 	if (dev == NODEV)
381 		(void)printf("%*s", v->width, "??");
382 	else {
383 		char buff[10+1+10+1];
384 
385 		(void)snprintf(buff, sizeof(buff),
386 		    "%u/%u", major(dev), minor(dev));
387 		(void)printf("%*s", v->width, buff);
388 	}
389 }
390 
391 void
392 tname(const struct kinfo_proc *kp, VARENT *ve)
393 {
394 	VAR *v;
395 	dev_t dev;
396 	char *ttname;
397 
398 	v = ve->var;
399 	dev = kp->p_tdev;
400 	if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL)
401 		(void)printf("%-*s", v->width, "??");
402 	else {
403 		if (strncmp(ttname, "tty", 3) == 0)
404 			ttname += 3;
405 		(void)printf("%*.*s%c", v->width-1, v->width-1, ttname,
406 			kp->p_eflag & EPROC_CTTY ? ' ' : '-');
407 	}
408 }
409 
410 void
411 longtname(const struct kinfo_proc *kp, VARENT *ve)
412 {
413 	VAR *v;
414 	dev_t dev;
415 	char *ttname;
416 
417 	v = ve->var;
418 	dev = kp->p_tdev;
419 	if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL)
420 		(void)printf("%-*s", v->width, "??");
421 	else
422 		(void)printf("%-*s", v->width, ttname);
423 }
424 
425 void
426 started(const struct kinfo_proc *kp, VARENT *ve)
427 {
428 	VAR *v;
429 	static time_t now;
430 	time_t startt;
431 	struct tm *tp;
432 	char buf[100];
433 
434 	v = ve->var;
435 	if (!kp->p_uvalid) {
436 		(void)printf("%-*s", v->width, "-");
437 		return;
438 	}
439 
440 #define SECSPERHOUR	(60 * 60)
441 #define SECSPERDAY	(24 * 60 * 60)
442 
443 	startt = kp->p_ustart_sec;
444 	tp = localtime(&startt);
445 	if (!now)
446 		(void)time(&now);
447 	if (now - kp->p_ustart_sec < 12 * SECSPERHOUR) {
448 		(void)strftime(buf, sizeof(buf) - 1, "%l:%M%p", tp);
449 	} else if (now - kp->p_ustart_sec < 7 * SECSPERDAY) {
450 		(void)strftime(buf, sizeof(buf) - 1, "%a%I%p", tp);
451 	} else
452 		(void)strftime(buf, sizeof(buf) - 1, "%e%b%y", tp);
453 	(void)printf("%-*s", v->width, buf);
454 }
455 
456 void
457 lstarted(const struct kinfo_proc *kp, VARENT *ve)
458 {
459 	VAR *v;
460 	time_t startt;
461 	char buf[100];
462 
463 	v = ve->var;
464 	if (!kp->p_uvalid) {
465 		(void)printf("%-*s", v->width, "-");
466 		return;
467 	}
468 	startt = kp->p_ustart_sec;
469 	(void)strftime(buf, sizeof(buf) -1, "%c",
470 	    localtime(&startt));
471 	(void)printf("%-*s", v->width, buf);
472 }
473 
474 void elapsed(const struct kinfo_proc *kp, VARENT *ve)
475 {
476 	VAR *v;
477 	static time_t now;
478 	time_t secs;
479 	char buf[64];
480 	long days, hours, minutes, seconds;
481 
482 	v = ve->var;
483 	if (!kp->p_uvalid) {
484 		(void)printf("%*s", v->width, "-");
485 		return;
486 	}
487 
488 	if (!now)
489 		(void)time(&now);
490 	secs = now - kp->p_ustart_sec;
491 
492 	if (secs < 0) {
493 		(void)printf("%*s", v->width, "-");
494 		return;
495 	}
496 
497 	days = secs / SECSPERDAY;
498 	secs %= SECSPERDAY;
499 
500 	hours = secs / SECSPERHOUR;
501 	secs %= SECSPERHOUR;
502 
503 	minutes = secs / 60;
504 	seconds = secs % 60;
505 
506 	if (days > 0)
507 		(void)snprintf(buf, sizeof(buf), "%ld-%02ld:%02ld:%02ld",
508 		    days, hours, minutes, seconds);
509 	else if (hours > 0)
510 		(void)snprintf(buf, sizeof(buf), "%02ld:%02ld:%02ld",
511 		    hours, minutes, seconds);
512 	else
513 		(void)snprintf(buf, sizeof(buf), "%02ld:%02ld",
514 		    minutes, seconds);
515 	(void)printf("%*s", v->width, buf);
516 }
517 
518 void
519 wchan(const struct kinfo_proc *kp, VARENT *ve)
520 {
521 	VAR *v;
522 
523 	v = ve->var;
524 	if (kp->p_wmesg[0]) {
525 		(void)printf("%-*s", (int)v->width, kp->p_wmesg);
526 	} else
527 		(void)printf("%-*s", v->width, "-");
528 }
529 
530 void
531 vsize(const struct kinfo_proc *kp, VARENT *ve)
532 {
533 	VAR *v;
534 
535 	v = ve->var;
536 	(void)printf("%*llu", v->width,
537 	    pgtok(kp->p_vm_dsize + kp->p_vm_ssize + kp->p_vm_tsize));
538 }
539 
540 void
541 rssize(const struct kinfo_proc *kp, VARENT *ve)
542 {
543 	VAR *v;
544 
545 	v = ve->var;
546 	/* XXX don't have info about shared */
547 	(void)printf("%*llu", v->width, (kp->p_flag & P_SYSTEM) ? 0 :
548 	    pgtok(kp->p_vm_rssize));
549 }
550 
551 void
552 p_rssize(const struct kinfo_proc *kp, VARENT *ve)
553 {
554 	VAR *v;
555 
556 	v = ve->var;
557 	(void)printf("%*llu", v->width, (kp->p_flag & P_SYSTEM) ? 0 :
558 	    pgtok(kp->p_vm_rssize));
559 }
560 
561 void
562 cputime(const struct kinfo_proc *kp, VARENT *ve)
563 {
564 	VAR *v;
565 	long secs;
566 	long psecs;	/* "parts" of a second. first micro, then centi */
567 	char obuff[128];
568 
569 	v = ve->var;
570 	if (kp->p_stat == SDEAD || !kp->p_uvalid) {
571 		secs = 0;
572 		psecs = 0;
573 	} else {
574 		/*
575 		 * This counts time spent handling interrupts.  XXX
576 		 */
577 		secs = kp->p_rtime_sec;
578 		psecs = kp->p_rtime_usec;
579 		if (sumrusage) {
580 			secs += kp->p_uctime_sec;
581 			psecs += kp->p_uctime_usec;
582 		}
583 		/*
584 		 * round and scale to 100's
585 		 */
586 		psecs = (psecs + 5000) / 10000;
587 		secs += psecs / 100;
588 		psecs = psecs % 100;
589 	}
590 	(void)snprintf(obuff, sizeof(obuff),
591 	    "%3ld:%02ld.%02ld", secs/60, secs%60, psecs);
592 	(void)printf("%*s", v->width, obuff);
593 }
594 
595 double
596 getpcpu(const struct kinfo_proc *kp)
597 {
598 	if (fscale == 0)
599 		return (0.0);
600 
601 #define	fxtofl(fixpt)	((double)(fixpt) / fscale)
602 
603 	return (100.0 * fxtofl(kp->p_pctcpu));
604 }
605 
606 void
607 pcpu(const struct kinfo_proc *kp, VARENT *ve)
608 {
609 	VAR *v;
610 
611 	v = ve->var;
612 	(void)printf("%*.1f", v->width, getpcpu(kp));
613 }
614 
615 double
616 getpmem(const struct kinfo_proc *kp)
617 {
618 	double fracmem;
619 
620 	if (mempages == 0)
621 		return (0.0);
622 
623 	if (kp->p_flag & P_SYSTEM)
624 		return (0.0);
625 	/* XXX don't have info about shared */
626 	fracmem = ((float)kp->p_vm_rssize)/mempages;
627 	return (100.0 * fracmem);
628 }
629 
630 void
631 pmem(const struct kinfo_proc *kp, VARENT *ve)
632 {
633 	VAR *v;
634 
635 	v = ve->var;
636 	(void)printf("%*.1f", v->width, getpmem(kp));
637 }
638 
639 void
640 pagein(const struct kinfo_proc *kp, VARENT *ve)
641 {
642 	VAR *v;
643 
644 	v = ve->var;
645 	(void)printf("%*llu", v->width,
646 	    kp->p_uvalid ? kp->p_uru_majflt : 0);
647 }
648 
649 void
650 maxrss(const struct kinfo_proc *kp, VARENT *ve)
651 {
652 	VAR *v;
653 
654 	v = ve->var;
655 	(void)printf("%*llu", v->width, kp->p_rlim_rss_cur / 1024);
656 }
657 
658 void
659 tsize(const struct kinfo_proc *kp, VARENT *ve)
660 {
661 	VAR *v;
662 
663 	v = ve->var;
664 	(void)printf("%*llu", v->width, pgtok(kp->p_vm_tsize));
665 }
666 
667 void
668 dsize(const struct kinfo_proc *kp, VARENT *ve)
669 {
670 	VAR *v;
671 
672 	v = ve->var;
673 	(void)printf("%*llu", v->width, pgtok(kp->p_vm_dsize));
674 }
675 
676 void
677 ssize(const struct kinfo_proc *kp, VARENT *ve)
678 {
679 	VAR *v;
680 
681 	v = ve->var;
682 	(void)printf("%*llu", v->width, pgtok(kp->p_vm_ssize));
683 }
684 
685 /*
686  * Generic output routines.  Print fields from various prototype
687  * structures.
688  */
689 static void
690 printval(char *bp, VAR *v)
691 {
692 	char ofmt[32];
693 
694 	snprintf(ofmt, sizeof(ofmt), "%%%s*%s", (v->flag & LJUST) ? "-" : "",
695 	    v->fmt);
696 
697 	/*
698 	 * Note that the "INF127" check is nonsensical for types
699 	 * that are or can be signed.
700 	 */
701 #define	GET(type)		(*(type *)bp)
702 #define	CHK_INF127(n)		(((n) > 127) && (v->flag & INF127) ? 127 : (n))
703 
704 	switch (v->type) {
705 	case INT8:
706 		(void)printf(ofmt, v->width, GET(int8_t));
707 		break;
708 	case UINT8:
709 		(void)printf(ofmt, v->width, CHK_INF127(GET(u_int8_t)));
710 		break;
711 	case INT16:
712 		(void)printf(ofmt, v->width, GET(int16_t));
713 		break;
714 	case UINT16:
715 		(void)printf(ofmt, v->width, CHK_INF127(GET(u_int16_t)));
716 		break;
717 	case INT32:
718 		(void)printf(ofmt, v->width, GET(int32_t));
719 		break;
720 	case UINT32:
721 		(void)printf(ofmt, v->width, CHK_INF127(GET(u_int32_t)));
722 		break;
723 	case INT64:
724 		(void)printf(ofmt, v->width, GET(int64_t));
725 		break;
726 	case UINT64:
727 		(void)printf(ofmt, v->width, CHK_INF127(GET(u_int64_t)));
728 		break;
729 	default:
730 		errx(1, "unknown type %d", v->type);
731 	}
732 #undef GET
733 #undef CHK_INF127
734 }
735 
736 void
737 pvar(const struct kinfo_proc *kp, VARENT *ve)
738 {
739 	VAR *v;
740 
741 	v = ve->var;
742 	if ((v->flag & USER) && !kp->p_uvalid)
743 		(void)printf("%*s", v->width, "-");
744 	else
745 		printval((char *)kp + v->off, v);
746 }
747 
748 void
749 emulname(const struct kinfo_proc *kp, VARENT *ve)
750 {
751 	VAR *v;
752 
753 	v = ve->var;
754 
755 	(void)printf("%-*s", (int)v->width, kp->p_emul);
756 }
757