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; 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 } else if (*obuf != '\0') { 107 /* Idea from NetBSD - reset the title on fmt == NULL */ 108 nargvp = oargv; 109 nargc = oargc; 110 } else 111 /* Nothing to restore */ 112 return (NULL); 113 114 if (ps_strings == NULL) 115 (void)_elf_aux_info(AT_PS_STRINGS, &ps_strings, 116 sizeof(ps_strings)); 117 118 if (ps_strings == NULL) { 119 len = sizeof(ul_ps_strings); 120 if (sysctlbyname("kern.ps_strings", &ul_ps_strings, &len, NULL, 121 0) == -1) 122 return (NULL); 123 ps_strings = (struct ps_strings *)ul_ps_strings; 124 } 125 126 if (ps_strings == NULL) 127 return (NULL); 128 129 /* 130 * PS_STRINGS points to zeroed memory on a style #2 kernel. 131 * Should not happen. 132 */ 133 if (ps_strings->ps_argvstr == NULL) 134 return (NULL); 135 136 /* style #3 */ 137 if (oargc == -1) { 138 /* Record our original args */ 139 oargc = ps_strings->ps_nargvstr; 140 oargv = ps_strings->ps_argvstr; 141 for (i = len = 0; i < oargc; i++) { 142 /* 143 * The program may have scribbled into its 144 * argv array, e.g., to remove some arguments. 145 * If that has happened, break out before 146 * trying to call strlen on a NULL pointer. 147 */ 148 if (oargv[i] == NULL) { 149 oargc = i; 150 break; 151 } 152 snprintf(obuf + len, SPT_BUFSIZE - len, "%s%s", 153 len != 0 ? " " : "", oargv[i]); 154 if (len != 0) 155 len++; 156 len += strlen(oargv[i]); 157 if (len >= SPT_BUFSIZE) 158 break; 159 } 160 } 161 ps_strings->ps_nargvstr = nargc; 162 ps_strings->ps_argvstr = nargvp; 163 164 return (nargvp[0]); 165 } 166 167 static int fast_update = 0; 168 169 void 170 setproctitle_fast(const char *fmt, ...) 171 { 172 va_list ap; 173 char *buf; 174 int oid[4]; 175 176 va_start(ap, fmt); 177 buf = setproctitle_internal(fmt, ap); 178 va_end(ap); 179 180 if (buf && !fast_update) { 181 /* Tell the kernel to start looking in user-space */ 182 oid[0] = CTL_KERN; 183 oid[1] = KERN_PROC; 184 oid[2] = KERN_PROC_ARGS; 185 oid[3] = -1; 186 sysctl(oid, 4, 0, 0, "", 0); 187 fast_update = 1; 188 } 189 } 190 191 void 192 setproctitle(const char *fmt, ...) 193 { 194 va_list ap; 195 char *buf; 196 int oid[4]; 197 198 va_start(ap, fmt); 199 buf = setproctitle_internal(fmt, ap); 200 va_end(ap); 201 202 if (buf != NULL) { 203 /* Set the title into the kernel cached command line */ 204 oid[0] = CTL_KERN; 205 oid[1] = KERN_PROC; 206 oid[2] = KERN_PROC_ARGS; 207 oid[3] = -1; 208 sysctl(oid, 4, 0, 0, buf, strlen(buf) + 1); 209 fast_update = 0; 210 } 211 } 212