diff options
author | John Levon <john.levon@joyent.com> | 2019-09-12 20:26:08 +0000 |
---|---|---|
committer | John Levon <john.levon@joyent.com> | 2019-09-12 20:26:08 +0000 |
commit | c6dd2307128aa25ac346f7818440cd5cfd1f7221 (patch) | |
tree | 9bda47db825ca7697580de5510764735b0748431 | |
parent | 1cc6f4c0fcc857bd86b9a8234d9ff75d5a6b9384 (diff) | |
download | illumos-joyent-c6dd2307128aa25ac346f7818440cd5cfd1f7221.tar.gz |
OS-7931 ::refstr would be useful
OS-7932 ::ps -s could show service FMRIs
OS-7934 ptree could show service FMRIs
OS-3513 ptools should see more process arguments
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Jason King <jason.king@joyent.com>
Approved by: Jerry Jelinek <jerry.jelinek@joyent.com>
29 files changed, 783 insertions, 644 deletions
diff --git a/usr/src/cmd/mdb/common/modules/genunix/Makefile.files b/usr/src/cmd/mdb/common/modules/genunix/Makefile.files index 44ed819316..d371cf70fe 100644 --- a/usr/src/cmd/mdb/common/modules/genunix/Makefile.files +++ b/usr/src/cmd/mdb/common/modules/genunix/Makefile.files @@ -21,7 +21,7 @@ # # Copyright 2011 Nexenta Systems, Inc. All rights reserved. # Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. -# Copyright 2019, Joyent, Inc. +# Copyright 2019 Joyent, Inc. # Copyright (c) 2013 by Delphix. All rights reserved. # @@ -73,6 +73,7 @@ GENUNIX_SRCS = \ pg.c \ rctl.c \ refhash.c \ + refstr.c \ sobj.c \ streams.c \ sysevent.c \ diff --git a/usr/src/cmd/mdb/common/modules/genunix/genunix.c b/usr/src/cmd/mdb/common/modules/genunix/genunix.c index 4c7c5ef5c1..f524a4c60c 100644 --- a/usr/src/cmd/mdb/common/modules/genunix/genunix.c +++ b/usr/src/cmd/mdb/common/modules/genunix/genunix.c @@ -61,6 +61,7 @@ #include <sys/panic.h> #include <regex.h> #include <sys/port_impl.h> +#include <sys/contract/process_impl.h> #include "avl.h" #include "bio.h" @@ -141,6 +142,7 @@ pstat2ch(uchar_t state) #define PS_TASKS 0x8 #define PS_PROJECTS 0x10 #define PS_ZONES 0x20 +#define PS_SERVICES 0x40 static int ps_threadprint(uintptr_t addr, const void *data, void *private) @@ -270,6 +272,7 @@ typedef struct mdb_ps_proc { struct sess *p_sessp; struct task *p_task; struct zone *p_zone; + struct cont_process *p_ct_process; pid_t p_ppid; uint_t p_flag; struct { @@ -278,6 +281,12 @@ typedef struct mdb_ps_proc { } p_user; } mdb_ps_proc_t; +/* + * A reasonable enough limit. Note that we purposefully let this column over-run + * if needed. + */ +#define FMRI_LEN (128) + int ps(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) { @@ -289,6 +298,8 @@ ps(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) task_t tk; kproject_t pj; zone_t zn; + struct cont_process cp; + char fmri[FMRI_LEN] = ""; if (!(flags & DCMD_ADDRSPEC)) { if (mdb_walk_dcmd("proc", "ps", argc, argv) == -1) { @@ -301,6 +312,7 @@ ps(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) if (mdb_getopts(argc, argv, 'f', MDB_OPT_SETBITS, PS_PSARGS, &prt_flags, 'l', MDB_OPT_SETBITS, PS_PRTLWPS, &prt_flags, + 's', MDB_OPT_SETBITS, PS_SERVICES, &prt_flags, 'T', MDB_OPT_SETBITS, PS_TASKS, &prt_flags, 'P', MDB_OPT_SETBITS, PS_PROJECTS, &prt_flags, 'z', MDB_OPT_SETBITS, PS_ZONES, &prt_flags, @@ -308,15 +320,17 @@ ps(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) return (DCMD_USAGE); if (DCMD_HDRSPEC(flags)) { - mdb_printf("%<u>%1s %6s %6s %6s %6s ", + mdb_printf("%<u>%-1s %-6s %-6s %-6s %-6s ", "S", "PID", "PPID", "PGID", "SID"); if (prt_flags & PS_TASKS) - mdb_printf("%5s ", "TASK"); + mdb_printf("%-5s ", "TASK"); if (prt_flags & PS_PROJECTS) - mdb_printf("%5s ", "PROJ"); + mdb_printf("%-5s ", "PROJ"); if (prt_flags & PS_ZONES) - mdb_printf("%5s ", "ZONE"); - mdb_printf("%6s %10s %?s %s%</u>\n", + mdb_printf("%-5s ", "ZONE"); + if (prt_flags & PS_SERVICES) + mdb_printf("%-40s ", "SERVICE"); + mdb_printf("%-6s %-10s %-?s %-s%</u>\n", "UID", "FLAGS", "ADDR", "NAME"); } @@ -334,17 +348,39 @@ ps(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) mdb_vread(&pj, sizeof (pj), (uintptr_t)tk.tk_proj); if (prt_flags & PS_ZONES) mdb_vread(&zn, sizeof (zn), (uintptr_t)pr.p_zone); + if ((prt_flags & PS_SERVICES) && pr.p_ct_process != NULL) { + mdb_vread(&cp, sizeof (cp), (uintptr_t)pr.p_ct_process); + + if (mdb_read_refstr((uintptr_t)cp.conp_svc_fmri, fmri, + sizeof (fmri)) <= 0) + (void) strlcpy(fmri, "?", sizeof (fmri)); + + /* Strip any standard prefix and suffix. */ + if (strncmp(fmri, "svc:/", sizeof ("svc:/") - 1) == 0) { + char *i = fmri; + char *j = fmri + sizeof ("svc:/") - 1; + for (; *j != '\0'; i++, j++) { + if (strcmp(j, ":default") == 0) + break; + *i = *j; + } - mdb_printf("%c %6d %6d %6d %6d ", + *i = '\0'; + } + } + + mdb_printf("%-c %-6d %-6d %-6d %-6d ", pstat2ch(pr.p_stat), pid.pid_id, pr.p_ppid, pgid.pid_id, sid.pid_id); if (prt_flags & PS_TASKS) - mdb_printf("%5d ", tk.tk_tkid); + mdb_printf("%-5d ", tk.tk_tkid); if (prt_flags & PS_PROJECTS) - mdb_printf("%5d ", pj.kpj_id); + mdb_printf("%-5d ", pj.kpj_id); if (prt_flags & PS_ZONES) - mdb_printf("%5d ", zn.zone_id); - mdb_printf("%6d 0x%08x %0?p %s\n", + mdb_printf("%-5d ", zn.zone_id); + if (prt_flags & PS_SERVICES) + mdb_printf("%-40s ", fmri); + mdb_printf("%-6d 0x%08x %0?p %-s\n", cred.cr_uid, pr.p_flag, addr, (prt_flags & PS_PSARGS) ? pr.p_user.u_psargs : pr.p_user.u_comm); @@ -363,6 +399,7 @@ ps_help(void) " -l\tDisplay LWPs\n" " -T\tDisplay tasks\n" " -P\tDisplay projects\n" + " -s\tDisplay SMF FMRI\n" " -z\tDisplay zones\n" " -t\tDisplay threads\n\n"); @@ -386,6 +423,7 @@ ps_help(void) mdb_printf("TASK\tThe task id of the process.\n"); mdb_printf("PROJ\tThe project id of the process.\n"); mdb_printf("ZONE\tThe zone id of the process.\n"); + mdb_printf("SERVICE The SMF service FMRI of the process.\n"); mdb_printf("UID\tThe user id of the process.\n"); mdb_printf("FLAGS\tThe process flags (see ::pflags).\n"); mdb_printf("ADDR\tThe kernel address of the proc_t structure of the " @@ -4053,6 +4091,8 @@ time_help(void) " -x report times in hexadecimal\n"); } +extern int cmd_refstr(uintptr_t, uint_t, int, const mdb_arg_t *); + static const mdb_dcmd_t dcmds[] = { /* from genunix.c */ @@ -4083,6 +4123,7 @@ static const mdb_dcmd_t dcmds[] = { { "pgrep", "[-x] [-n | -o] pattern", "pattern match against all processes", pgrep }, { "ptree", NULL, "print process tree", ptree }, + { "refstr", NULL, "print string from a refstr_t", cmd_refstr, NULL }, { "sysevent", "?[-sv]", "print sysevent pending or sent queue", sysevent}, { "sysevent_channel", "?", "print sysevent channel database", diff --git a/usr/src/cmd/mdb/common/modules/genunix/refstr.c b/usr/src/cmd/mdb/common/modules/genunix/refstr.c new file mode 100644 index 0000000000..5b5fcec14c --- /dev/null +++ b/usr/src/cmd/mdb/common/modules/genunix/refstr.c @@ -0,0 +1,43 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2019 Joyent, Inc. + */ + +#include <mdb/mdb_modapi.h> +#include <mdb/mdb_ks.h> +#include <sys/refstr.h> + +#define REFSTR_LEN (1024) + +int +cmd_refstr(uintptr_t addr, uint_t flags __unused, + int argc, const mdb_arg_t *argv) +{ + if (!(flags & DCMD_ADDRSPEC)) { + mdb_warn("address is required\n"); + return (DCMD_ERR); + } + + if (mdb_getopts(argc, argv, NULL) != argc) + return (DCMD_USAGE); + + char *buf = mdb_alloc(REFSTR_LEN, UM_SLEEP | UM_GC); + + if (mdb_read_refstr(addr, buf, REFSTR_LEN) < 0) { + mdb_warn("couldn't read refstr from %p", addr); + return (DCMD_ERR); + } + + mdb_printf("%s\n", buf); + return (DCMD_OK); +} diff --git a/usr/src/cmd/pgrep/Makefile b/usr/src/cmd/pgrep/Makefile index 67993f0ff2..09fb900da7 100644 --- a/usr/src/cmd/pgrep/Makefile +++ b/usr/src/cmd/pgrep/Makefile @@ -22,6 +22,8 @@ # Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # +# Copyright 2019 Joyent, Inc. +# PROG = pgrep PKILLFILE = pkill @@ -31,13 +33,14 @@ ROOTLINKS = $(ROOTBIN)/$(PKILLFILE) OBJS = pgrep.o idtab.o psexp.o SRCS = $(OBJS:.o=.c) POFILES = $(OBJS:.o=.po) -lint := LINTFLAGS = -ux include ../Makefile.cmd CLOBBERFILES += $(PKILLFILE) + CFLAGS += $(CCVERBOSE) -CERRWARN += -_gcc=-Wno-parentheses +CSTD = $(CSTD_GNU99) + LDLIBS += -luutil -lproject -lcontract POFILE = ppgrep.po @@ -69,6 +72,4 @@ $(ROOTLINKS): $(ROOTPROG) clean: $(RM) $(OBJS) -lint: lint_SRCS - include ../Makefile.targ diff --git a/usr/src/cmd/pgrep/idtab.c b/usr/src/cmd/pgrep/idtab.c index 52d6e88cdb..56db6eab91 100644 --- a/usr/src/cmd/pgrep/idtab.c +++ b/usr/src/cmd/pgrep/idtab.c @@ -24,7 +24,9 @@ * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" +/* + * Copyright 2019 Joyent, Inc. + */ #include <libintl.h> #include <string.h> @@ -61,7 +63,8 @@ idtab_append(idtab_t *idt, idkey_t id) if (idt->id_nelems >= idt->id_size) { size = idt->id_size ? idt->id_size * IDTAB_GROW : IDTAB_DEFSIZE; - if (data = realloc(idt->id_data, sizeof (idkey_t) * size)) { + if ((data = realloc(idt->id_data, + sizeof (idkey_t) * size)) != NULL) { idt->id_data = data; idt->id_size = size; } else { diff --git a/usr/src/cmd/pgrep/pgrep.c b/usr/src/cmd/pgrep/pgrep.c index 857f6ef818..0fda6733fb 100644 --- a/usr/src/cmd/pgrep/pgrep.c +++ b/usr/src/cmd/pgrep/pgrep.c @@ -24,6 +24,10 @@ */ /* Copyright (c) 2012 by Delphix. All rights reserved */ +/* + * Copyright 2019 Joyent, Inc. + */ + #include <sys/types.h> #include <sys/stat.h> #include <sys/param.h> @@ -59,11 +63,11 @@ #define TEXT_DOMAIN "SYS_TEST" #endif -#define OPT_SETB 0x0001 /* Set the bits specified by o_bits */ -#define OPT_CLRB 0x0002 /* Clear the bits specified by o_bits */ -#define OPT_FUNC 0x0004 /* Call the function specified by o_func */ -#define OPT_STR 0x0008 /* Set the string specified by o_ptr */ -#define OPT_CRIT 0x0010 /* Option is part of selection criteria */ +#define OPT_SETB 0x0001 /* Set the bits specified by o_bits */ +#define OPT_CLRB 0x0002 /* Clear the bits specified by o_bits */ +#define OPT_FUNC 0x0004 /* Call the function specified by o_func */ +#define OPT_STR 0x0008 /* Set the string specified by o_ptr */ +#define OPT_CRIT 0x0010 /* Option is part of selection criteria */ #define F_LONG_FMT 0x0001 /* Match against long format cmd */ #define F_NEWEST 0x0002 /* Match only newest pid */ @@ -138,7 +142,7 @@ static optdesc_t g_optdtab[] = { { 0, 0, 0, 0 }, /* 'k' */ { OPT_SETB, F_LONG_OUT, 0, &g_flags }, /* 'l' */ { 0, 0, 0, 0 }, /* 'm' */ - { OPT_SETB, F_NEWEST, 0, &g_flags }, /* -n */ + { OPT_SETB, F_NEWEST, 0, &g_flags }, /* -n */ { OPT_SETB, F_OLDEST, 0, &g_flags }, /* -o */ { 0, 0, 0, 0 }, /* 'p' */ { 0, 0, 0, 0 }, /* 'q' */ @@ -173,7 +177,7 @@ static pid_t g_pid; /* Current pid */ static int g_signal = SIGTERM; /* Signal to send */ static void -print_proc(psinfo_t *psinfo) +print_proc(psinfo_t *psinfo, char *argv __unused, size_t len __unused) { if (g_flags & F_OUTPUT) (void) printf("%s%d", g_delim, (int)psinfo->pr_pid); @@ -183,7 +187,7 @@ print_proc(psinfo_t *psinfo) } } -static char * +static void mbstrip(char *buf, size_t nbytes) { wchar_t wc; @@ -191,6 +195,7 @@ mbstrip(char *buf, size_t nbytes) int n; buf[nbytes - 1] = '\0'; + p = buf; while (*p != '\0') { @@ -212,30 +217,23 @@ mbstrip(char *buf, size_t nbytes) p += n; } } - - return (buf); } static void -print_proc_long(psinfo_t *psinfo) +print_proc_long(psinfo_t *psinfo, char *argv, size_t len) { - char *name; - - if (g_flags & F_LONG_FMT) - name = mbstrip(psinfo->pr_psargs, PRARGSZ); - else - name = psinfo->pr_fname; + mbstrip(argv, len); if (g_flags & F_OUTPUT) - (void) printf("%s%5d %s", g_delim, (int)psinfo->pr_pid, name); + (void) printf("%s%5d %s", g_delim, (int)psinfo->pr_pid, argv); else { - (void) printf("%5d %s", (int)psinfo->pr_pid, name); + (void) printf("%5d %s", (int)psinfo->pr_pid, argv); g_flags |= F_OUTPUT; } } static void -kill_proc(psinfo_t *psinfo) +kill_proc(psinfo_t *psinfo, char *argv __unused, size_t len __unused) { if (psinfo->pr_pid > 0 && kill(psinfo->pr_pid, g_signal) == -1) uu_warn(gettext("Failed to signal pid %d"), @@ -268,6 +266,46 @@ open_proc_dir(const char *dirpath) return (dirp); } +static void +get_argv(int flags, psinfo_t *ps, char *buf, size_t bufsize) +{ + char *path = NULL; + ssize_t size = 0; + int fd; + + if (!(flags & F_LONG_FMT)) { + (void) strlcpy(buf, ps->pr_fname, bufsize); + return; + } + + if (getenv("SHORT_PSARGS") != NULL) { + (void) strlcpy(buf, ps->pr_psargs, bufsize); + return; + } + + if (asprintf(&path, "%s/%d/cmdline", g_procdir, + (int)ps->pr_pid) != -1 && (fd = open(path, O_RDONLY)) != -1) { + size = read(fd, buf, bufsize); + (void) close(fd); + } + + free(path); + + if (size <= 0) { + (void) strlcpy(buf, ps->pr_psargs, bufsize); + } else { + buf[bufsize - 1] = '\0'; + for (char *cp = buf; cp - buf < size; cp++) { + if (*cp == '\0' && (cp - buf) + 1 < size) + *cp = ' '; + } + } + + for (ssize_t i = strlen(buf) - 1; i >= 0 && isspace(buf[i]); i--) { + buf[i] = '\0'; + } +} + #define NEWER(ps1, ps2) \ ((ps1.pr_start.tv_sec > ps2.pr_start.tv_sec) || \ (ps1.pr_start.tv_sec == ps2.pr_start.tv_sec && \ @@ -275,9 +313,10 @@ open_proc_dir(const char *dirpath) static int scan_proc_dir(const char *dirpath, DIR *dirp, psexp_t *psexp, - void (*funcp)(psinfo_t *)) + void (*funcp)(psinfo_t *, char *, size_t)) { char procpath[MAXPATHLEN]; + char argv[PRMAXARGVLEN] = ""; psinfo_t ps, ops; dirent_t *dent; int procfd; @@ -285,9 +324,6 @@ scan_proc_dir(const char *dirpath, DIR *dirp, psexp_t *psexp, int reverse = (g_flags & F_REVERSE) ? 1 : 0; int ovalid = 0, nmatches = 0, flags = 0; - if (g_flags & F_LONG_FMT) - flags |= PSEXP_PSARGS; - if (g_flags & F_EXACT_MATCH) flags |= PSEXP_EXACT; @@ -302,12 +338,17 @@ scan_proc_dir(const char *dirpath, DIR *dirp, psexp_t *psexp, if ((procfd = open(procpath, O_RDONLY)) == -1) continue; - if ((read(procfd, &ps, sizeof (ps)) == sizeof (psinfo_t)) && - (ps.pr_nlwp != 0) && (ps.pr_pid != g_pid) && - (psexp_match(psexp, &ps, flags) ^ reverse)) { + if (read(procfd, &ps, sizeof (ps)) != sizeof (psinfo_t)) { + (void) close(procfd); + continue; + } + + get_argv(g_flags, &ps, argv, sizeof (argv)); + + if ((ps.pr_nlwp != 0) && (ps.pr_pid != g_pid) && + (psexp_match(psexp, &ps, argv, flags) ^ reverse)) { if (g_flags & F_NEWEST) { - /* LINTED - opsinfo use ok */ if (!ovalid || NEWER(ps, ops)) { (void) memcpy(&ops, &ps, sizeof (psinfo_t)); @@ -320,7 +361,7 @@ scan_proc_dir(const char *dirpath, DIR *dirp, psexp_t *psexp, ovalid = 1; } } else { - (*funcp)(&ps); + (*funcp)(&ps, argv, sizeof (argv)); nmatches++; } } @@ -329,7 +370,8 @@ scan_proc_dir(const char *dirpath, DIR *dirp, psexp_t *psexp, } if ((g_flags & (F_NEWEST | F_OLDEST)) && ovalid) { - (*funcp)(&ops); + (*funcp)(&ops, argv, sizeof (argv)); + nmatches++; } @@ -592,7 +634,7 @@ print_usage(FILE *stream) int main(int argc, char *argv[]) { - void (*funcp)(psinfo_t *); + void (*funcp)(psinfo_t *, char *, size_t); const char *optstr; optdesc_t *optd; diff --git a/usr/src/cmd/pgrep/psexp.c b/usr/src/cmd/pgrep/psexp.c index be14393bd1..abb8699523 100644 --- a/usr/src/cmd/pgrep/psexp.c +++ b/usr/src/cmd/pgrep/psexp.c @@ -24,7 +24,9 @@ * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" +/* + * Copyright 2019 Joyent, Inc. + */ #include <string.h> #include <stdlib.h> @@ -110,10 +112,9 @@ psexp_compile(psexp_t *psexp) psexp->__f1.id_data && !idtab_search(&psexp->__f1, psinfo->__f2) int -psexp_match(psexp_t *psexp, psinfo_t *psinfo, int flags) +psexp_match(psexp_t *psexp, psinfo_t *psinfo, const char *argv, int flags) { regmatch_t pmatch; - const char *s; if (NOMATCH(ps_euids, pr_euid)) return (0); @@ -139,14 +140,11 @@ psexp_match(psexp_t *psexp, psinfo_t *psinfo, int flags) return (0); if (psexp->ps_pat != NULL) { - s = (flags & PSEXP_PSARGS) ? - psinfo->pr_psargs : psinfo->pr_fname; - - if (regexec(&psexp->ps_reg, s, 1, &pmatch, 0) != 0) + if (regexec(&psexp->ps_reg, argv, 1, &pmatch, 0) != 0) return (0); if ((flags & PSEXP_EXACT) && - (pmatch.rm_so != 0 || s[pmatch.rm_eo] != '\0')) + (pmatch.rm_so != 0 || argv[pmatch.rm_eo] != '\0')) return (0); } diff --git a/usr/src/cmd/pgrep/psexp.h b/usr/src/cmd/pgrep/psexp.h index 741050cbe4..7de6742311 100644 --- a/usr/src/cmd/pgrep/psexp.h +++ b/usr/src/cmd/pgrep/psexp.h @@ -24,11 +24,13 @@ * Use is subject to license terms. */ +/* + * Copyright 2019 Joyent, Inc. + */ + #ifndef _PSEXP_H #define _PSEXP_H -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/types.h> #include <procfs.h> #include <regex.h> @@ -39,8 +41,7 @@ extern "C" { #include "idtab.h" -#define PSEXP_PSARGS 0x1 /* Match against psargs rather than fname */ -#define PSEXP_EXACT 0x2 /* Match must be exact (entire string) */ +#define PSEXP_EXACT 0x1 /* Match must be exact (entire string) */ typedef struct psexp { idtab_t ps_euids; /* Table of effective uids to match */ @@ -54,14 +55,14 @@ typedef struct psexp { idtab_t ps_taskids; /* Table of task ids to match */ idtab_t ps_zoneids; /* Table of zone ids to match */ idtab_t ps_ctids; /* Table of contract ids to match */ - const char *ps_pat; /* Uncompiled fname/psargs regexp pattern */ - regex_t ps_reg; /* Compiled fname/psargs regexp */ + const char *ps_pat; /* Uncompiled fname/argv regexp pattern */ + regex_t ps_reg; /* Compiled fname/argv regexp */ } psexp_t; extern void psexp_create(psexp_t *); extern void psexp_destroy(psexp_t *); extern int psexp_compile(psexp_t *); -extern int psexp_match(psexp_t *, psinfo_t *, int); +extern int psexp_match(psexp_t *, psinfo_t *, const char *, int); #ifdef __cplusplus } diff --git a/usr/src/cmd/ps/ps.c b/usr/src/cmd/ps/ps.c index 6a01543b00..1387a9440a 100644 --- a/usr/src/cmd/ps/ps.c +++ b/usr/src/cmd/ps/ps.c @@ -27,7 +27,7 @@ */ /* - * Copyright (c) 2018, Joyent, Inc. + * Copyright 2019 Joyent, Inc. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ @@ -64,6 +64,8 @@ #include <sys/pset.h> #include <project.h> #include <zone.h> +#include <assert.h> +#include <stdbool.h> #define min(a, b) ((a) > (b) ? (b) : (a)) #define max(a, b) ((a) < (b) ? (b) : (a)) @@ -337,6 +339,10 @@ static int pidcmp(const void *p1, const void *p2); extern int ucbmain(int, char **); static int stdmain(int, char **); +/* also used by ucbps.c */ +void get_psargs(bool, bool, psinfo_t *, char *, size_t); +void print_psargs(char *, int); + int main(int argc, char **argv) { @@ -1370,14 +1376,12 @@ prfind(int found, psinfo_t *psinfo, char **tpp) static void prcom(psinfo_t *psinfo, char *ttyp) { - char *cp; - long tm; - int bytesleft; - int wcnt, length; - wchar_t wchar; + long tm; + int wcnt; struct passwd *pwd; - int zombie_lwp; - char zonename[ZONENAME_MAX]; + int zombie_lwp; + char zonename[ZONENAME_MAX]; + char psargs[PRMAXARGVLEN] = ""; /* * If process is zombie, call zombie print routine and return. @@ -1566,44 +1570,22 @@ prcom(psinfo_t *psinfo, char *ttyp) if (psinfo->pr_time.tv_nsec > 500000000) tm++; } - (void) printf(" %4ld:%.2ld", tm / 60, tm % 60); /* [L]TIME */ + (void) printf(" %4ld:%.2ld ", tm / 60, tm % 60); /* [L]TIME */ if (zombie_lwp) { - (void) printf(" <defunct>\n"); + (void) printf("<defunct>\n"); return; } if (!fflg) { /* CMD */ wcnt = namencnt(psinfo->pr_fname, 16, 8); - (void) printf(" %.*s\n", wcnt, psinfo->pr_fname); + (void) printf("%.*s\n", wcnt, psinfo->pr_fname); return; } - - /* - * PRARGSZ == length of cmd arg string. - */ - psinfo->pr_psargs[PRARGSZ-1] = '\0'; - bytesleft = PRARGSZ; - for (cp = psinfo->pr_psargs; *cp != '\0'; cp += length) { - length = mbtowc(&wchar, cp, MB_LEN_MAX); - if (length == 0) - break; - if (length < 0 || !iswprint(wchar)) { - if (length < 0) - length = 1; - if (bytesleft <= length) { - *cp = '\0'; - break; - } - /* omit the unprintable character */ - (void) memmove(cp, cp+length, bytesleft-length); - length = 0; - } - bytesleft -= length; - } - wcnt = namencnt(psinfo->pr_psargs, PRARGSZ, lflg ? 35 : PRARGSZ); - (void) printf(" %.*s\n", wcnt, psinfo->pr_psargs); + get_psargs(false, fflg, psinfo, psargs, sizeof (psargs)); + print_psargs(psargs, 0); + printf("\n"); } /* @@ -1658,20 +1640,98 @@ print_time(time_t tim, int width) (void) printf("%*s", width, buf); } +void +get_psargs(bool comm, bool full, psinfo_t *psinfo, char *buf, size_t bufsize) +{ + char *path = NULL; + ssize_t size = 0; + char *cp; + int fd; + + assert(psinfo->pr_psargs[PRARGSZ - 1] == '\0'); + + if (full && getenv("SHORT_PSARGS") == NULL && + asprintf(&path, "%s/%d/cmdline", procdir, + (int)psinfo->pr_pid) != -1 && (fd = open(path, O_RDONLY)) != -1) { + size = read(fd, buf, bufsize); + (void) close(fd); + } + + free(path); + + if (size <= 0) { + (void) strlcpy(buf, psinfo->pr_psargs, bufsize); + } else { + ssize_t i; + + buf[bufsize - 1] = '\0'; + + for (cp = buf; cp - buf < size; cp++) { + if (*cp == '\0' && (cp - buf) + 1 < size) + *cp = ' '; + } + + for (i = strlen(buf) - 1; i >= 0 && isspace(buf[i]); i--) { + buf[i] = '\0'; + } + } + + if (comm && (cp = strpbrk(buf, " \t\r\v\f\n")) != NULL) + *cp = '\0'; +} + +void +print_psargs(char *psargs, int width) +{ + int bytesleft; + int length; + char *cp; + int wcnt; + + bytesleft = strlen(psargs); + + for (cp = psargs; *cp != '\0'; cp += length) { + wchar_t wchar; + + length = mbtowc(&wchar, cp, MB_LEN_MAX); + + if (length == 0) + break; + + if (length < 0 || !iswprint(wchar)) { + if (length < 0) + length = 1; + if (bytesleft <= length) { + *cp = '\0'; + break; + } + /* omit the unprintable character */ + (void) memmove(cp, cp + length, bytesleft - length); + bytesleft -= length; + length = 0; + } + bytesleft -= length; + } + + wcnt = namencnt(psargs, PRMAXARGVLEN, width); + + if (width != 0) { + (void) printf("%.*s", width, psargs); + } else { + (void) printf("%-.*s", wcnt, psargs); + } +} + static void print_field(psinfo_t *psinfo, struct field *f, const char *ttyp) { + char psargs[PRMAXARGVLEN] = ""; int width = f->width; struct passwd *pwd; struct group *grp; time_t cputime; - int bytesleft; int wcnt; - wchar_t wchar; - char *cp; - int length; ulong_t mask; - char c = '\0', *csave = NULL; int zombie_lwp; zombie_lwp = (Lflg && psinfo->pr_lwp.pr_sname == 'Z'); @@ -1924,12 +1984,11 @@ print_field(psinfo_t *psinfo, struct field *f, const char *ttyp) (void) printf("%s", "<defunct>"); break; } - csave = strpbrk(psinfo->pr_psargs, " \t\r\v\f\n"); - if (csave) { - c = *csave; - *csave = '\0'; - } - /* FALLTHROUGH */ + + get_psargs(true, false, psinfo, psargs, sizeof (psargs)); + print_psargs(psargs, f->next != NULL ? width : 0); + break; + case F_ARGS: /* * PRARGSZ == length of cmd arg string. @@ -1938,38 +1997,11 @@ print_field(psinfo_t *psinfo, struct field *f, const char *ttyp) (void) printf("%-*s", width, "<defunct>"); break; } - psinfo->pr_psargs[PRARGSZ-1] = '\0'; - bytesleft = PRARGSZ; - for (cp = psinfo->pr_psargs; *cp != '\0'; cp += length) { - length = mbtowc(&wchar, cp, MB_LEN_MAX); - if (length == 0) - break; - if (length < 0 || !iswprint(wchar)) { - if (length < 0) - length = 1; - if (bytesleft <= length) { - *cp = '\0'; - break; - } - /* omit the unprintable character */ - (void) memmove(cp, cp+length, bytesleft-length); - length = 0; - } - bytesleft -= length; - } - wcnt = namencnt(psinfo->pr_psargs, PRARGSZ, width); - /* - * Print full width unless this is the last format. - */ - if (f->next != NULL) - (void) printf("%-*.*s", width, wcnt, - psinfo->pr_psargs); - else - (void) printf("%-.*s", wcnt, - psinfo->pr_psargs); - if (f->fname == F_COMM && csave) - *csave = c; + + get_psargs(false, fflg, psinfo, psargs, sizeof (psargs)); + print_psargs(psargs, f->next != NULL ? width : 0); break; + case F_TASKID: (void) printf("%*d", width, (int)psinfo->pr_taskid); break; @@ -2430,7 +2462,8 @@ namencnt(char *cmd, int csisize, int scrsize) return (8); /* default to use for illegal chars */ if ((nscrsz = wcwidth(wchar)) <= 0) return (8); - if (csiwcnt + ncsisz > csisize || scrwcnt + nscrsz > scrsize) + if (csiwcnt + ncsisz > csisize || + (scrsize != 0 && scrwcnt + nscrsz > scrsize)) break; csiwcnt += ncsisz; scrwcnt += nscrsz; diff --git a/usr/src/cmd/ps/ucbps.c b/usr/src/cmd/ps/ucbps.c index 3110e95313..c368426184 100644 --- a/usr/src/cmd/ps/ucbps.c +++ b/usr/src/cmd/ps/ucbps.c @@ -21,7 +21,7 @@ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. - * Copyright 2012, Joyent, Inc. All rights reserved. + * Copyright 2019 Joyent, Inc. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ @@ -65,8 +65,10 @@ #include <wctype.h> #include <stdarg.h> #include <sys/proc.h> +#include <sys/procfs.h> #include <priv_utils.h> #include <zone.h> +#include <stdbool.h> #define NTTYS 2 /* max ttys that can be specified with the -t option */ /* only one tty can be specified with SunOS ps */ @@ -101,6 +103,7 @@ static int nflg; /* Numerical output */ static int pflg; /* Specific process id passed as argument */ static int Uflg; /* Update private database, ups_data */ static int errflg; +static int wflag; static char *gettty(); static char argbuf[ARGSIZ]; @@ -133,8 +136,7 @@ static void getarg(void); static void prtime(timestruc_t st); static void przom(psinfo_t *psinfo); static int num(char *); -static int preadargs(int, psinfo_t *, char *); -static int preadenvs(int, psinfo_t *, char *); +static int preadenvs(int, psinfo_t *, char *, size_t); static int prcom(int, psinfo_t *, char *); static int namencnt(char *, int, int); static int pscompare(const void *, const void *); @@ -142,12 +144,18 @@ static char *err_string(int); extern int scrwidth(wchar_t); /* header file? */ +/* from ps.c */ +void get_psargs(bool, bool, psinfo_t *, char *, size_t); +void print_psargs(char *, int); + int ucbmain(int argc, char **argv) { psinfo_t info; /* process information structure from /proc */ - char *psargs = NULL; /* pointer to buffer for -w and -ww options */ - char *svpsargs = NULL; + /* + * This can also store env vars, so we bump up the size. + */ + char psargs[PRMAXARGVLEN * 2] = ""; struct psent *psent; int entsize; int nent; @@ -236,11 +244,12 @@ ucbmain(int argc, char **argv) case 'U': /* update private database ups_data */ Uflg++; break; - case 'w': /* increase display width */ + case 'w': if (twidth < 132) twidth = 132; - else /* second w option */ + if (wflag) twidth = NCARGS; + wflag++; break; case 'v': /* display virtual memory format */ vflg++; @@ -372,15 +381,9 @@ ucbmain(int argc, char **argv) (void) sprintf(hdr, "%*s TT S TIME COMMAND", pidwidth + 1, "PID"); - twidth = twidth - strlen(hdr) + 6; + twidth = twidth - strlen(hdr) + 7; (void) printf("%s\n", hdr); - if (twidth > PRARGSZ && (psargs = malloc(twidth)) == NULL) { - (void) fprintf(stderr, "ps: no memory\n"); - exit(1); - } - svpsargs = psargs; - /* * Determine which processes to print info about by searching * the /proc directory and looking at each process. @@ -410,7 +413,7 @@ retry: if ((psfd = open(psname, O_RDONLY)) == -1) continue; asfd = -1; - if (psargs != NULL || eflg) { + if (eflg) { /* now we need the proc_owner privilege */ (void) __priv_bracket(PRIV_ON); @@ -470,26 +473,20 @@ retry: if (!found && !tflg && !aflg && info.pr_euid != my_uid) goto closeit; - /* - * Read the args for the -w and -ww cases - */ - if (asfd > 0) { - if ((psargs != NULL && - preadargs(asfd, &info, psargs) == -1) || - (eflg && preadenvs(asfd, &info, psargs) == -1)) { - int saverr = errno; + get_psargs(false, wflag, &info, psargs, sizeof (psargs)); - (void) close(asfd); - if (saverr == EAGAIN) - goto retry; - if (saverr != ENOENT) - (void) fprintf(stderr, - "ps: read() on %s: %s\n", - asname, err_string(saverr)); - continue; + if (eflg && asfd > 0 && + preadenvs(asfd, &info, psargs, sizeof (psargs)) == -1) { + int saverr = errno; + + (void) close(asfd); + if (saverr == EAGAIN) + goto retry; + if (saverr != ENOENT) { + (void) fprintf(stderr, "ps: read() on %s: %s\n", + asname, err_string(saverr)); } - } else { - psargs = info.pr_psargs; + continue; } if (nent >= entsize) { @@ -507,22 +504,17 @@ retry: exit(1); } *psent[nent].psinfo = info; - if (psargs == NULL) - psent[nent].psargs = NULL; - else { - if ((psent[nent].psargs = malloc(strlen(psargs)+1)) - == NULL) { - (void) fprintf(stderr, "ps: no memory\n"); - exit(1); - } - (void) strcpy(psent[nent].psargs, psargs); + + if ((psent[nent].psargs = strndup(psargs, twidth)) == NULL) { + (void) fprintf(stderr, "ps: no memory\n"); + exit(1); } + psent[nent].found = found; nent++; closeit: if (asfd > 0) (void) close(asfd); - psargs = svpsargs; } /* revert to non-privileged user */ @@ -553,100 +545,17 @@ usage() /* print usage message and quit */ } /* - * Read the process arguments from the process. - * This allows >PRARGSZ characters of arguments to be displayed but, - * unlike pr_psargs[], the process may have changed them. - */ -#define NARG 100 -static int -preadargs(int pfd, psinfo_t *psinfo, char *psargs) -{ - off_t argvoff = (off_t)psinfo->pr_argv; - size_t len; - char *psa = psargs; - int bsize = twidth; - int narg = NARG; - off_t argv[NARG]; - off_t argoff; - off_t nextargoff; - int i; -#ifdef _LP64 - caddr32_t argv32[NARG]; - int is32 = (psinfo->pr_dmodel != PR_MODEL_LP64); -#endif - - if (psinfo->pr_nlwp == 0 || - strcmp(psinfo->pr_lwp.pr_clname, "SYS") == 0) - goto out; - - (void) memset(psa, 0, bsize--); - nextargoff = 0; - errno = EIO; - while (bsize > 0) { - if (narg == NARG) { - (void) memset(argv, 0, sizeof (argv)); -#ifdef _LP64 - if (is32) { - if ((i = pread(pfd, argv32, sizeof (argv32), - argvoff)) <= 0) { - if (i == 0 || errno == EIO) - break; - return (-1); - } - for (i = 0; i < NARG; i++) - argv[i] = argv32[i]; - } else -#endif - if ((i = pread(pfd, argv, sizeof (argv), - argvoff)) <= 0) { - if (i == 0 || errno == EIO) - break; - return (-1); - } - narg = 0; - } - if ((argoff = argv[narg++]) == 0) - break; - if (argoff != nextargoff && - (i = pread(pfd, psa, bsize, argoff)) <= 0) { - if (i == 0 || errno == EIO) - break; - return (-1); - } - len = strlen(psa); - psa += len; - *psa++ = ' '; - bsize -= len + 1; - nextargoff = argoff + len + 1; -#ifdef _LP64 - argvoff += is32? sizeof (caddr32_t) : sizeof (caddr_t); -#else - argvoff += sizeof (caddr_t); -#endif - } - while (psa > psargs && isspace(*(psa-1))) - psa--; - -out: - *psa = '\0'; - if (strlen(psinfo->pr_psargs) > strlen(psargs)) - (void) strcpy(psargs, psinfo->pr_psargs); - - return (0); -} - -/* * Read environment variables from the process. * Append them to psargs if there is room. */ +#define NARG 100 static int -preadenvs(int pfd, psinfo_t *psinfo, char *psargs) +preadenvs(int pfd, psinfo_t *psinfo, char *psargs, size_t bufsize) { off_t envpoff = (off_t)psinfo->pr_envp; int len; char *psa; - char *psainit; - int bsize; + int remaining; int nenv = NARG; off_t envp[NARG]; off_t envoff; @@ -657,18 +566,18 @@ preadenvs(int pfd, psinfo_t *psinfo, char *psargs) int is32 = (psinfo->pr_dmodel != PR_MODEL_LP64); #endif - psainit = psa = (psargs != NULL)? psargs : psinfo->pr_psargs; + psa = psargs; len = strlen(psa); psa += len; - bsize = twidth - len - 1; + remaining = bufsize - len - 1; - if (bsize <= 0 || psinfo->pr_nlwp == 0 || + if (remaining <= 0 || psinfo->pr_nlwp == 0 || strcmp(psinfo->pr_lwp.pr_clname, "SYS") == 0) return (0); nextenvoff = 0; errno = EIO; - while (bsize > 0) { + while (remaining > 0) { if (nenv == NARG) { (void) memset(envp, 0, sizeof (envp)); #ifdef _LP64 @@ -694,7 +603,7 @@ preadenvs(int pfd, psinfo_t *psinfo, char *psargs) if ((envoff = envp[nenv++]) == 0) break; if (envoff != nextenvoff && - (i = pread(pfd, psa+1, bsize, envoff)) <= 0) { + (i = pread(pfd, psa+1, remaining, envoff)) <= 0) { if (i == 0 || errno == EIO) break; return (-1); @@ -702,7 +611,7 @@ preadenvs(int pfd, psinfo_t *psinfo, char *psargs) *psa++ = ' '; len = strlen(psa); psa += len; - bsize -= len + 1; + remaining -= len + 1; nextenvoff = envoff + len + 1; #ifdef _LP64 envpoff += is32? sizeof (caddr32_t) : sizeof (caddr_t); @@ -710,7 +619,7 @@ preadenvs(int pfd, psinfo_t *psinfo, char *psargs) envpoff += sizeof (caddr_t); #endif } - while (psa > psainit && isspace(*(psa-1))) + while (psa > psargs && isspace(*(psa-1))) psa--; *psa = '\0'; @@ -842,12 +751,9 @@ prtpct(ushort_t pct) static int prcom(int found, psinfo_t *psinfo, char *psargs) { - char *cp; char *tp; - char *psa; long tm; - int i, wcnt, length; - wchar_t wchar; + int wcnt; struct tty *ttyp; /* @@ -867,7 +773,6 @@ prcom(int found, psinfo_t *psinfo, char *psargs) * info. If 't' is set, check if term is in list of desired terminals * and print it if it is. */ - i = 0; tp = gettty(psinfo); if (*tp == '?' && !found && !xflg) @@ -999,37 +904,9 @@ prcom(int found, psinfo_t *psinfo, char *psargs) (void) printf(" %.*s", wcnt, psinfo->pr_fname); return (1); } - /* - * PRARGSZ == length of cmd arg string. - */ - if (psargs == NULL) { - psa = &psinfo->pr_psargs[0]; - i = PRARGSZ; - tp = &psinfo->pr_psargs[PRARGSZ]; - } else { - psa = psargs; - i = strlen(psargs); - tp = psa + i; - } - for (cp = psa; cp < tp; /* empty */) { - if (*cp == 0) - break; - length = mbtowc(&wchar, cp, MB_LEN_MAX); - if (length < 0 || !iswprint(wchar)) { - (void) printf(" [ %.16s ]", psinfo->pr_fname); - return (1); - } - cp += length; - } - wcnt = namencnt(psa, i, maxlen); -#if 0 - /* dumps core on really long strings */ - (void) printf(" %.*s", wcnt, psa); -#else - (void) putchar(' '); - (void) fwrite(psa, 1, wcnt, stdout); -#endif + printf(" "); + print_psargs(psargs, wflag < 2 ? maxlen : 0); return (1); } diff --git a/usr/src/cmd/ptools/ptree/ptree.c b/usr/src/cmd/ptools/ptree/ptree.c index 92a65e2f44..9890583260 100644 --- a/usr/src/cmd/ptools/ptree/ptree.c +++ b/usr/src/cmd/ptools/ptree/ptree.c @@ -21,7 +21,7 @@ /* * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. - * Copyright (c) 2014, Joyent, Inc. All rights reserved. + * Copyright 2019 Joyent, Inc. */ /* @@ -47,6 +47,8 @@ #include <sys/ctfs.h> #include <libcontract_priv.h> #include <sys/stat.h> +#include <stdbool.h> + #include "ptools_common.h" #define FAKEDPID0(p) (p->pid == 0 && p->psargs[0] == '\0') @@ -61,6 +63,7 @@ typedef struct ps { pid_t sid; zoneid_t zoneid; ctid_t ctid; + char *svc_fmri; timestruc_t start; char psargs[PRARGSZ]; struct ps *pp; /* parent */ @@ -81,16 +84,21 @@ static char *command; static int aflag = 0; static int cflag = 0; +static int sflag = 0; static int zflag = 0; static zoneid_t zoneid; +static const char *svc_fmri; static int columns = 80; -static void markprocs(ps_t *p); -static int printone(ps_t *p, int level); +static bool match_proc(ps_t *); +static void markprocs(ps_t *); +static int printone(ps_t *, int); static void insertchild(ps_t *, ps_t *); -static void prsort(ps_t *p); -static void printsubtree(ps_t *p, int level); -static zoneid_t getzone(char *arg); +static void prsort(ps_t *); +static void printsubtree(ps_t *, int); +static void p_get_svc_fmri(ps_t *, ct_stathdl_t); +static char *stripsvc(const char *); +static zoneid_t getzone(const char *); static ps_t *fakepid0(void); int @@ -118,7 +126,7 @@ main(int argc, char **argv) command++; /* options */ - while ((opt = getopt(argc, argv, "acz:")) != EOF) { + while ((opt = getopt(argc, argv, "acs:z:")) != EOF) { switch (opt) { case 'a': /* include children of process 0 */ aflag = 1; @@ -126,6 +134,10 @@ main(int argc, char **argv) case 'c': /* display contract ownership */ aflag = cflag = 1; break; + case 's': + sflag = 1; + svc_fmri = stripsvc(optarg); + break; case 'z': /* only processes in given zone */ zflag = 1; zoneid = getzone(optarg); @@ -141,7 +153,7 @@ main(int argc, char **argv) if (errflg) { (void) fprintf(stderr, - "usage:\t%s [-ac] [-z zone] [ {pid|user} ... ]\n", + "usage:\t%s [-ac] [-s svc] [-z zone] [ {pid|user} ... ]\n", command); (void) fprintf(stderr, " (show process trees)\n"); @@ -150,7 +162,9 @@ main(int argc, char **argv) (void) fprintf(stderr, " -a : include children of process 0\n"); (void) fprintf(stderr, - " -c : show contract ownership\n"); + " -c : show contracts\n"); + (void) fprintf(stderr, + " -s : print only processes with given service FMRI\n"); (void) fprintf(stderr, " -z : print only processes in given zone\n"); return (2); @@ -224,8 +238,8 @@ retry: return (1); } } - if ((p = malloc(sizeof (ps_t))) == NULL) { - perror("malloc()"); + if ((p = calloc(1, sizeof (ps_t))) == NULL) { + perror("calloc()"); return (1); } ps[nps++] = p; @@ -252,6 +266,10 @@ retry: p->pp = NULL; p->sp = NULL; p->cp = NULL; + + if (sflag) + p_get_svc_fmri(p, NULL); + if (p->pid == p->ppid) proc0 = p; if (p->pid == 1) @@ -338,8 +356,7 @@ retry: p->done != 1 && p->pid != 0; p = p->pp) if ((p->ppid != 0 || aflag) && - (!zflag || - p->zoneid == zoneid)) + match_proc(p)) p->done = 1; if (uid == (uid_t)-1) break; @@ -371,8 +388,9 @@ printone(ps_t *p, int level) PIDWIDTH, (int)p->pid, n, p->psargs); } else { assert(cflag != 0); - (void) printf("%*.*s[process contract %d]\n", - indent, indent, " ", (int)p->ctid); + (void) printf("%*.*s[process contract %d: %s]\n", + indent, indent, " ", (int)p->ctid, + p->svc_fmri == NULL ? "?" : p->svc_fmri); } return (1); } @@ -401,11 +419,50 @@ insertchild(ps_t *pp, ps_t *cp) *here = cp; } +static ct_stathdl_t +ct_status_open(ctid_t ctid, struct stat64 *stp) +{ + ct_stathdl_t hdl; + int fd; + + if ((fd = contract_open(ctid, "process", "status", O_RDONLY)) == -1) + return (NULL); + + if (fstat64(fd, stp) == -1 || ct_status_read(fd, CTD_FIXED, &hdl)) { + (void) close(fd); + return (NULL); + } + + (void) close(fd); + + return (hdl); +} + +/* + * strdup() failure is OK - better to report something than fail totally. + */ +static void +p_get_svc_fmri(ps_t *p, ct_stathdl_t inhdl) +{ + ct_stathdl_t hdl = inhdl; + struct stat64 st; + char *fmri; + + if (hdl == NULL && (hdl = ct_status_open(p->ctid, &st)) == NULL) + return; + + if (ct_pr_status_get_svc_fmri(hdl, &fmri) == 0) + p->svc_fmri = strdup(fmri); + + if (inhdl == NULL) + ct_status_free(hdl); +} + static void ctsort(ctid_t ctid, ps_t *p) { ps_t *pp; - int fd, n; + int n; ct_stathdl_t hdl; struct stat64 st; @@ -415,13 +472,8 @@ ctsort(ctid_t ctid, ps_t *p) return; } - if ((fd = contract_open(ctid, "process", "status", O_RDONLY)) == -1) - return; - if (fstat64(fd, &st) == -1 || ct_status_read(fd, CTD_COMMON, &hdl)) { - (void) close(fd); + if ((hdl = ct_status_open(ctid, &st)) == NULL) return; - } - (void) close(fd); if (nctps >= ctsize) { if ((ctsize *= 2) == 0) @@ -440,10 +492,14 @@ ctsort(ctid_t ctid, ps_t *p) pp->pid = -1; pp->ctid = ctid; + + p_get_svc_fmri(pp, hdl); + pp->start.tv_sec = st.st_ctime; insertchild(pp, p); pp->zoneid = ct_status_get_zoneid(hdl); + /* * In a zlogin <zonename>, the contract belongs to the * global zone and the shell opened belongs to <zonename>. @@ -513,11 +569,52 @@ printsubtree(ps_t *p, int level) printsubtree(p, level); } +/* + * For the service matching, we don't go the whole hog like svcs(1), but we will + * strip svc:/ and a :default prefix, and allow a match of the final part of the + * service such as "name-service-cache". + */ +static bool +match_proc(ps_t *p) +{ + const char *cp; + char *psvc; + + if (zflag && p->zoneid != zoneid) + return (false); + + if (!sflag) + return (true); + + if (p->svc_fmri == NULL) + return (false); + + if (strcmp(p->svc_fmri, svc_fmri) == 0) + return (true); + + psvc = stripsvc(p->svc_fmri); + + if (strcmp(psvc, svc_fmri) == 0) { + free(psvc); + return (true); + } + + if ((cp = strrchr(psvc, '/')) != NULL && + strcmp(cp + 1, svc_fmri) == 0) { + free(psvc); + return (true); + } + + free(psvc); + return (false); +} + static void markprocs(ps_t *p) { - if (!zflag || p->zoneid == zoneid) + if (match_proc(p)) p->done = 1; + for (p = p->cp; p != NULL; p = p->sp) markprocs(p); } @@ -532,8 +629,8 @@ fakepid0(void) ps_t *p0, *p; int n; - if ((p0 = malloc(sizeof (ps_t))) == NULL) { - perror("malloc()"); + if ((p0 = calloc(1, sizeof (ps_t))) == NULL) { + perror("calloc()"); exit(1); } (void) memset(p0, '\0', sizeof (ps_t)); @@ -559,7 +656,7 @@ fakepid0(void) /* convert string containing zone name or id to a numeric id */ static zoneid_t -getzone(char *arg) +getzone(const char *arg) { zoneid_t zoneid; @@ -569,3 +666,26 @@ getzone(char *arg) } return (zoneid); } + +/* svc:/...:default -> ... */ +static char * +stripsvc(const char *arg) +{ + const char *p = arg; + char *ret; + char *cp; + + if (strncmp(p, "svc:/", strlen("svc:/")) == 0) + p += strlen("svc:/"); + + if ((ret = strdup(p)) == NULL) { + perror("strdup()"); + exit(1); + } + + if ((cp = strrchr(ret, ':')) != NULL && + strcmp(cp, ":default") == 0) + *cp = '\0'; + + return (ret); +} diff --git a/usr/src/man/man1/pgrep.1 b/usr/src/man/man1/pgrep.1 index 9e65244f8d..57b23dfc7e 100644 --- a/usr/src/man/man1/pgrep.1 +++ b/usr/src/man/man1/pgrep.1 @@ -1,13 +1,13 @@ '\" te -.\" Copyright (c) 2004, Sun Microsystems, Inc. All Rights Reserved +.\" Copyright (c) 2004, Sun Microsystems, Inc. All Rights Reserved +.\" Copyright 2019 Joyent, Inc. .\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License. .\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing. See the License for the specific language governing permissions and limitations under the License. .\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE. If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner] -.TH PGREP 1 "Jan 17, 2014" +.TH PGREP 1 "Aug 13, 2019" .SH NAME pgrep, pkill \- find or signal processes by name and other attributes .SH SYNOPSIS -.LP .nf \fBpgrep\fR [\fB-flvx\fR] [\fB-n\fR | \fB-o\fR] [\fB-d\fR \fIdelim\fR] [\fB-P\fR \fIppidlist\fR] [\fB-g\fR \fIpgrplist\fR] [\fB-s\fR \fIsidlist\fR] [\fB-u\fR \fIeuidlist\fR] [\fB-U\fR \fIuidlist\fR] @@ -26,8 +26,6 @@ pgrep, pkill \- find or signal processes by name and other attributes .fi .SH DESCRIPTION -.sp -.LP The \fBpgrep\fR utility examines the active processes on the system and reports the process \fBID\fRs of the processes whose attributes match the criteria specified on the command line. Each process \fBID\fR is printed as a decimal @@ -74,8 +72,6 @@ process is signaled as if by \fBkill\fR(1) instead of having its process \fBID\fR printed. A signal name or number may be specified as the first command line option to \fBpkill\fR. .SH OPTIONS -.sp -.LP The following options are supported: .sp .ne 2 @@ -104,11 +100,11 @@ character. The \fB-d\fR option is only valid when specified as an option to \fB\fB-f\fR\fR .ad .RS 17n -The regular expression \fIpattern\fR should be matched against the full process -argument string (obtained from the \fBpr_psargs\fR field of the -\fB/proc/\fInnnnn\fR/psinfo\fR file). If no \fB-f\fR option is specified, the -expression is matched only against the name of the executable file (obtained -from the \fBpr_fname\fR field of the \fB/proc/\fInnnnn\fR/psinfo\fR file). +The regular expression \fIpattern\fR should be matched against all the process +arguments, not just the executable file name. +The process arguments are read from \fB\fB/proc/\fInnnnn\fR\fB/cmdline\fR: this +does not truncate the arguments, but reflects the current value, which may have +been changed. .RE .sp @@ -150,11 +146,9 @@ project \fBID\fR. \fB\fB-l\fR\fR .ad .RS 17n -Long output format. Prints the process name along with the process \fBID\fR of -each matching process. The process name is obtained from the \fBpr_psargs\fR or -\fBpr_fname\fR field, depending on whether the \fB-f\fR option was specified -(see above). The \fB-l\fR option is only valid when specified as an option to -\fBpgrep\fR. +Long output format. Prints the process arguments along with the process \fBID\fR of +each matching process, depending on how the \fB-f\fR option was specified. +The \fB-l\fR option is only valid when specified as an option to \fBpgrep\fR. .RE .sp @@ -258,8 +252,8 @@ which meet the specified matching criteria. .RS 17n Matches only processes whose executable file name (ignoring any path) \fBexactly\fR matches the specified \fIpattern\fR. However, when used with -f, -the \fIpattern\fR should be matched against the full process argument -string. For example if there exists a process `/bin/ls /home' then: +the \fIpattern\fR is matched against the full process argument +string. For example, if there exists a process `/bin/ls /home' then: .sp .in +2 .nf @@ -308,8 +302,6 @@ one of the symbolic names defined in \fBsignal.h\fR(3HEAD) without the .RE .SH OPERANDS -.sp -.LP The following operand is supported: .sp .ne 2 @@ -323,7 +315,6 @@ either the executable file name or full process argument string. See .RE .SH EXAMPLES -.LP \fBExample 1 \fRObtaining a Process ID .sp .LP @@ -352,9 +343,20 @@ example% \fBpkill -n xterm\fR .in -2 .sp -.SH EXIT STATUS +.LP +\fBExample 3 \fRMatching against all process arguments .sp .LP +Match against any process argument and report the arguments: + +.sp +.in +2 +.nf +example% \fBpgrep -fl myfile.txt\fR +.fi +.in -2 +.sp +.SH EXIT STATUS The following exit values are returned: .sp .ne 2 @@ -393,30 +395,33 @@ A fatal error occurred. .RE .SH FILES -.sp .ne 2 .na -\fB\fB/proc/\fInnnnn\fR/psinfo\fR\fR +\fB\fB/proc/\fInnnnn\fR\fB/psinfo\fR\fR .ad .RS 22n Process information files .RE -.SH SEE ALSO .sp -.LP +.ne 2 +.na +\fB\fB/proc/\fInnnnn\fR\fB/cmdline\fR\fR +.ad +.RS 22n +Process arguments. +.RE + +.SH SEE ALSO \fBkill\fR(1), \fBproc\fR(1), \fBps\fR(1), \fBtruss\fR(1), \fBkill\fR(2), \fBsignal.h\fR(3HEAD), \fBproc\fR(4), \fBattributes\fR(5), \fBprivileges\fR(5), \fBregex\fR(5), \fBzones\fR(5) .SH NOTES -.sp -.LP Both utilities match the \fBERE\fR \fIpattern\fR argument against either the -\fBpr_fname\fR or \fBpr_psargs\fR fields of the -\fB/proc/\fR\fInnnnn\fR\fB/psinfo\fR files. The lengths of these strings are -limited according to definitions in \fB<sys/procfs.h>\fR\&. Patterns which can -match strings longer than the current limits may fail to match the intended set -of processes. +\fBpr_fname\fR field of the \fB/proc/\fR\fInnnnn\fR\fB/psinfo\fR file, or +\fB/proc/\fR\fInnnnn\fR\fB/cmdline\fR, and may be truncated. +Patterns which can match strings longer than the current limits may fail to +match the intended set of processes. .sp .LP If the \fIpattern\fR argument contains \fBERE\fR meta-characters which are also diff --git a/usr/src/man/man1/ps.1 b/usr/src/man/man1/ps.1 index 2ed67d399e..ccce0d658b 100644 --- a/usr/src/man/man1/ps.1 +++ b/usr/src/man/man1/ps.1 @@ -44,13 +44,12 @@ .\" Portions Copyright (c) 1992, X/Open Company Limited All Rights Reserved .\" Copyright (c) 2009, Sun Microsystems, Inc. All Rights Reserved .\" Copyright (c) 2013 Gary Mills -.\" Copyright (c) 2018, Joyent, Inc. +.\" Copyright 2019 Joyent, Inc. .\" -.TH PS 1 "August 22, 2018" +.TH PS 1 "August 28, 2019" .SH NAME ps \- report process status .SH SYNOPSIS -.LP .nf \fBps\fR [\fB-aAcdefjHlLPWyZ\fR] [\fB-g\fR \fIgrplist\fR] [\fB-h\fR \fIlgrplist\fR] [\fB-n\fR \fInamelist\fR] [\fB-o\fR \fIformat\fR]... [\fB-p\fR \fIproclist\fR] @@ -59,7 +58,6 @@ ps \- report process status .fi .SH DESCRIPTION -.LP The \fBps\fR command prints information about active processes. Without options, \fBps\fR prints information about processes that have the same effective user \fBID\fR and the same controlling terminal as the invoker. The @@ -75,7 +73,6 @@ for \fIproclist\fR and \fIgrplist\fR must be numeric. .LP The \fBps\fR command also accepts BSD-style options. See \fBps\fR(1b). .SH OPTIONS -.LP The following options are supported: .sp .ne 2 @@ -375,9 +372,9 @@ Many of the options shown are used to select processes to list. If any are specified, the default list is ignored and \fBps\fR selects the processes represented by the inclusive OR of all the selection-criteria options. .SH DISPLAY FORMATS -.LP -Under the \fB-f\fR option, \fBps\fR tries to determine the command name and -arguments given when the process was created by examining the user block. +Under the \fB-f\fR option, \fBps\fR uses the \fB\fB/proc/\fInnnnn\fR\fB/cmdline\fR\fR +file to read the full process arguments. The process may have changed these +since it was started. Failing this, the command name is printed, as it would have appeared without the \fB-f\fR option, in square brackets. .sp @@ -608,8 +605,8 @@ The execution time for the lwp being reported. \fB\fBCMD\fR(all)\fR .ad .RS 14n -The command name (the full command name and its arguments, up to a limit of 80 -characters, are printed under the \fB-f\fR option). +The command name (or, with the \fB-f\fR option, the full current process +arguments). .RE .sp @@ -667,7 +664,6 @@ lwp. A process that has exited and has a parent, but has not yet been waited for by the parent, is marked \fB<defunct>\fR\&. .SS "\fB-o\fR format" -.LP The \fB-o\fR option allows the output format to be specified under user control. .sp @@ -885,9 +881,9 @@ is a version of the argument list as it was passed to the command when it started, or is a version of the arguments as they might have been modified by the application. Applications cannot depend on being able to modify their argument list and having that modification be reflected in the output of -\fBps\fR. The illumos implementation limits the string to 80 bytes; the string -is the version of the argument list as it was passed to the command when it -started. +\fBps\fR. However, the current implementation will display the full modified +process arguments when given the \fB-f\fR argument; otherwise this is the +initial process arguments, but limited to 80 bytes. .RE .sp @@ -1244,7 +1240,6 @@ ctid CTID .TE .SH EXAMPLES -.LP \fBExample 1 \fRUsing \fBps\fR Command .sp .LP @@ -1277,7 +1272,6 @@ The contents of the \fBCOMMAND\fR field need not be the same due to possible truncation. .SH ENVIRONMENT VARIABLES -.LP See \fBenviron\fR(5) for descriptions of the following environment variables that affect the execution of \fBps\fR: \fBLANG\fR, \fBLC_ALL\fR, \fBLC_CTYPE\fR, \fBLC_MESSAGES\fR, \fBLC_TIME\fR, and \fBNLSPATH\fR. @@ -1292,7 +1286,6 @@ number of text columns to display. .RE .SH EXIT STATUS -.LP The following exit values are returned: .sp .ne 2 @@ -1349,7 +1342,6 @@ process control files .RE .SH ATTRIBUTES -.LP See \fBattributes\fR(5) for descriptions of the following attributes: .sp @@ -1368,14 +1360,12 @@ Standard See \fBstandards\fR(5). .TE .SH SEE ALSO -.LP \fBkill\fR(1), \fBlgrpinfo\fR(1), \fBnice\fR(1), \fBpagesize\fR(1), \fBpmap\fR(1), \fBpriocntl\fR(1), \fBps\fR(1b), \fBwho\fR(1), \fBgetty\fR(1M), \fBproc\fR(4), \fBttysrch\fR(4), \fBattributes\fR(5), \fBenviron\fR(5), \fBresource_controls\fR(5), \fBstandards\fR(5), \fBzones\fR(5) .SH NOTES -.LP Things can change while \fBps\fR is running. The snapshot it gives is true only for a split-second, and it might not be accurate by the time you see it. Some data printed for defunct processes is irrelevant. diff --git a/usr/src/man/man1/ptree.1 b/usr/src/man/man1/ptree.1 index a8de77c0bd..e001066d59 100644 --- a/usr/src/man/man1/ptree.1 +++ b/usr/src/man/man1/ptree.1 @@ -1,27 +1,23 @@ '\" te .\" Copyright (c) 2005, Sun Microsystems, Inc. All Rights Reserved. +.\" Copyright 2019 Joyent, Inc. .\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License. .\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing. See the License for the specific language governing permissions and limitations under the License. .\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE. If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner] -.TH PTREE 1 "Oct 11, 2005" +.TH PTREE 1 "Sep 3, 2019" .SH NAME ptree \- print process trees .SH SYNOPSIS -.LP .nf -\fB/usr/bin/ptree\fR [\fB-a\fR] [\fB-c\fR] [\fB-z\fR \fIzone\fR] [\fIpid\fR | \fIuser\fR]... +\fB/usr/bin/ptree\fR [\fB-a\fR] [\fB-c\fR] [\fB-s\fR \fIsvc\fR] [\fB-z\fR \fIzone\fR] [\fIpid\fR | \fIuser\fR]... .fi .SH DESCRIPTION -.sp -.LP The \fBptree\fR utility prints the process trees containing the specified \fIpid\fRs or \fIuser\fRs, with child processes indented from their respective parent processes. An argument of all digits is taken to be a process-ID, otherwise it is assumed to be a user login name. The default is all processes. .SH OPTIONS -.sp -.LP The following options are supported: .sp .ne 2 @@ -38,8 +34,21 @@ All. Print all processes, including children of process 0. \fB\fB-c\fR\fR .ad .RS 11n -Contracts. Print process contract memberships in addition to parent-child -relationships. See \fBprocess\fR(4). This option implies the \fB-a\fR option. +Contracts. Print process contract memberships and their associated SMF FMRIs, +in addition to parent-child relationships. See \fBprocess\fR(4). +This option implies the \fB-a\fR option. +.RE + +.sp +.ne 2 +.na +\fB\fB-s\fR \fIsvc\fR\fR +.ad +.RS 11n +Print only processes with an SMF service FMRI matching the argument. The FMRI +may be in truncated form (such as 'console-login'). This includes children +processes even if they are not members of the service contract. +See \fBprocess\fR(4). .RE .sp @@ -55,8 +64,6 @@ This option is only useful when executed in the global zone. .RE .SH OPERANDS -.sp -.LP The following operands are supported: .sp .ne 2 @@ -80,7 +87,6 @@ given are displayed. .RE .SH EXAMPLES -.LP \fBExample 1 \fRUsing ptree .sp .LP @@ -104,8 +110,6 @@ $ ptree -a `pgrep ssh` .sp .SH EXIT STATUS -.sp -.LP The following exit values are returned: .sp .ne 2 @@ -126,7 +130,6 @@ An error has occurred. .RE .SH FILES -.sp .ne 2 .na \fB\fB/proc/*\fR\fR @@ -136,8 +139,6 @@ process files .RE .SH ATTRIBUTES -.sp -.LP See \fBattributes\fR(5) for descriptions of the following attributes: .sp @@ -155,8 +156,6 @@ Interface Stability See below. .LP The human readable output is Unstable. The options are Evolving. .SH SEE ALSO -.sp -.LP \fBgcore\fR(1), \fBldd\fR(1), \fBpargs\fR(1), \fBpgrep\fR(1), \fBpkill\fR(1), \fBplimit\fR(1), \fBpmap\fR(1), \fBpreap\fR(1), \fBproc\fR(1), \fBps\fR(1), \fBppgsz\fR(1), \fBpwd\fR(1), \fBrlogin\fR(1), \fBtime\fR(1), \fBtruss\fR(1), diff --git a/usr/src/man/man1b/ps.1b b/usr/src/man/man1b/ps.1b index 5db8faf6f6..77c970fc7e 100644 --- a/usr/src/man/man1b/ps.1b +++ b/usr/src/man/man1b/ps.1b @@ -1,17 +1,16 @@ '\" te .\" Copyright (c) 2002, Sun Microsystems, Inc. - All Rights Reserved. .\" Copyright (c), 1980 Regents of the University of California. All rights reserved. The Berkeley software License Agreement specifies the terms and conditions for redistribution. -.TH PS 1B "May 13, 2017" +.\" Copyright 2019 Joyent, Inc. +.TH PS 1B "Aug 13, 2019" .SH NAME ps \- display the status of current processes .SH SYNOPSIS -.LP .nf \fB/usr/ucb/ps\fR [\fB-aceglnrSuUvwx\fR] [\fB-t\fR \fIterm\fR] [\fInum\fR] .fi .SH DESCRIPTION -.LP The \fBps\fR command displays information about processes. Normally, only those processes that are running with your effective user \fBID\fR and are attached to a controlling terminal (see \fBtermio\fR(7I)) are shown. Additional @@ -78,7 +77,6 @@ Traced. Process stopped by a signal because parent is tracing it. .RE .SH OPTIONS -.LP The following options must all be combined to form the first argument: .sp .ne 2 @@ -206,11 +204,10 @@ fields \fBSIZE\fR, \fB%CPU\fR, \fB%MEM\fR, and \fBRSS\fR, described below. \fB\fB-w\fR\fR .ad .RS 11n -Uses a wide output format, that is, 132 columns rather than 80. If the option +Uses a wide output format, that is, truncate process arguments at 132 columns +rather than 80. If the option letter is repeated, that is, \fB-ww\fR, this option uses arbitrarily wide output. This information is used to decide how much of long commands to print. -\fBNote:\fR The wide output option can be viewed only by a superuser or the -user who owns the process. .RE .sp @@ -233,7 +230,6 @@ process. This option must be supplied last. .RE .SH DISPLAY FORMATS -.LP Fields that are not common to all output formats: .sp .ne 2 @@ -376,7 +372,6 @@ the parent, is marked <\fBdefunct\fR>\|; otherwise, \fBps\fR tries to determine the command name and arguments given when the process was created by examining the user block. .SH FILES -.LP \fB/dev/tty*\fR .sp .ne 2 @@ -388,11 +383,9 @@ the user block. .RE .SH SEE ALSO -.LP \fBkill\fR(1), \fBps\fR(1), \fBwhodo\fR(1M), \fBgetpriority\fR(3C), \fBnice\fR(2), \fBproc\fR(4), \fBattributes\fR(5), \fBtermio\fR(7I) .SH NOTES -.LP Things can change while \fBps\fR is running. The picture \fBps\fR gives is only a close approximation to the current state. Some data printed for defunct processes is irrelevant. diff --git a/usr/src/uts/common/brand/lx/os/lx_brand.c b/usr/src/uts/common/brand/lx/os/lx_brand.c index 83fbd6adb7..b6038fca07 100644 --- a/usr/src/uts/common/brand/lx/os/lx_brand.c +++ b/usr/src/uts/common/brand/lx/os/lx_brand.c @@ -379,8 +379,6 @@ lx_setbrand(proc_t *p) { /* Send SIGCHLD to parent by default when child exits */ ptolxproc(p)->l_signal = stol_signo[SIGCHLD]; - - lx_read_argv_bounds(p); } /* ARGSUSED */ diff --git a/usr/src/uts/common/brand/lx/os/lx_misc.c b/usr/src/uts/common/brand/lx/os/lx_misc.c index b73e7f430a..726c3c7915 100644 --- a/usr/src/uts/common/brand/lx/os/lx_misc.c +++ b/usr/src/uts/common/brand/lx/os/lx_misc.c @@ -135,11 +135,6 @@ lx_exec() lx_restore(lwp); kpreempt_enable(); - /* Grab the updated argv bounds */ - mutex_enter(&p->p_lock); - lx_read_argv_bounds(p); - mutex_exit(&p->p_lock); - /* * The exec syscall doesn't return (so we don't call lx_syscall_return) * but for our ptrace emulation we need to do this so that a tracer @@ -1058,72 +1053,6 @@ stol_ksiginfo32_copyout(k_siginfo_t *sip, void *ulxsip) } #endif -/* - * Linux uses the original bounds of the argv array when determining the - * contents of /proc/<pid/cmdline. We mimic those bounds using argv[0] and - * envp[0] as the beginning and end, respectively. - */ -void -lx_read_argv_bounds(proc_t *p) -{ - user_t *up = PTOU(p); - lx_proc_data_t *pd = ptolxproc(p); - uintptr_t addr_arg = up->u_argv; - uintptr_t addr_env = up->u_envp; - uintptr_t arg_start = 0, env_start = 0, env_end = 0; - int i = 0; - - VERIFY(pd != NULL); - VERIFY(MUTEX_HELD(&p->p_lock)); - - /* - * Use AT_SUN_PLATFORM in the aux vector to find the end of the envp - * strings. - */ - for (i = 0; i < __KERN_NAUXV_IMPL; i++) { - if (up->u_auxv[i].a_type == AT_SUN_PLATFORM) { - env_end = (uintptr_t)up->u_auxv[i].a_un.a_val; - } - } - - /* - * If we come through here for a kernel process (zsched), which happens - * with our cgroupfs when we fork the release agent, then u_argv and - * u_envp will be NULL. While this won't cause a failure, it does - * cause a lot of overhead when the fuword causes a fault, which leads - * to a large amount of stack growth and anonymous memory allocation, - * all of which is pointless since the first page can't be mapped. - */ - if (addr_arg != (uintptr_t)NULL || addr_env != (uintptr_t)NULL) { - mutex_exit(&p->p_lock); -#if defined(_LP64) - if (p->p_model != DATAMODEL_NATIVE) { - uint32_t buf32; - if (fuword32((void *)addr_arg, &buf32) == 0) { - arg_start = (uintptr_t)buf32; - } - if (fuword32((void *)addr_env, &buf32) == 0) { - env_start = (uintptr_t)buf32; - } - } else -#endif /* defined(_LP64) */ - { - ulong_t buf; - if (fulword((void *)addr_arg, &buf) == 0) { - arg_start = (uintptr_t)buf; - } - if (fulword((void *)addr_env, &buf) == 0) { - env_start = (uintptr_t)buf; - } - } - mutex_enter(&p->p_lock); - } - - pd->l_args_start = arg_start; - pd->l_envs_start = env_start; - pd->l_envs_end = env_end; -} - /* Given an LX LWP, determine where user register state is stored. */ lx_regs_location_t lx_regs_location(lx_lwp_data_t *lwpd, void **ucp, boolean_t for_write) diff --git a/usr/src/uts/common/brand/lx/procfs/lx_prvnops.c b/usr/src/uts/common/brand/lx/procfs/lx_prvnops.c index bcfdd346da..90e8fbe4d5 100644 --- a/usr/src/uts/common/brand/lx/procfs/lx_prvnops.c +++ b/usr/src/uts/common/brand/lx/procfs/lx_prvnops.c @@ -83,10 +83,11 @@ #include <sys/socketvar.h> #include <fs/sockfs/socktpi.h> #include <sys/random.h> +#include <sys/procfs.h> /* Dependent on procfs */ extern kthread_t *prchoose(proc_t *); -extern int prreadargv(proc_t *, char *, size_t, size_t *); +extern int prreadcmdline(proc_t *, char *, size_t, size_t *); extern int prreadenvv(proc_t *, char *, size_t, size_t *); extern int prreadbuf(proc_t *, uintptr_t, uint8_t *, size_t, size_t *); @@ -332,10 +333,9 @@ extern swrand_stats_t swrand_stats; #define FOURGB 4294967295ULL /* - * The maximum length of the concatenation of argument vector strings we - * will return to the user via the branded procfs. Likewise for the env vector. + * The maximum length of the concatenation of env vector strings we + * will return to the user via the branded procfs. */ -int lxpr_maxargvlen = 4096; int lxpr_maxenvvlen = 4096; /* @@ -1501,77 +1501,6 @@ lxpr_read_pid_cgroup(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf) lxpr_uiobuf_printf(uiobuf, "1:name=systemd:/\n"); } -static void -lxpr_copy_cmdline(proc_t *p, lx_proc_data_t *pd, lxpr_uiobuf_t *uiobuf) -{ - uio_t *uiop = uiobuf->uiop; - char *buf = uiobuf->buffer; - int bsz = uiobuf->buffsize; - boolean_t env_overflow = B_FALSE; - uintptr_t pos = pd->l_args_start + uiop->uio_offset; - uintptr_t estart = pd->l_envs_start; - uintptr_t eend = pd->l_envs_end; - size_t chunk, copied; - int err = 0; - - /* Do not bother with data beyond the end of the envp strings area. */ - if (pos > eend) { - return; - } - mutex_exit(&p->p_lock); - - /* - * If the starting or ending bounds are outside the argv strings area, - * check to see if the process has overwritten the terminating NULL. - * If not, no data needs to be copied from oustide the argv area. - */ - if (pos >= estart || (pos + uiop->uio_resid) >= estart) { - uint8_t term; - if (uread(p, &term, sizeof (term), estart - 1) != 0) { - err = EFAULT; - } else if (term != 0) { - env_overflow = B_TRUE; - } - } - - /* Data between astart and estart-1 can be copied freely. */ - while (pos < estart && uiop->uio_resid > 0 && err == 0) { - chunk = MIN(estart - pos, uiop->uio_resid); - chunk = MIN(chunk, bsz); - - if (prreadbuf(p, pos, (uint8_t *)buf, chunk, &copied) != 0 || - copied != chunk) { - err = EFAULT; - break; - } - err = uiomove(buf, copied, UIO_READ, uiop); - pos += copied; - } - - /* - * Onward from estart, data is copied as a contiguous string. To - * protect env data from potential snooping, only one buffer-sized copy - * is allowed to avoid complex seek logic. - */ - if (err == 0 && env_overflow && pos == estart && uiop->uio_resid > 0) { - chunk = MIN(eend - pos, uiop->uio_resid); - chunk = MIN(chunk, bsz); - if (prreadbuf(p, pos, (uint8_t *)buf, chunk, &copied) == 0) { - int len = strnlen(buf, copied); - if (len > 0) { - err = uiomove(buf, len, UIO_READ, uiop); - } - } - } - - uiobuf->error = err; - /* reset any uiobuf state */ - uiobuf->pos = uiobuf->buffer; - uiobuf->beg = 0; - - mutex_enter(&p->p_lock); -} - /* * lxpr_read_pid_cmdline(): read argument vector from process */ @@ -1580,8 +1509,8 @@ lxpr_read_pid_cmdline(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf) { proc_t *p; char *buf; - size_t asz = lxpr_maxargvlen, sz; - lx_proc_data_t *pd; + size_t asz = PRMAXARGVLEN, sz; + int r; ASSERT(lxpnp->lxpr_type == LXPR_PID_CMDLINE || lxpnp->lxpr_type == LXPR_PID_TID_CMDLINE); @@ -1594,23 +1523,16 @@ lxpr_read_pid_cmdline(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf) return; } - if ((pd = ptolxproc(p)) != NULL && pd->l_args_start != 0 && - pd->l_envs_start != 0 && pd->l_envs_end != 0) { - /* Use Linux-style argv bounds if possible. */ - lxpr_copy_cmdline(p, pd, uiobuf); - lxpr_unlock(p); - } else { - int r; + r = prreadcmdline(p, buf, asz, &sz); - r = prreadargv(p, buf, asz, &sz); - lxpr_unlock(p); + lxpr_unlock(p); - if (r != 0) { - lxpr_uiobuf_seterr(uiobuf, EINVAL); - } else { - lxpr_uiobuf_write(uiobuf, buf, sz); - } + if (r != 0) { + lxpr_uiobuf_seterr(uiobuf, EINVAL); + } else { + lxpr_uiobuf_write(uiobuf, buf, sz); } + kmem_free(buf, asz); } diff --git a/usr/src/uts/common/brand/lx/sys/lx_brand.h b/usr/src/uts/common/brand/lx/sys/lx_brand.h index 9c1579cc82..90d87d78a8 100644 --- a/usr/src/uts/common/brand/lx/sys/lx_brand.h +++ b/usr/src/uts/common/brand/lx/sys/lx_brand.h @@ -24,7 +24,7 @@ */ /* - * Copyright 2018 Joyent, Inc. + * Copyright 2019 Joyent, Inc. */ #ifndef _LX_BRAND_H @@ -132,8 +132,8 @@ typedef enum lx_ptrace_options { } lx_ptrace_options_t; #define LX_PTRACE_O_ALL \ - (LX_PTRACE_O_TRACESYSGOOD | LX_PTRACE_O_TRACEFORK | \ - LX_PTRACE_O_TRACEVFORK | LX_PTRACE_O_TRACECLONE | \ + (LX_PTRACE_O_TRACESYSGOOD | LX_PTRACE_O_TRACEFORK | \ + LX_PTRACE_O_TRACEVFORK | LX_PTRACE_O_TRACECLONE | \ LX_PTRACE_O_TRACEEXEC | LX_PTRACE_O_TRACEVFORKDONE | \ LX_PTRACE_O_TRACEEXIT | LX_PTRACE_O_TRACESECCOMP) #endif /* !_ASM */ @@ -344,11 +344,6 @@ typedef struct lx_proc_data { uint_t l_io_ctx_cnt; struct lx_io_ctx **l_io_ctxs; - /* original start/end bounds of arg/env string data */ - uintptr_t l_args_start; - uintptr_t l_envs_start; - uintptr_t l_envs_end; - /* Override zone-wide settings for uname release and version */ char l_uname_release[LX_KERN_RELEASE_MAX]; char l_uname_version[LX_KERN_VERSION_MAX]; @@ -365,7 +360,7 @@ typedef struct lx_proc_data { lx_segmap_t l_remap_anoncache[LX_REMAP_ANONCACHE_NENTRIES]; /* Block all signals to all threads; used during vfork */ - uint_t l_block_all_signals; + uint_t l_block_all_signals; } lx_proc_data_t; #endif /* _KERNEL */ @@ -545,7 +540,7 @@ struct lx_lwp_data { lx_ptrace_accord_t *br_ptrace_tracer; /* accord tracing this LWP */ list_node_t br_ptrace_linkage; /* linkage for lxpa_tracees list */ - ushort_t br_ptrace_whystop; /* stop reason, 0 for no stop */ + ushort_t br_ptrace_whystop; /* stop reason, 0 for no stop */ ushort_t br_ptrace_whatstop; /* stop sub-reason */ int32_t br_ptrace_stopsig; /* stop signal, 0 for no signal */ diff --git a/usr/src/uts/common/brand/lx/sys/lx_misc.h b/usr/src/uts/common/brand/lx/sys/lx_misc.h index 0418d3e9f9..e81a1597f3 100644 --- a/usr/src/uts/common/brand/lx/sys/lx_misc.h +++ b/usr/src/uts/common/brand/lx/sys/lx_misc.h @@ -10,7 +10,7 @@ */ /* - * Copyright 2017 Joyent, Inc. + * Copyright 2019 Joyent, Inc. */ #ifndef _SYS__LX_MISC_H @@ -62,7 +62,6 @@ extern int ltos_at_flag(int, int, boolean_t); #if defined(_SYSCALL32_IMPL) extern int stol_ksiginfo32_copyout(k_siginfo_t *, void *); #endif -extern void lx_read_argv_bounds(proc_t *p); typedef enum lx_regs_location { LX_REG_LOC_UNAVAIL, diff --git a/usr/src/uts/common/contract/process.c b/usr/src/uts/common/contract/process.c index e46cbd3abf..6e43bd7aef 100644 --- a/usr/src/uts/common/contract/process.c +++ b/usr/src/uts/common/contract/process.c @@ -21,7 +21,7 @@ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. - * Copyright 2016 Joyent, Inc. + * Copyright 2019 Joyent, Inc. */ #include <sys/mutex.h> @@ -737,13 +737,11 @@ contract_process_status(contract_t *ct, zone_t *zone, int detail, nvlist_t *nvl, * if we are in a local zone and svc_fmri was inherited from * the global zone, we provide fake svc_fmri and svc_ctid */ - if (local_svc_zone_enter == 0|| + if (local_svc_zone_enter == 0 || zone->zone_uniqid == GLOBAL_ZONEUNIQID) { if (detail > CTD_COMMON) { VERIFY(nvlist_add_int32(nvl, CTPS_SVC_CTID, ctp->conp_svc_ctid) == 0); - } - if (detail == CTD_ALL) { VERIFY(nvlist_add_string(nvl, CTPS_SVC_FMRI, refstr_value(ctp->conp_svc_fmri)) == 0); } @@ -751,8 +749,6 @@ contract_process_status(contract_t *ct, zone_t *zone, int detail, nvlist_t *nvl, if (detail > CTD_COMMON) { VERIFY(nvlist_add_int32(nvl, CTPS_SVC_CTID, local_svc_zone_enter) == 0); - } - if (detail == CTD_ALL) { VERIFY(nvlist_add_string(nvl, CTPS_SVC_FMRI, CT_PR_SVC_FMRI_ZONE_ENTER) == 0); } diff --git a/usr/src/uts/common/fs/proc/prargv.c b/usr/src/uts/common/fs/proc/prargv.c index 40d47598ac..60d098d125 100644 --- a/usr/src/uts/common/fs/proc/prargv.c +++ b/usr/src/uts/common/fs/proc/prargv.c @@ -28,7 +28,7 @@ * returned to the caller via 'rdsz'. */ int -prreadbuf(proc_t *p, uintptr_t ustart, uint8_t *buf, size_t sz, size_t *rdsz) +prreadbuf(proc_t *p, uintptr_t ustart, char *buf, size_t sz, size_t *rdsz) { int error = 0; size_t rem = sz; @@ -63,6 +63,95 @@ prreadbuf(proc_t *p, uintptr_t ustart, uint8_t *buf, size_t sz, size_t *rdsz) return (error); } + +/* + * Effectively a truncating version of copyinstr(). + * + * The resulting string is guaranteed to be truncated to fit within the buffer + * (hence sz == 0 is not supported). The returned size includes the truncating + * NUL. + */ +int +prreadstr(proc_t *p, uintptr_t ustart, char *buf, size_t bufsz, size_t *rdsz) +{ + size_t slen; + int err; + + VERIFY(bufsz != 0); + + if ((err = prreadbuf(p, ustart, buf, bufsz, &slen)) != 0) + return (err); + + slen = strnlen(buf, slen); + + if (slen == bufsz) + slen--; + + buf[slen++] = '\0'; + + if (rdsz != NULL) + *rdsz = slen; + return (0); +} + +/* + * /proc/pid/cmdline: Linux-compatible '\0'-separated process argv. + * + * Unlike /proc/pid/argv, this looks at the exec()-time argv string area, rather + * than starting from the argv[] array. Thus changes to the array are not + * noticed, but direct modifications of the string are visible here. Since it's + * common for applications to expect it, we implement the Linux semantics here. + * + * There is special handling if the process has modified its argv: if the last + * byte of the argv string area is no longer NUL, then we presume that it has + * done setproctitle() or similar, and we should copy it as a single string from + * the start, even though it overflows into the env string area. Note that we + * can't use copyinstr() as that returns ENAMETOOLONG rather than truncating as + * we need. + * + * Otherwise, we provide the argv string area in toto. + */ +int +prreadcmdline(proc_t *p, char *buf, size_t bufsz, size_t *slen) +{ + user_t *up = &p->p_user; + uint8_t term; + int err = 0; + + VERIFY(bufsz == PRMAXARGVLEN); + VERIFY(MUTEX_HELD(&p->p_lock)); + + if ((p->p_flag & SSYS) || p->p_as == &kas || up->u_argvstrsize == 0) { + bcopy(up->u_psargs, buf, MIN(bufsz, sizeof (up->u_psargs))); + buf[bufsz - 1] = '\0'; + *slen = strlen(buf) + 1; + return (0); + } + + VERIFY(up->u_argvstrs != (uintptr_t)NULL); + + mutex_exit(&p->p_lock); + + if (uread(p, &term, sizeof (term), + up->u_argvstrs + up->u_argvstrsize - 1) != 0) { + err = EFAULT; + goto out; + } + + if (term != '\0') { + err = prreadstr(p, up->u_argvstrs, buf, bufsz, slen); + } else { + size_t size = MIN(bufsz, up->u_argvstrsize); + err = prreadbuf(p, up->u_argvstrs, buf, size, slen); + } + +out: + mutex_enter(&p->p_lock); + VERIFY(p->p_proc_flag & P_PR_LOCK); + return (err); +} + + /* * Attempt to read the argument vector (argv) from this process. The caller * must hold the p_lock mutex, and have marked the process P_PR_LOCK (e.g. via @@ -113,8 +202,8 @@ prreadargv(proc_t *p, char *buf, size_t bufsz, size_t *slen) * while we do I/O to avoid deadlock with the clock thread. */ mutex_exit(&p->p_lock); - if ((error = prreadbuf(p, up->u_argv, (uint8_t *)argv, argvsz, - NULL)) != 0) { + if ((error = prreadbuf(p, up->u_argv, (char *)argv, + argvsz, NULL)) != 0) { kmem_free(argv, argvsz); mutex_enter(&p->p_lock); VERIFY(p->p_proc_flag & P_PR_LOCK); @@ -175,7 +264,7 @@ retry: * Read string data for this argument. Leave room * in the buffer for a final NUL terminator. */ - if ((error = prreadbuf(p, arg, (uint8_t *)&buf[pos], trysz, + if ((error = prreadbuf(p, arg, (char *)&buf[pos], trysz, &rdsz)) != 0) { /* * There was a problem reading this string @@ -288,7 +377,7 @@ prreadenvv(proc_t *p, char *buf, size_t bufsz, size_t *slen) for (cnt = 0, tmpp = up->u_envp; cnt < bound; cnt++, tmpp += rdsz) { caddr_t tmp = NULL; - if ((error = prreadbuf(p, tmpp, (uint8_t *)&tmp, rdsz, + if ((error = prreadbuf(p, tmpp, (char *)&tmp, rdsz, NULL)) != 0) { mutex_enter(&p->p_lock); VERIFY(p->p_proc_flag & P_PR_LOCK); @@ -317,7 +406,7 @@ prreadenvv(proc_t *p, char *buf, size_t bufsz, size_t *slen) /* * Extract the env array from the target process. */ - if ((error = prreadbuf(p, up->u_envp, (uint8_t *)envp, envpsz, + if ((error = prreadbuf(p, up->u_envp, (char *)envp, envpsz, NULL)) != 0) { kmem_free(envp, envpsz); mutex_enter(&p->p_lock); @@ -379,7 +468,7 @@ retry: * Read string data for this env var. Leave room * in the buffer for a final NUL terminator. */ - if ((error = prreadbuf(p, ev, (uint8_t *)&buf[pos], trysz, + if ((error = prreadbuf(p, ev, (char *)&buf[pos], trysz, &rdsz)) != 0) { /* * There was a problem reading this string diff --git a/usr/src/uts/common/fs/proc/prdata.h b/usr/src/uts/common/fs/proc/prdata.h index 706e3ad14d..0ed015b9a2 100644 --- a/usr/src/uts/common/fs/proc/prdata.h +++ b/usr/src/uts/common/fs/proc/prdata.h @@ -27,7 +27,7 @@ /* All Rights Reserved */ /* - * Copyright 2018 Joyent, Inc. + * Copyright 2019 Joyent, Inc. */ #ifndef _SYS_PROC_PRDATA_H @@ -124,6 +124,7 @@ typedef enum prnodetype { PR_LDT, /* /proc/<pid>/ldt */ #endif PR_ARGV, /* /proc/<pid>/argv */ + PR_CMDLINE, /* /proc/<pid>/cmdline */ PR_USAGE, /* /proc/<pid>/usage */ PR_LUSAGE, /* /proc/<pid>/lusage */ PR_PAGEDATA, /* /proc/<pid>/pagedata */ @@ -351,6 +352,7 @@ extern void pr_sethold(prnode_t *, sigset_t *); extern void pr_setfault(proc_t *, fltset_t *); extern int prusrio(proc_t *, enum uio_rw, struct uio *, int); extern int prreadargv(proc_t *, char *, size_t, size_t *); +extern int prreadcmdline(proc_t *, char *, size_t, size_t *); extern int prreadenvv(proc_t *, char *, size_t, size_t *); extern int prwritectl(vnode_t *, struct uio *, cred_t *); extern int prlock(prnode_t *, int); diff --git a/usr/src/uts/common/fs/proc/prvnops.c b/usr/src/uts/common/fs/proc/prvnops.c index 657cebf8c2..a9d9fe89ec 100644 --- a/usr/src/uts/common/fs/proc/prvnops.c +++ b/usr/src/uts/common/fs/proc/prvnops.c @@ -21,7 +21,7 @@ /* * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2018, Joyent, Inc. + * Copyright 2019 Joyent, Inc. * Copyright (c) 2017 by Delphix. All rights reserved. */ @@ -98,11 +98,6 @@ struct prdirect { #define PRSDSIZE (sizeof (struct prdirect)) /* - * Maximum length of the /proc/$$/argv file: - */ -int prmaxargvlen = 4096; - -/* * Directory characteristics. */ typedef struct prdirent { @@ -171,12 +166,14 @@ static prdirent_t piddir[] = { "contracts" }, { PR_SECFLAGS, 27 * sizeof (prdirent_t), sizeof (prdirent_t), "secflags" }, + { PR_ARGV, 28 * sizeof (prdirent_t), sizeof (prdirent_t), + "argv" }, + { PR_CMDLINE, 29 * sizeof (prdirent_t), sizeof (prdirent_t), + "cmdline" }, #if defined(__x86) - { PR_LDT, 28 * sizeof (prdirent_t), sizeof (prdirent_t), + { PR_LDT, 30 * sizeof (prdirent_t), sizeof (prdirent_t), "ldt" }, #endif - { PR_ARGV, 28 * sizeof (prdirent_t), sizeof (prdirent_t), - "argv" }, }; #define NPIDDIRFILES (sizeof (piddir) / sizeof (piddir[0]) - 2) @@ -595,7 +592,7 @@ static int pr_read_inval(), pr_read_as(), pr_read_status(), #if defined(__x86) pr_read_ldt(), #endif - pr_read_argv(), + pr_read_argv(), pr_read_cmdline(), pr_read_usage(), pr_read_lusage(), pr_read_pagedata(), pr_read_watch(), pr_read_lwpstatus(), pr_read_lwpsinfo(), pr_read_lwpusage(), pr_read_lwpname(), @@ -626,6 +623,7 @@ static int (*pr_read_function[PR_NFILES])() = { pr_read_ldt, /* /proc/<pid>/ldt */ #endif pr_read_argv, /* /proc/<pid>/argv */ + pr_read_cmdline, /* /proc/<pid>/cmdline */ pr_read_usage, /* /proc/<pid>/usage */ pr_read_lusage, /* /proc/<pid>/lusage */ pr_read_pagedata, /* /proc/<pid>/pagedata */ @@ -690,11 +688,46 @@ pr_uioread(void *base, long count, uio_t *uiop) } static int +pr_read_cmdline(prnode_t *pnp, uio_t *uiop) +{ + char *args; + int error; + size_t asz = PRMAXARGVLEN, sz; + + /* + * Allocate a scratch buffer for collection of the process arguments. + */ + args = kmem_alloc(asz, KM_SLEEP); + + ASSERT(pnp->pr_type == PR_CMDLINE); + + if ((error = prlock(pnp, ZNO)) != 0) { + kmem_free(args, asz); + return (error); + } + + if ((error = prreadcmdline(pnp->pr_common->prc_proc, args, asz, + &sz)) != 0) { + prunlock(pnp); + kmem_free(args, asz); + return (error); + } + + prunlock(pnp); + + error = pr_uioread(args, sz, uiop); + + kmem_free(args, asz); + + return (error); +} + +static int pr_read_argv(prnode_t *pnp, uio_t *uiop) { char *args; int error; - size_t asz = prmaxargvlen, sz; + size_t asz = PRMAXARGVLEN, sz; /* * Allocate a scratch buffer for collection of the process arguments. @@ -1872,6 +1905,7 @@ static int (*pr_read_function_32[PR_NFILES])() = { pr_read_ldt, /* /proc/<pid>/ldt */ #endif pr_read_argv, /* /proc/<pid>/argv */ + pr_read_cmdline, /* /proc/<pid>/cmdline */ pr_read_usage_32, /* /proc/<pid>/usage */ pr_read_lusage_32, /* /proc/<pid>/lusage */ pr_read_pagedata_32, /* /proc/<pid>/pagedata */ @@ -3317,7 +3351,7 @@ prgetattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr, if ((p->p_flag & SSYS) || p->p_as == &kas) { vap->va_size = PSARGSZ; } else { - vap->va_size = prmaxargvlen; + vap->va_size = PRMAXARGVLEN; } break; #if defined(__x86) @@ -3442,6 +3476,7 @@ prgetattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr, #endif case PR_CTL: case PR_LWPCTL: + case PR_CMDLINE: default: vap->va_size = 0; break; @@ -3497,6 +3532,7 @@ praccess(vnode_t *vp, int mode, int flags, cred_t *cr, caller_context_t *ct) case PR_LUSAGE: case PR_LWPUSAGE: case PR_ARGV: + case PR_CMDLINE: p = pr_p_lock(pnp); mutex_exit(&pr_pidlock); if (p == NULL) @@ -3583,6 +3619,7 @@ static vnode_t *(*pr_lookup_function[PR_NFILES])() = { pr_lookup_notdir, /* /proc/<pid>/ldt */ #endif pr_lookup_notdir, /* /proc/<pid>/argv */ + pr_lookup_notdir, /* /proc/<pid>/cmdline */ pr_lookup_notdir, /* /proc/<pid>/usage */ pr_lookup_notdir, /* /proc/<pid>/lusage */ pr_lookup_notdir, /* /proc/<pid>/pagedata */ @@ -4871,6 +4908,7 @@ prgetnode(vnode_t *dp, prnodetype_t type) case PR_LUSAGE: case PR_LWPUSAGE: case PR_ARGV: + case PR_CMDLINE: pnp->pr_mode = 0444; /* read-only by all */ break; @@ -4977,6 +5015,7 @@ static int (*pr_readdir_function[PR_NFILES])() = { pr_readdir_notdir, /* /proc/<pid>/ldt */ #endif pr_readdir_notdir, /* /proc/<pid>/argv */ + pr_readdir_notdir, /* /proc/<pid>/cmdline */ pr_readdir_notdir, /* /proc/<pid>/usage */ pr_readdir_notdir, /* /proc/<pid>/lusage */ pr_readdir_notdir, /* /proc/<pid>/pagedata */ @@ -5129,6 +5168,7 @@ pr_readdir_piddir(prnode_t *pnp, uio_t *uiop, int *eofp) case PR_PSINFO: case PR_USAGE: case PR_ARGV: + case PR_CMDLINE: break; default: continue; diff --git a/usr/src/uts/common/os/exec.c b/usr/src/uts/common/os/exec.c index 24b6f0e2eb..62d1e298dd 100644 --- a/usr/src/uts/common/os/exec.c +++ b/usr/src/uts/common/os/exec.c @@ -24,7 +24,7 @@ */ /* Copyright (c) 1988 AT&T */ -/* All Rights Reserved */ +/* All Rights Reserved */ /* * Copyright 2019 Joyent, Inc. */ @@ -1712,7 +1712,9 @@ stk_copyin(execa_t *uap, uarg_t *args, intpdata_t *intp, void **auxvpp) } } argc = (int *)(args->stk_base + args->stk_size) - args->stk_offp; - args->arglen = args->stk_strp - args->stk_base; + args->argstrlen = args->stk_strp - args->stk_base; + + const char *envstr = args->stk_strp; /* * Add environ[] strings to the stack. @@ -1734,6 +1736,8 @@ stk_copyin(execa_t *uap, uarg_t *args, intpdata_t *intp, void **auxvpp) envp += ptrsize; } } + + args->envstrlen = args->stk_strp - envstr; args->na = (int *)(args->stk_base + args->stk_size) - args->stk_offp; args->ne = args->na - argc; @@ -1823,46 +1827,53 @@ stk_copyout(uarg_t *args, char *usrstack, void **auxvpp, user_t *up) */ if (stk_putptr(args, usp, (char *)(uintptr_t)argc)) return (-1); + usp += ptrsize; /* - * Add argc space (ptrsize) to usp and record argv for /proc. + * For the benefit of /proc, record the user address of the argv[] array + * as well as the start of the argv string space (argv[0]). */ - up->u_argv = (uintptr_t)(usp += ptrsize); + up->u_argv = (uintptr_t)usp; + up->u_argvstrs = (uintptr_t)(&ustrp[*(offp - 1)]); + up->u_argvstrsize = args->argstrlen; /* - * Put the argv[] pointers on the stack. + * Put the argv[] pointers on the stack, including a NULL terminator. */ for (i = 0; i < argc; i++, usp += ptrsize) if (stk_putptr(args, usp, &ustrp[*--offp])) return (-1); + usp += ptrsize; /* * Copy arguments to u_psargs. */ - pslen = MIN(args->arglen, PSARGSZ) - 1; + pslen = MIN(args->argstrlen, PSARGSZ) - 1; for (i = 0; i < pslen; i++) up->u_psargs[i] = (kstrp[i] == '\0' ? ' ' : kstrp[i]); while (i < PSARGSZ) up->u_psargs[i++] = '\0'; /* - * Add space for argv[]'s NULL terminator (ptrsize) to usp and - * record envp for /proc. + * For the benefit of /proc, record the user address of the envp[] array + * as well as the start of the envp string space (envp[0]). */ - up->u_envp = (uintptr_t)(usp += ptrsize); + up->u_envp = (uintptr_t)usp; + up->u_envstrs = (uintptr_t)(&ustrp[*(offp - 1)]); + up->u_envstrsize = args->envstrlen; /* - * Put the envp[] pointers on the stack. + * Put the envp[] pointers on the stack, including a NULL terminator. */ for (i = 0; i < envc; i++, usp += ptrsize) if (stk_putptr(args, usp, &ustrp[*--offp])) return (-1); + usp += ptrsize; /* - * Add space for envp[]'s NULL terminator (ptrsize) to usp and - * remember where the stack ends, which is also where auxv begins. + * Remember where the stack ends, which is also where auxv begins. */ - args->stackend = usp += ptrsize; + args->stackend = usp; /* * Put all the argv[], envp[], and auxv strings on the stack. @@ -2149,7 +2160,7 @@ exec_args(execa_t *uap, uarg_t *args, intpdata_t *intp, void **auxvpp) delete_itimer_realprof(); if (AU_AUDITING()) - audit_exec(args->stk_base, args->stk_base + args->arglen, + audit_exec(args->stk_base, args->stk_base + args->argstrlen, args->na - args->ne, args->ne, args->pfcred); /* diff --git a/usr/src/uts/common/os/zone.c b/usr/src/uts/common/os/zone.c index 1db130797c..3d4e7ed7cd 100644 --- a/usr/src/uts/common/os/zone.c +++ b/usr/src/uts/common/os/zone.c @@ -21,7 +21,7 @@ /* * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2019, Joyent, Inc. + * Copyright 2019 Joyent, Inc. * Copyright (c) 2016 by Delphix. All rights reserved. * Copyright 2018 OmniOS Community Edition (OmniOSce) Association. */ @@ -4478,7 +4478,11 @@ zsched(void *arg) bcopy("zsched", PTOU(pp)->u_comm, sizeof ("zsched")); PTOU(pp)->u_argc = 0; PTOU(pp)->u_argv = 0; + PTOU(pp)->u_argvstrs = 0; + PTOU(pp)->u_argvstrsize = 0; PTOU(pp)->u_envp = 0; + PTOU(pp)->u_envstrs = 0; + PTOU(pp)->u_envstrsize = 0; PTOU(pp)->u_commpagep = 0; closeall(P_FINFO(pp)); diff --git a/usr/src/uts/common/sys/exec.h b/usr/src/uts/common/sys/exec.h index 12115b7e27..d66a8dc15d 100644 --- a/usr/src/uts/common/sys/exec.h +++ b/usr/src/uts/common/sys/exec.h @@ -80,7 +80,8 @@ typedef struct uarg { ssize_t na; ssize_t ne; ssize_t nc; - ssize_t arglen; + size_t argstrlen; + size_t envstrlen; char *fname; char *pathname; size_t auxsize; diff --git a/usr/src/uts/common/sys/procfs.h b/usr/src/uts/common/sys/procfs.h index 99da92ab79..b24b2d9da1 100644 --- a/usr/src/uts/common/sys/procfs.h +++ b/usr/src/uts/common/sys/procfs.h @@ -25,7 +25,7 @@ */ /* * Copyright 2012 DEY Storage Systems, Inc. All rights reserved. - * Copyright 2018 Joyent, Inc. + * Copyright 2019 Joyent, Inc. */ #ifndef _SYS_PROCFS_H @@ -271,10 +271,12 @@ typedef struct lwpsinfo { int pr_filler[4]; /* reserved for future use */ } lwpsinfo_t; +#define PRARGSZ 80 /* number of chars of arguments */ +#define PRMAXARGVLEN 4096 /* max len of /proc/%s/argv */ + /* * process ps(1) information file. /proc/<pid>/psinfo */ -#define PRARGSZ 80 /* number of chars of arguments */ typedef struct psinfo { int pr_flag; /* process flags (DEPRECATED; do not use) */ int pr_nlwp; /* number of active lwps in the process */ diff --git a/usr/src/uts/common/sys/user.h b/usr/src/uts/common/sys/user.h index 15b4d0b247..8c424e7bf3 100644 --- a/usr/src/uts/common/sys/user.h +++ b/usr/src/uts/common/sys/user.h @@ -26,7 +26,7 @@ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ /* - * Copyright (c) 2018, Joyent, Inc. + * Copyright 2019 Joyent, Inc. */ @@ -227,7 +227,11 @@ typedef struct user { char u_psargs[PSARGSZ]; /* arguments from exec */ int u_argc; /* value of argc passed to main() */ uintptr_t u_argv; /* value of argv passed to main() */ + uintptr_t u_argvstrs; /* argv string space pointer */ + size_t u_argvstrsize; /* size of argv string space */ uintptr_t u_envp; /* value of envp passed to main() */ + uintptr_t u_envstrs; /* env string space pointer */ + size_t u_envstrsize; /* size of env string space */ uintptr_t u_commpagep; /* address of mapped comm page */ /* |