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 void 59 setproctitle(const char *fmt, ...) 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 va_list ap; 71 size_t len; 72 unsigned long ul_ps_strings; 73 int oid[4]; 74 75 if (buf == NULL) { 76 buf = malloc(SPT_BUFSIZE); 77 if (buf == NULL) 78 return; 79 nargv[0] = buf; 80 } 81 82 if (obuf == NULL ) { 83 obuf = malloc(SPT_BUFSIZE); 84 if (obuf == NULL) 85 return; 86 *obuf = '\0'; 87 } 88 89 va_start(ap, fmt); 90 91 if (fmt) { 92 buf[SPT_BUFSIZE - 1] = '\0'; 93 94 if (fmt[0] == '-') { 95 /* skip program name prefix */ 96 fmt++; 97 len = 0; 98 } else { 99 /* print program name heading for grep */ 100 (void)snprintf(buf, SPT_BUFSIZE, "%s: ", _getprogname()); 101 len = strlen(buf); 102 } 103 104 /* print the argument string */ 105 (void) vsnprintf(buf + len, SPT_BUFSIZE - len, fmt, ap); 106 107 nargvp = nargv; 108 nargc = 1; 109 kbuf = buf; 110 } else if (*obuf != '\0') { 111 /* Idea from NetBSD - reset the title on fmt == NULL */ 112 nargvp = oargv; 113 nargc = oargc; 114 kbuf = obuf; 115 } else 116 /* Nothing to restore */ 117 return; 118 119 va_end(ap); 120 121 /* Set the title into the kernel cached command line */ 122 oid[0] = CTL_KERN; 123 oid[1] = KERN_PROC; 124 oid[2] = KERN_PROC_ARGS; 125 oid[3] = getpid(); 126 sysctl(oid, 4, 0, 0, kbuf, strlen(kbuf) + 1); 127 128 if (ps_strings == NULL) { 129 len = sizeof(ul_ps_strings); 130 if (sysctlbyname("kern.ps_strings", &ul_ps_strings, &len, NULL, 131 0) == -1) 132 return; 133 ps_strings = (struct ps_strings *)ul_ps_strings; 134 } 135 136 /* 137 * PS_STRINGS points to zeroed memory on a style #2 kernel. 138 * Should not happen. 139 */ 140 if (ps_strings->ps_argvstr == NULL) 141 return; 142 143 /* style #3 */ 144 if (oargc == -1) { 145 /* Record our original args */ 146 oargc = ps_strings->ps_nargvstr; 147 oargv = ps_strings->ps_argvstr; 148 for (i = len = 0; i < oargc; i++) { 149 /* 150 * The program may have scribbled into its 151 * argv array, e.g., to remove some arguments. 152 * If that has happened, break out before 153 * trying to call strlen on a NULL pointer. 154 */ 155 if (oargv[i] == NULL) { 156 oargc = i; 157 break; 158 } 159 snprintf(obuf + len, SPT_BUFSIZE - len, "%s%s", 160 len != 0 ? " " : "", oargv[i]); 161 if (len != 0) 162 len++; 163 len += strlen(oargv[i]); 164 if (len >= SPT_BUFSIZE) 165 break; 166 } 167 } 168 ps_strings->ps_nargvstr = nargc; 169 ps_strings->ps_argvstr = nargvp; 170 } 171