setproctitle.c revision 93399
1150850Sscottl/*
2150850Sscottl * Copyright (c) 1995 Peter Wemm <peter@freebsd.org>
3150850Sscottl * All rights reserved.
4150850Sscottl *
5150850Sscottl * Redistribution and use in source and binary forms, with or without
6150850Sscottl * modification, is permitted provided that the following conditions
7150850Sscottl * are met:
8150850Sscottl * 1. Redistributions of source code must retain the above copyright
9150850Sscottl *    notice immediately at the beginning of the file, without modification,
10150850Sscottl *    this list of conditions, and the following disclaimer.
11150850Sscottl * 2. Redistributions in binary form must reproduce the above copyright
12150850Sscottl *    notice, this list of conditions and the following disclaimer in the
13150850Sscottl *    documentation and/or other materials provided with the distribution.
14150850Sscottl * 3. Absolutely no warranty of function or purpose is made by the author
15150850Sscottl *    Peter Wemm.
16150850Sscottl */
17150850Sscottl
18150850Sscottl#include <sys/cdefs.h>
19150850Sscottl__FBSDID("$FreeBSD: head/lib/libc/gen/setproctitle.c 93399 2002-03-29 22:43:43Z markm $");
20150850Sscottl
21150850Sscottl#include "namespace.h"
22150850Sscottl#include <sys/types.h>
23150850Sscottl#include <sys/param.h>
24150850Sscottl#include <sys/exec.h>
25150850Sscottl#include <sys/sysctl.h>
26150850Sscottl
27150850Sscottl#include <vm/vm.h>
28150850Sscottl#include <vm/vm_param.h>
29150850Sscottl#include <vm/pmap.h>
30150850Sscottl
31150850Sscottl#include <stdio.h>
32150850Sscottl#include <string.h>
33150850Sscottl#include <stdlib.h>
34150850Sscottl#include <unistd.h>
35150850Sscottl#include "un-namespace.h"
36150850Sscottl
37150850Sscottl#include "libc_private.h"
38150850Sscottl
39150850Sscottl/*
40150850Sscottl * Older FreeBSD 2.0, 2.1 and 2.2 had different ps_strings structures and
41150850Sscottl * in different locations.
42150850Sscottl * 1: old_ps_strings at the very top of the stack.
43150850Sscottl * 2: old_ps_strings at SPARE_USRSPACE below the top of the stack.
44150850Sscottl * 3: ps_strings at the very top of the stack.
45150850Sscottl * This attempts to support a kernel built in the #2 and #3 era.
46150850Sscottl */
47150850Sscottl
48150850Sscottlstruct old_ps_strings {
49150850Sscottl	char	*old_ps_argvstr;
50150850Sscottl	int	old_ps_nargvstr;
51150850Sscottl	char	*old_ps_envstr;
52150850Sscottl	int	old_ps_nenvstr;
53150850Sscottl};
54150850Sscottl#define	OLD_PS_STRINGS ((struct old_ps_strings *) \
55150850Sscottl	(USRSTACK - SPARE_USRSPACE - sizeof(struct old_ps_strings)))
56150850Sscottl
57150850Sscottl#include <stdarg.h>
58150850Sscottl
59150850Sscottl#define SPT_BUFSIZE 2048	/* from other parts of sendmail */
60150850Sscottl
61150850Sscottlvoid
62150850Sscottlsetproctitle(const char *fmt, ...)
63150850Sscottl{
64150850Sscottl	static struct ps_strings *ps_strings;
65150850Sscottl	static char buf[SPT_BUFSIZE];
66150850Sscottl	static char obuf[SPT_BUFSIZE];
67150850Sscottl	static char **oargv, *kbuf;
68216600Suqs	static int oargc = -1;
69216600Suqs	static char *nargv[2] = { buf, NULL };
70216600Suqs	char **nargvp;
71216600Suqs	int nargc;
72216600Suqs	int i;
73216600Suqs	va_list ap;
74150850Sscottl	size_t len;
75150850Sscottl	unsigned long ul_ps_strings;
76188826Simp	int oid[4];
77188826Simp
78216600Suqs	va_start(ap, fmt);
79150850Sscottl
80150850Sscottl	if (fmt) {
81150850Sscottl		buf[sizeof(buf) - 1] = '\0';
82150850Sscottl
83150850Sscottl		if (fmt[0] == '-') {
84150850Sscottl			/* skip program name prefix */
85150850Sscottl			fmt++;
86150850Sscottl			len = 0;
87150850Sscottl		} else {
88150850Sscottl			/* print program name heading for grep */
89150850Sscottl			(void)snprintf(buf, sizeof(buf), "%s: ", _getprogname());
90150850Sscottl			len = strlen(buf);
91150850Sscottl		}
92150850Sscottl
93150850Sscottl		/* print the argument string */
94150850Sscottl		(void) vsnprintf(buf + len, sizeof(buf) - len, fmt, ap);
95150850Sscottl
96150850Sscottl		nargvp = nargv;
97150850Sscottl		nargc = 1;
98150850Sscottl		kbuf = buf;
99216600Suqs	} else if (*obuf != '\0') {
100216600Suqs  		/* Idea from NetBSD - reset the title on fmt == NULL */
101216600Suqs		nargvp = oargv;
102216600Suqs		nargc = oargc;
103216600Suqs		kbuf = obuf;
104216600Suqs	} else
105216600Suqs		/* Nothing to restore */
106150850Sscottl		return;
107150850Sscottl
108150850Sscottl	va_end(ap);
109150850Sscottl
110150850Sscottl	/* Set the title into the kernel cached command line */
111150850Sscottl	oid[0] = CTL_KERN;
112150850Sscottl	oid[1] = KERN_PROC;
113150850Sscottl	oid[2] = KERN_PROC_ARGS;
114150850Sscottl	oid[3] = getpid();
115150850Sscottl	sysctl(oid, 4, 0, 0, kbuf, strlen(kbuf) + 1);
116150850Sscottl
117150850Sscottl	if (ps_strings == NULL) {
118150850Sscottl		len = sizeof(ul_ps_strings);
119150850Sscottl		if (sysctlbyname("kern.ps_strings", &ul_ps_strings, &len, NULL,
120150850Sscottl		    0) == -1)
121150850Sscottl			ul_ps_strings = PS_STRINGS;
122150850Sscottl		ps_strings = (struct ps_strings *)ul_ps_strings;
123150850Sscottl	}
124150850Sscottl
125150850Sscottl	/* PS_STRINGS points to zeroed memory on a style #2 kernel */
126150850Sscottl	if (ps_strings->ps_argvstr) {
127150850Sscottl		/* style #3 */
128150850Sscottl		if (oargc == -1) {
129150850Sscottl			/* Record our original args */
130150850Sscottl			oargc = ps_strings->ps_nargvstr;
131150850Sscottl			oargv = ps_strings->ps_argvstr;
132150850Sscottl			for (i = len = 0; i < oargc; i++) {
133150850Sscottl				/*
134150850Sscottl				 * The program may have scribbled into its
135150850Sscottl				 * argv array, e.g., to remove some arguments.
136150850Sscottl				 * If that has happened, break out before
137150850Sscottl				 * trying to call strlen on a NULL pointer.
138150850Sscottl				 */
139150850Sscottl				if (oargv[i] == NULL) {
140150850Sscottl					oargc = i;
141150850Sscottl					break;
142150850Sscottl				}
143150850Sscottl				snprintf(obuf + len, sizeof(obuf) - len, "%s%s",
144150850Sscottl				    len ? " " : "", oargv[i]);
145150850Sscottl				if (len)
146150850Sscottl					len++;
147150850Sscottl				len += strlen(oargv[i]);
148150850Sscottl				if (len >= sizeof(obuf))
149150850Sscottl					break;
150150850Sscottl			}
151150850Sscottl		}
152150850Sscottl		ps_strings->ps_nargvstr = nargc;
153150850Sscottl		ps_strings->ps_argvstr = nargvp;
154150850Sscottl	} else {
155150850Sscottl		/* style #2 - we can only restore our first arg :-( */
156216600Suqs		if (*obuf == '\0')
157150850Sscottl			strncpy(obuf, OLD_PS_STRINGS->old_ps_argvstr,
158150850Sscottl			    sizeof(obuf) - 1);
159150850Sscottl		OLD_PS_STRINGS->old_ps_nargvstr = 1;
160150850Sscottl		OLD_PS_STRINGS->old_ps_argvstr = nargvp[0];
161150850Sscottl	}
162150850Sscottl}
163150850Sscottl