4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2012 DEY Storage Systems, Inc. All rights reserved.
27 * Copyright (c) 2013 Joyent, Inc. All Rights reserved.
40 #include <sys/types.h>
41 #include <sys/socket.h>
43 #include <sys/mkdev.h>
44 #include <sys/stropts.h>
45 #include <sys/timod.h>
48 #include <netinet/in.h>
49 #include <netinet/udp.h>
50 #include <arpa/inet.h>
54 #define copyflock(dst, src) \
55 (dst).l_type = (src).l_type; \
56 (dst).l_whence = (src).l_whence; \
57 (dst).l_start = (src).l_start; \
58 (dst).l_len = (src).l_len; \
59 (dst).l_sysid = (src).l_sysid; \
60 (dst).l_pid = (src).l_pid;
63 static volatile int interrupt
;
65 static boolean_t nflag
= B_FALSE
;
67 static void intr(int);
68 static void dofcntl(struct ps_prochandle
*, prfdinfo_t
*, int, int);
69 static void dosocket(struct ps_prochandle
*, int);
70 static void dofifo(struct ps_prochandle
*, int);
71 static void dotli(struct ps_prochandle
*, int);
72 static void show_files(struct ps_prochandle
*);
73 static void show_fileflags(int);
74 static void show_door(struct ps_prochandle
*, int);
75 static int getflock(struct ps_prochandle
*, int, struct flock
*);
78 main(int argc
, char **argv
)
83 struct ps_prochandle
*Pr
;
85 if ((command
= strrchr(argv
[0], '/')) != NULL
)
91 while ((opt
= getopt(argc
, argv
, "Fn")) != EOF
) {
93 case 'F': /* force grabbing (no O_EXCL) */
108 if (errflg
|| argc
<= 0) {
109 (void) fprintf(stderr
, "usage:\t%s [-F] { pid | core } ...\n",
111 (void) fprintf(stderr
,
112 " (report open files of each process)\n");
113 (void) fprintf(stderr
,
114 " -F: force grabbing of the target process\n");
118 /* catch signals from terminal */
119 if (sigset(SIGHUP
, SIG_IGN
) == SIG_DFL
)
120 (void) sigset(SIGHUP
, intr
);
121 if (sigset(SIGINT
, SIG_IGN
) == SIG_DFL
)
122 (void) sigset(SIGINT
, intr
);
123 if (sigset(SIGQUIT
, SIG_IGN
) == SIG_DFL
)
124 (void) sigset(SIGQUIT
, intr
);
125 (void) sigset(SIGPIPE
, intr
);
126 (void) sigset(SIGTERM
, intr
);
128 (void) proc_initstdio();
131 while (--argc
>= 0 && !interrupt
) {
137 (void) proc_flushstdio();
141 /* get the specified pid and the psinfo struct */
142 if ((pid
= proc_arg_psinfo(arg
, PR_ARG_PIDS
,
143 &psinfo
, &gret
)) == -1) {
145 if ((Pr
= proc_arg_xgrab(arg
, NULL
, PR_ARG_CORES
,
146 Fflag
, &gret
, NULL
)) == NULL
) {
147 (void) fprintf(stderr
,
148 "%s: cannot examine %s: %s\n",
149 command
, arg
, Pgrab_error(gret
));
153 if (proc_arg_psinfo(arg
, PR_ARG_ANY
, &psinfo
,
155 (void) fprintf(stderr
,
156 "%s: cannot examine %s: %s\n",
157 command
, arg
, Pgrab_error(gret
));
162 (void) printf("core '%s' of %d:\t%.70s\n",
163 arg
, (int)psinfo
.pr_pid
, psinfo
.pr_psargs
);
168 } else if ((Pr
= Pgrab(pid
, Fflag
, &gret
)) != NULL
) {
169 if (Pcreate_agent(Pr
) == 0) {
170 proc_unctrl_psinfo(&psinfo
);
171 (void) printf("%d:\t%.70s\n",
172 (int)pid
, psinfo
.pr_psargs
);
176 (void) fprintf(stderr
,
177 "%s: cannot control process %d\n",
186 proc_unctrl_psinfo(&psinfo
);
187 (void) printf("%d:\t%.70s\n", (int)pid
,
189 (void) printf(" [system process]\n");
192 (void) fprintf(stderr
, "%s: %s: %d\n",
193 command
, Pgrab_error(gret
), (int)pid
);
200 (void) proc_finistdio();
202 if (interrupt
&& retc
== 0)
214 /* ------ begin specific code ------ */
217 show_file(void *data
, prfdinfo_t
*info
)
219 struct ps_prochandle
*Pr
= data
;
227 mode
= info
->pr_mode
;
229 switch (mode
& S_IFMT
) {
230 case S_IFCHR
: s
= "S_IFCHR"; break;
231 case S_IFBLK
: s
= "S_IFBLK"; break;
232 case S_IFIFO
: s
= "S_IFIFO"; break;
233 case S_IFDIR
: s
= "S_IFDIR"; break;
234 case S_IFREG
: s
= "S_IFREG"; break;
235 case S_IFLNK
: s
= "S_IFLNK"; break;
236 case S_IFSOCK
: s
= "S_IFSOCK"; break;
237 case S_IFDOOR
: s
= "S_IFDOOR"; break;
238 case S_IFPORT
: s
= "S_IFPORT"; break;
241 (void) sprintf(s
, "0x%.4x ", (int)mode
& S_IFMT
);
245 (void) printf("%4d: %s mode:0%.3o", info
->pr_fd
, s
,
246 (int)mode
& ~S_IFMT
);
248 (void) printf(" dev:%u,%u",
249 (unsigned)info
->pr_major
, (unsigned)info
->pr_minor
);
251 if ((mode
& S_IFMT
) == S_IFPORT
) {
252 (void) printf(" uid:%d gid:%d",
253 (int)info
->pr_uid
, (int)info
->pr_gid
);
254 (void) printf(" size:%lld\n", (longlong_t
)info
->pr_size
);
258 (void) printf(" ino:%llu uid:%d gid:%d",
259 (u_longlong_t
)info
->pr_ino
, (int)info
->pr_uid
, (int)info
->pr_gid
);
261 if ((info
->pr_rmajor
== (major_t
)NODEV
) &&
262 (info
->pr_rminor
== (minor_t
)NODEV
))
263 (void) printf(" size:%lld\n", (longlong_t
)info
->pr_size
);
265 (void) printf(" rdev:%u,%u\n",
266 (unsigned)info
->pr_rmajor
, (unsigned)info
->pr_rminor
);
270 (mode
& (S_IFMT
|S_ENFMT
|S_IXGRP
)) == (S_IFREG
|S_ENFMT
),
271 (mode
& S_IFMT
) == S_IFDOOR
);
273 if (Pstate(Pr
) != PS_DEAD
) {
276 if ((mode
& S_IFMT
) == S_IFSOCK
)
277 dosocket(Pr
, info
->pr_fd
);
278 else if ((mode
& S_IFMT
) == S_IFIFO
)
279 dofifo(Pr
, info
->pr_fd
);
281 if ((mode
& S_IFMT
) == S_IFCHR
) {
283 * There's no elegant way to determine
284 * if a character device supports TLI,
285 * so we lame out and just check a
286 * hardcoded list of known TLI devices.
289 const char *tlidevs
[] = {
290 "tcp", "tcp6", "udp", "udp6", NULL
293 /* global zone: /devices paths */
294 dev
= strrchr(info
->pr_path
, ':');
295 /* also check the /dev path for zones */
297 dev
= strrchr(info
->pr_path
, '/');
299 dev
++; /* skip past the `:' or '/' */
301 for (i
= 0; tlidevs
[i
] != NULL
; i
++) {
302 if (strcmp(dev
, tlidevs
[i
]) ==
304 dotli(Pr
, info
->pr_fd
);
312 if (info
->pr_path
[0] != '\0')
313 (void) printf(" %s\n", info
->pr_path
);
315 if (info
->pr_offset
!= -1) {
316 (void) printf(" offset:%lld\n",
317 (long long)info
->pr_offset
);
324 show_files(struct ps_prochandle
*Pr
)
328 if (pr_getrlimit(Pr
, RLIMIT_NOFILE
, &rlim
) == 0) {
329 ulong_t nfd
= rlim
.rlim_cur
;
330 if (nfd
== RLIM_INFINITY
)
332 " Current rlimit: unlimited file descriptors\n");
335 " Current rlimit: %lu file descriptors\n", nfd
);
338 (void) Pfdinfo_iter(Pr
, show_file
, Pr
);
343 getflock(struct ps_prochandle
*Pr
, int fd
, struct flock
*flock_native
)
347 struct flock64_32 flock_target
;
349 if (Pstatus(Pr
)->pr_dmodel
== PR_MODEL_ILP32
) {
350 copyflock(flock_target
, *flock_native
);
351 ret
= pr_fcntl(Pr
, fd
, F_GETLK
, &flock_target
);
352 copyflock(*flock_native
, flock_target
);
356 ret
= pr_fcntl(Pr
, fd
, F_GETLK
, flock_native
);
360 /* examine open file with fcntl() */
362 dofcntl(struct ps_prochandle
*Pr
, prfdinfo_t
*info
, int mandatory
, int isdoor
)
371 fileflags
= info
->pr_fileflags
;
372 fdflags
= info
->pr_fdflags
;
374 if (fileflags
!= -1 || fdflags
!= -1) {
377 show_fileflags(fileflags
);
378 if (fdflags
!= -1 && (fdflags
& FD_CLOEXEC
))
379 (void) printf(" FD_CLOEXEC");
380 if (isdoor
&& (Pstate(Pr
) != PS_DEAD
))
382 (void) fputc('\n', stdout
);
383 } else if (isdoor
&& (Pstate(Pr
) != PS_DEAD
)) {
386 (void) fputc('\n', stdout
);
389 flock
.l_type
= F_WRLCK
;
395 if ((Pstate(Pr
) != PS_DEAD
) && (getflock(Pr
, fd
, &flock
) != -1)) {
396 if (flock
.l_type
!= F_UNLCK
&& (flock
.l_sysid
|| flock
.l_pid
)) {
397 unsigned long sysid
= flock
.l_sysid
;
399 (void) printf(" %s %s lock set by",
400 mandatory
? "mandatory" : "advisory",
401 flock
.l_type
== F_RDLCK
? "read" : "write");
403 (void) printf(" system 0x%lX", sysid
);
405 (void) printf(" process %d", (int)flock
.l_pid
);
406 (void) fputc('\n', stdout
);
411 #define ALL_O_FLAGS O_ACCMODE | O_NDELAY | O_NONBLOCK | O_APPEND | \
412 O_SYNC | O_DSYNC | O_RSYNC | O_XATTR | \
413 O_CREAT | O_TRUNC | O_EXCL | O_NOCTTY | O_LARGEFILE
416 show_fileflags(int flags
)
421 switch (flags
& O_ACCMODE
) {
423 (void) strcpy(str
, "O_RDONLY");
426 (void) strcpy(str
, "O_WRONLY");
429 (void) strcpy(str
, "O_RDWR");
432 (void) strcpy(str
, "O_SEARCH");
435 (void) strcpy(str
, "O_EXEC");
438 (void) sprintf(str
, "0x%x", flags
& O_ACCMODE
);
442 if (flags
& O_NDELAY
)
443 (void) strcat(str
, "|O_NDELAY");
444 if (flags
& O_NONBLOCK
)
445 (void) strcat(str
, "|O_NONBLOCK");
446 if (flags
& O_APPEND
)
447 (void) strcat(str
, "|O_APPEND");
449 (void) strcat(str
, "|O_SYNC");
451 (void) strcat(str
, "|O_DSYNC");
453 (void) strcat(str
, "|O_RSYNC");
455 (void) strcat(str
, "|O_CREAT");
457 (void) strcat(str
, "|O_TRUNC");
459 (void) strcat(str
, "|O_EXCL");
460 if (flags
& O_NOCTTY
)
461 (void) strcat(str
, "|O_NOCTTY");
462 if (flags
& O_LARGEFILE
)
463 (void) strcat(str
, "|O_LARGEFILE");
465 (void) strcat(str
, "|O_XATTR");
466 if (flags
& ~(ALL_O_FLAGS
))
467 (void) sprintf(str
+ strlen(str
), "|0x%x",
468 flags
& ~(ALL_O_FLAGS
));
470 (void) printf("%s", str
);
473 /* show process on the other end of a door, socket or fifo */
475 show_peer_process(pid_t ppid
)
479 if (proc_get_psinfo(ppid
, &psinfo
) == 0)
480 (void) printf(" %s[%d]", psinfo
.pr_fname
, (int)ppid
);
482 (void) printf(" pid %d", (int)ppid
);
487 show_door(struct ps_prochandle
*Pr
, int fd
)
489 door_info_t door_info
;
491 if (pr_door_info(Pr
, fd
, &door_info
) != 0)
494 (void) printf(" door to");
495 show_peer_process(door_info
.di_target
);
499 * Print out the socket address pointed to by `sa'. `len' is only
500 * needed for AF_UNIX sockets.
503 show_sockaddr(const char *str
, struct sockaddr
*sa
, socklen_t len
)
505 struct sockaddr_in
*so_in
= (struct sockaddr_in
*)(void *)sa
;
506 struct sockaddr_in6
*so_in6
= (struct sockaddr_in6
*)(void *)sa
;
507 struct sockaddr_un
*so_un
= (struct sockaddr_un
*)sa
;
508 char abuf
[INET6_ADDRSTRLEN
];
514 switch (sa
->sa_family
) {
518 (void) printf("\t%s: AF_INET %s port: %u\n", str
,
519 inet_ntop(AF_INET
, &so_in
->sin_addr
, abuf
, sizeof (abuf
)),
520 ntohs(so_in
->sin_port
));
523 (void) printf("\t%s: AF_INET6 %s port: %u\n", str
,
524 inet_ntop(AF_INET6
, &so_in6
->sin6_addr
,
525 abuf
, sizeof (abuf
)),
526 ntohs(so_in
->sin_port
));
529 if (len
>= sizeof (so_un
->sun_family
)) {
531 len
-= sizeof (so_un
->sun_family
);
532 so_un
->sun_path
[len
] = '\0';
533 (void) printf("\t%s: AF_UNIX %s\n",
534 str
, so_un
->sun_path
);
537 case AF_IMPLINK
: p
= "AF_IMPLINK"; break;
538 case AF_PUP
: p
= "AF_PUP"; break;
539 case AF_CHAOS
: p
= "AF_CHAOS"; break;
540 case AF_NS
: p
= "AF_NS"; break;
541 case AF_NBS
: p
= "AF_NBS"; break;
542 case AF_ECMA
: p
= "AF_ECMA"; break;
543 case AF_DATAKIT
: p
= "AF_DATAKIT"; break;
544 case AF_CCITT
: p
= "AF_CCITT"; break;
545 case AF_SNA
: p
= "AF_SNA"; break;
546 case AF_DECnet
: p
= "AF_DECnet"; break;
547 case AF_DLI
: p
= "AF_DLI"; break;
548 case AF_LAT
: p
= "AF_LAT"; break;
549 case AF_HYLINK
: p
= "AF_HYLINK"; break;
550 case AF_APPLETALK
: p
= "AF_APPLETALK"; break;
551 case AF_NIT
: p
= "AF_NIT"; break;
552 case AF_802
: p
= "AF_802"; break;
553 case AF_OSI
: p
= "AF_OSI"; break;
554 case AF_X25
: p
= "AF_X25"; break;
555 case AF_OSINET
: p
= "AF_OSINET"; break;
556 case AF_GOSIP
: p
= "AF_GOSIP"; break;
557 case AF_IPX
: p
= "AF_IPX"; break;
558 case AF_ROUTE
: p
= "AF_ROUTE"; break;
559 case AF_LINK
: p
= "AF_LINK"; break;
562 (void) printf("\t%s: %s\n", str
, p
);
566 * Print out the process information for the other end of local sockets
570 show_ucred(const char *str
, ucred_t
*cred
)
572 pid_t upid
= ucred_getpid(cred
);
573 zoneid_t uzid
= ucred_getzoneid(cred
);
574 char zonename
[ZONENAME_MAX
];
576 if ((upid
!= -1) || (uzid
!= -1)) {
577 (void) printf("\t%s:", str
);
579 show_peer_process(upid
);
582 if (getzonenamebyid(uzid
, zonename
, sizeof (zonename
))
584 (void) printf(" zone: %s[%d]", zonename
,
587 (void) printf(" zoneid: %d", (int)uzid
);
595 show_socktype(uint_t type
)
597 static const char *types
[] = {
598 NULL
, "DGRAM", "STREAM", NULL
, "RAW", "RDM", "SEQPACKET"
601 if (type
< sizeof (types
) / sizeof (*types
) && types
[type
] != NULL
)
602 (void) printf("\tSOCK_%s\n", types
[type
]);
604 (void) printf("\tunknown socket type %u\n", type
);
609 show_sockopts(struct ps_prochandle
*Pr
, int fd
)
614 char ipaddr
[INET_ADDRSTRLEN
];
616 in_addr_t nexthop_val
;
622 static struct boolopt boolopts
[] = {
623 { SOL_SOCKET
, SO_DEBUG
, "SO_DEBUG," },
624 { SOL_SOCKET
, SO_REUSEADDR
, "SO_REUSEADDR," },
625 { SOL_SOCKET
, SO_KEEPALIVE
, "SO_KEEPALIVE," },
626 { SOL_SOCKET
, SO_DONTROUTE
, "SO_DONTROUTE," },
627 { SOL_SOCKET
, SO_BROADCAST
, "SO_BROADCAST," },
628 { SOL_SOCKET
, SO_OOBINLINE
, "SO_OOBINLINE," },
629 { SOL_SOCKET
, SO_DGRAM_ERRIND
, "SO_DGRAM_ERRIND,"},
630 { SOL_SOCKET
, SO_ALLZONES
, "SO_ALLZONES," },
631 { SOL_SOCKET
, SO_MAC_EXEMPT
, "SO_MAC_EXEMPT," },
632 { SOL_SOCKET
, SO_MAC_IMPLICIT
, "SO_MAC_IMPLICIT," },
633 { SOL_SOCKET
, SO_EXCLBIND
, "SO_EXCLBIND," },
634 { SOL_SOCKET
, SO_VRRP
, "SO_VRRP," },
635 { IPPROTO_UDP
, UDP_NAT_T_ENDPOINT
, "UDP_NAT_T_ENDPOINT," },
639 buf
[0] = '!'; /* sentinel value, never printed */
642 for (i
= 0; i
< sizeof (boolopts
) / sizeof (boolopts
[0]); i
++) {
644 if (pr_getsockopt(Pr
, fd
, boolopts
[i
].level
, boolopts
[i
].opt
,
645 &val
, &vlen
) == 0 && val
!= 0)
646 (void) strlcat(buf
, boolopts
[i
].name
, sizeof (buf
));
650 if (pr_getsockopt(Pr
, fd
, SOL_SOCKET
, SO_LINGER
, &l
, &vlen
) == 0 &&
652 (void) snprintf(buf1
, sizeof (buf1
), "SO_LINGER(%d),",
654 (void) strlcat(buf
, buf1
, sizeof (buf
));
658 if (pr_getsockopt(Pr
, fd
, SOL_SOCKET
, SO_SNDBUF
, &val
, &vlen
) == 0) {
659 (void) snprintf(buf1
, sizeof (buf1
), "SO_SNDBUF(%d),", val
);
660 (void) strlcat(buf
, buf1
, sizeof (buf
));
663 if (pr_getsockopt(Pr
, fd
, SOL_SOCKET
, SO_RCVBUF
, &val
, &vlen
) == 0) {
664 (void) snprintf(buf1
, sizeof (buf1
), "SO_RCVBUF(%d),", val
);
665 (void) strlcat(buf
, buf1
, sizeof (buf
));
667 vlen
= sizeof (nexthop_val
);
668 if (pr_getsockopt(Pr
, fd
, IPPROTO_IP
, IP_NEXTHOP
, &nexthop_val
,
671 (void) inet_ntop(AF_INET
, (void *) &nexthop_val
,
672 ipaddr
, sizeof (ipaddr
));
673 (void) snprintf(buf1
, sizeof (buf1
), "IP_NEXTHOP(%s),",
675 (void) strlcat(buf
, buf1
, sizeof (buf
));
679 buf
[strlen(buf
) - 1] = '\0'; /* overwrites sentinel if no options */
681 (void) printf("\t%s\n", buf
+1);
686 show_sockfilters(struct ps_prochandle
*Pr
, int fd
)
689 int i
= 0, nalloc
= 2, len
= nalloc
* sizeof (*fi
);
690 boolean_t printhdr
= B_TRUE
;
692 fi
= calloc(nalloc
, sizeof (*fi
));
699 if (pr_getsockopt(Pr
, fd
, SOL_FILTER
, FIL_LIST
, fi
, &len
) != 0)
704 /* Make sure buffer was large enough */
705 if (fi
->fi_pos
>= nalloc
) {
706 struct fil_info
*new;
708 nalloc
= fi
->fi_pos
+ 1;
709 if (nalloc
> MAXNALLOC
)
711 len
= nalloc
* sizeof (*fi
);
712 new = realloc(fi
, nalloc
* sizeof (*fi
));
721 for (i
= 0; (i
+ 1) * sizeof (*fi
) <= len
; i
++) {
722 if (fi
[i
].fi_flags
& FILF_BYPASS
)
725 (void) printf("\tfilters: ");
728 (void) printf("%s", fi
[i
].fi_name
);
729 if (fi
[i
].fi_flags
!= 0) {
731 if (fi
[i
].fi_flags
& FILF_AUTO
)
732 (void) printf("auto,");
733 if (fi
[i
].fi_flags
& FILF_PROG
)
734 (void) printf("prog,");
735 (void) printf("\b)");
737 if (fi
[i
].fi_pos
== 0) /* last one */
748 /* print peer credentials for sockets and named pipes */
750 dopeerucred(struct ps_prochandle
*Pr
, int fd
)
752 ucred_t
*peercred
= NULL
; /* allocated by getpeerucred */
754 if (pr_getpeerucred(Pr
, fd
, &peercred
) == 0) {
755 show_ucred("peer", peercred
);
756 ucred_free(peercred
);
760 /* the file is a socket */
762 dosocket(struct ps_prochandle
*Pr
, int fd
)
764 /* A buffer large enough for PATH_MAX size AF_UNIX address */
765 long buf
[(sizeof (short) + PATH_MAX
+ sizeof (long) - 1)
767 struct sockaddr
*sa
= (struct sockaddr
*)buf
;
771 tlen
= sizeof (type
);
772 if (pr_getsockopt(Pr
, fd
, SOL_SOCKET
, SO_TYPE
, &type
, &tlen
) == 0)
773 show_socktype((uint_t
)type
);
775 show_sockopts(Pr
, fd
);
776 show_sockfilters(Pr
, fd
);
779 if (pr_getsockname(Pr
, fd
, sa
, &len
) == 0)
780 show_sockaddr("sockname", sa
, len
);
783 if (pr_getpeername(Pr
, fd
, sa
, &len
) == 0)
784 show_sockaddr("peername", sa
, len
);
789 /* the file is a fifo (aka "named pipe") */
791 dofifo(struct ps_prochandle
*Pr
, int fd
)
796 /* the file is a TLI endpoint */
798 dotli(struct ps_prochandle
*Pr
, int fd
)
800 struct strcmd strcmd
;
802 strcmd
.sc_len
= STRCMDBUFSIZE
;
803 strcmd
.sc_timeout
= 5;
805 strcmd
.sc_cmd
= TI_GETMYNAME
;
806 if (pr_ioctl(Pr
, fd
, _I_CMD
, &strcmd
, sizeof (strcmd
)) == 0)
807 show_sockaddr("sockname", (void *)&strcmd
.sc_buf
,
808 (size_t)strcmd
.sc_len
);
810 strcmd
.sc_cmd
= TI_GETPEERNAME
;
811 if (pr_ioctl(Pr
, fd
, _I_CMD
, &strcmd
, sizeof (strcmd
)) == 0)
812 show_sockaddr("peername", (void *)&strcmd
.sc_buf
,
813 (size_t)strcmd
.sc_len
);