1 /* 2 * Copyright (c) 1995 Peter Wemm <peter@freebsd.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, is permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice immediately at the beginning of the file, without modification, 10 * this list of conditions, and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. Absolutely no warranty of function or purpose is made by the author 15 * Peter Wemm. 16 */ 17 18 #include <sys/cdefs.h> 19 __FBSDID("$FreeBSD$"); 20 21 #include "namespace.h" 22 #include <sys/param.h> 23 #include <sys/exec.h> 24 #include <sys/sysctl.h> 25 26 #include <stdio.h> 27 #include <string.h> 28 #include <stdlib.h> 29 #include <unistd.h> 30 #include "un-namespace.h" 31 32 #include "libc_private.h" 33 34 /* 35 * Older FreeBSD 2.0, 2.1 and 2.2 had different ps_strings structures and 36 * in different locations. 37 * 1: old_ps_strings at the very top of the stack. 38 * 2: old_ps_strings at SPARE_USRSPACE below the top of the stack. 39 * 3: ps_strings at the very top of the stack. 40 * We only support a kernel providing #3 style ps_strings. 41 * 42 * For historical purposes, a definition of the old ps_strings structure 43 * and location is preserved below: 44 struct old_ps_strings { 45 char *old_ps_argvstr; 46 int old_ps_nargvstr; 47 char *old_ps_envstr; 48 int old_ps_nenvstr; 49 }; 50 #define OLD_PS_STRINGS ((struct old_ps_strings *) \ 51 (USRSTACK - SPARE_USRSPACE - sizeof(struct old_ps_strings))) 52 */ 53 54 #include <stdarg.h> 55 56 #define SPT_BUFSIZE 2048 /* from other parts of sendmail */ 57 58 static char * 59 setproctitle_internal(const char *fmt, va_list ap) 60 { 61 static struct ps_strings *ps_strings; 62 static char *buf = NULL; 63 static char *obuf = NULL; 64 static char **oargv, *kbuf; 65 static int oargc = -1; 66 static char *nargv[2] = { NULL, NULL }; 67 char **nargvp; 68 int nargc; 69 int i; 70 size_t len; 71 unsigned long ul_ps_strings; 72 73 if (buf == NULL) { 74 buf = malloc(SPT_BUFSIZE); 75 if (buf == NULL) 76 return (NULL); 77 nargv[0] = buf; 78 } 79 80 if (obuf == NULL ) { 81 obuf = malloc(SPT_BUFSIZE); 82 if (obuf == NULL) 83 return (NULL); 84 *obuf = '\0'; 85 } 86 87 if (fmt) { 88 buf[SPT_BUFSIZE - 1] = '\0'; 89 90 if (fmt[0] == '-') { 91 /* skip program name prefix */ 92 fmt++; 93 len = 0; 94 } else { 95 /* print program name heading for grep */ 96 (void)snprintf(buf, SPT_BUFSIZE, "%s: ", _getprogname()); 97 len = strlen(buf); 98 } 99 100 /* print the argument string */ 101 (void)vsnprintf(buf + len, SPT_BUFSIZE - len, fmt, ap); 102 103 nargvp = nargv; 104 nargc = 1; 105 kbuf = buf; 106 } else if (*obuf != '\0') { 107 /* Idea from NetBSD - reset the title on fmt == NULL */ 108 nargvp = oargv; 109 nargc = oargc; 110 kbuf = obuf; 111 } else 112 /* Nothing to restore */ 113 return (NULL); 114 115 if (ps_strings == NULL) { 116 len = sizeof(ul_ps_strings); 117 if (sysctlbyname("kern.ps_strings", &ul_ps_strings, &len, NULL, 118 0) == -1) 119 return (NULL); 120 ps_strings = (struct ps_strings *)ul_ps_strings; 121 } 122 123 /* 124 * PS_STRINGS points to zeroed memory on a style #2 kernel. 125 * Should not happen. 126 */ 127 if (ps_strings->ps_argvstr == NULL) 128 return (NULL); 129 130 /* style #3 */ 131 if (oargc == -1) { 132 /* Record our original args */ 133 oargc = ps_strings->ps_nargvstr; 134 oargv = ps_strings->ps_argvstr; 135 for (i = len = 0; i < oargc; i++) { 136 /* 137 * The program may have scribbled into its 138 * argv array, e.g., to remove some arguments. 139 * If that has happened, break out before 140 * trying to call strlen on a NULL pointer. 141 */ 142 if (oargv[i] == NULL) { 143 oargc = i; 144 break; 145 } 146 snprintf(obuf + len, SPT_BUFSIZE - len, "%s%s", 147 len != 0 ? " " : "", oargv[i]); 148 if (len != 0) 149 len++; 150 len += strlen(oargv[i]); 151 if (len >= SPT_BUFSIZE) 152 break; 153 } 154 } 155 ps_strings->ps_nargvstr = nargc; 156 ps_strings->ps_argvstr = nargvp; 157 158 return (nargvp[0]); 159 } 160 161 static int fast_update = 0; 162 163 void 164 setproctitle_fast(const char *fmt, ...) 165 { 166 va_list ap; 167 char *buf; 168 int oid[4]; 169 170 va_start(ap, fmt); 171 buf = setproctitle_internal(fmt, ap); 172 va_end(ap); 173 174 if (buf && !fast_update) { 175 /* Tell the kernel to start looking in user-space */ 176 oid[0] = CTL_KERN; 177 oid[1] = KERN_PROC; 178 oid[2] = KERN_PROC_ARGS; 179 oid[3] = getpid(); 180 sysctl(oid, 4, 0, 0, "", 0); 181 fast_update = 1; 182 } 183 } 184 185 void 186 setproctitle(const char *fmt, ...) 187 { 188 va_list ap; 189 char *buf; 190 int oid[4]; 191 192 va_start(ap, fmt); 193 buf = setproctitle_internal(fmt, ap); 194 va_end(ap); 195 196 if (buf != NULL) { 197 /* Set the title into the kernel cached command line */ 198 oid[0] = CTL_KERN; 199 oid[1] = KERN_PROC; 200 oid[2] = KERN_PROC_ARGS; 201 oid[3] = getpid(); 202 sysctl(oid, 4, 0, 0, buf, strlen(buf) + 1); 203 fast_update = 0; 204 } 205 } 206