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