]> FriiDump Source - friidump.git/blob - libfriidump/misc.c
FriiDump 0.5.3.16 candidate: add native reports and Linux Xbox support
[friidump.git] / libfriidump / misc.c
1 /***************************************************************************
2  *   Copyright (C) 2007 by Arep                                            *
3  *   Support is provided through the forums at                             *
4  *   http://wii.console-tribe.com                                          *
5  *                                                                         *
6  *   This program is free software; you can redistribute it and/or modify  *
7  *   it under the terms of the GNU General Public License as published by  *
8  *   the Free Software Foundation; either version 2 of the License, or     *
9  *   (at your option) any later version.                                   *
10  *                                                                         *
11  *   This program is distributed in the hope that it will be useful,       *
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
14  *   GNU General Public License for more details.                          *
15  *                                                                         *
16  *   You should have received a copy of the GNU General Public License     *
17  *   along with this program; if not, write to the                         *
18  *   Free Software Foundation, Inc.,                                       *
19  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
20  ***************************************************************************/
21
22 #include "misc.h"
23 #include "xbox_ref/xbox_ref_log.h"
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <ctype.h>
29 #include <sys/types.h>
30 #ifndef WIN32
31 #include <sys/time.h>
32 #endif
33 #include <time.h>
34
35 /*** LOGGING STUFF ***/
36 /* Uses code from the printf man page */
37 static int my_vasprintf (char **dst, const char *fmt, va_list ap) {
38     char *p;
39     int n, size;
40     bool done;
41     va_list ap2;
42
43     /* Guess we need no more than 100 bytes. */
44     size = 100;
45     if ((p = (char *) malloc (size)) != NULL) {
46         do {
47             done = false;
48             va_copy (ap2, ap);
49             n = vsnprintf (p, size, fmt, ap2);
50             va_end (ap2);
51
52             /* If that worked, return the string. */
53             if (n > -1 && n < size)
54                 done = true;
55             else {
56                 /* Else try again with more space. */
57                 if (n > -1)        /* glibc 2.1 */
58                     size = n + 1; /* precisely what is needed */
59                 else    /* glibc 2.0 */
60                     size *= 2;  /* twice the old size */
61
62                 if ((p = (char *) realloc (p, size)) == NULL)
63                     done = true;
64             }
65         } while (!done);
66     }
67
68     /* Return -1 if memory allocation failed */
69     if (!(*dst = p))
70         n = -1;
71
72     return (n);
73 }
74
75
76 /* Appends a print-like string to the log file, with respect to the verbosity setting */
77 void _logprintf (int level, char tag[], char format[], ...) {
78     static bool last_nocr = false;
79     char *buffer, t[50];
80     va_list ap;
81         struct timeval now;
82         time_t nowtt;
83     struct tm nowtm;
84
85     va_start (ap, format);
86     my_vasprintf (&buffer, format, ap);
87     va_end (ap);
88
89     /* Start of line, including time and tag */
90     if (!last_nocr) {
91                 gettimeofday (&now, NULL);
92                 nowtt = (time_t) now.tv_sec;
93                 if (localtime_r (&nowtt, &nowtm))
94                 strftime (t, 50, "%H:%M:%S", &nowtm);
95         if (tag)
96             xbox_ref_log_fprintf (stderr, "[%s/%s] ", t, tag);
97         else
98             xbox_ref_log_fprintf (stderr, "[%s] ", t);
99
100         /* Debug level tag */
101         if (level & LOG_WARNING)
102             xbox_ref_log_fprintf (stderr, "WARNING: ");
103         else if (level & LOG_ERROR)
104             xbox_ref_log_fprintf (stderr, "ERROR: ");
105         #ifdef DEBUG
106         else if (level & LOG_DEBUG)
107             xbox_ref_log_fprintf (stderr, "DEBUG: ");
108         #endif
109     }
110
111     /* Actual message */
112     xbox_ref_log_fprintf (stderr, "%s%s", buffer, level & LOG_NOCR ? "" : "\n");
113     free (buffer);
114
115     if (level & LOG_NOCR)
116         last_nocr = true;
117     else
118         last_nocr = false;
119
120     return;
121 }
122 /******/
123
124
125 /***************** TAKEN FROM TCPDUMP ****************/
126
127 #define ASCII_LINELENGTH 300
128 #define HEXDUMP_BYTES_PER_LINE 16
129 #define HEXDUMP_SHORTS_PER_LINE (HEXDUMP_BYTES_PER_LINE / 2)
130 #define HEXDUMP_HEXSTUFF_PER_SHORT 5 /* 4 hex digits and a space */
131 #define HEXDUMP_HEXSTUFF_PER_LINE (HEXDUMP_HEXSTUFF_PER_SHORT * HEXDUMP_SHORTS_PER_LINE)
132
133 void hex_and_ascii_print_with_offset (const char *ident, register const u_int8_t *cp,
134                                       register u_int16_t length, register u_int16_t oset) {
135     register u_int16_t i;
136     register int s1, s2;
137     register int nshorts;
138     char hexstuff[HEXDUMP_SHORTS_PER_LINE*HEXDUMP_HEXSTUFF_PER_SHORT+1], *hsp;
139     char asciistuff[ASCII_LINELENGTH+1], *asp;
140
141     nshorts = length / sizeof(unsigned short);
142     i = 0;
143     hsp = hexstuff;
144     asp = asciistuff;
145     while (--nshorts >= 0) {
146         s1 = *cp++;
147         s2 = *cp++;
148         (void)snprintf(hsp, sizeof(hexstuff) - (hsp - hexstuff),
149                        " %02x%02x", s1, s2);
150         hsp += HEXDUMP_HEXSTUFF_PER_SHORT;
151         *(asp++) = (isgraph(s1) ? s1 : '.');
152         *(asp++) = (isgraph(s2) ? s2 : '.');
153         i++;
154         if (i >= HEXDUMP_SHORTS_PER_LINE) {
155             *hsp = *asp = '\0';
156             (void)printf("%s0x%04x: %-*s  %s",
157                          ident, oset, HEXDUMP_HEXSTUFF_PER_LINE,
158                          hexstuff, asciistuff);
159             i = 0;
160             hsp = hexstuff;
161             asp = asciistuff;
162             oset += HEXDUMP_BYTES_PER_LINE;
163         }
164     }
165     if (length & 1) {
166         s1 = *cp++;
167         (void)snprintf(hsp, sizeof(hexstuff) - (hsp - hexstuff),
168                        " %02x", s1);
169         hsp += 3;
170         *(asp++) = (isgraph(s1) ? s1 : '.');
171         ++i;
172     }
173     if (i > 0) {
174         *hsp = *asp = '\0';
175         debug ("%s0x%04x: %-*s  %s",
176                ident, oset, HEXDUMP_HEXSTUFF_PER_LINE,
177                hexstuff, asciistuff);
178     }
179
180     debug ("\n");               // Final spacing
181 }
182
183 char *strtrimr (char *s) {
184     int i;
185
186     for (i = strlen (s) - 1; i >= 0 && isspace (s[i]); i--)
187         s[i] = '\0';
188
189     return (s);
190 }
191
192
193 /*** The following was taken from the Python sources */
194 #if !defined(HAVE_LARGEFILE_SUPPORT)
195 #error "Large file support must be enabled for this program"
196 #else
197
198 /* A portable fseek() function
199    return 0 on success, non-zero on failure (with errno set) */
200 int my_fseek (FILE *fp, my_off_t offset, int whence) {
201     #if defined(_MSC_VER) || defined(WIN32)
202     return _fseeki64(fp, (__int64) offset, whence);
203     #elif defined(HAVE_FSEEKO) && SIZEOF_OFF_T >= 8
204     return fseeko(fp, offset, whence);
205     #elif defined(HAVE_FSEEK64)
206     return fseek64(fp, offset, whence);
207     #elif defined(__BEOS__)
208     return _fseek(fp, offset, whence);
209     #elif SIZEOF_FPOS_T >= 8
210     /* lacking a 64-bit capable fseek(), use a 64-bit capable fsetpos()
211        and fgetpos() to implement fseek()*/
212     fpos_t pos;
213
214     switch (whence) {
215     case SEEK_END:
216         #ifdef MS_WINDOWS
217         fflush (fp);
218         if (_lseeki64 (fileno(fp), 0, 2) == -1)
219             return -1;
220         #else
221         if (fseek (fp, 0, SEEK_END) != 0)
222             return -1;
223         #endif
224         // fall through
225     case SEEK_CUR:
226         if (fgetpos (fp, &pos) != 0)
227             return -1;
228         offset += pos;
229         break;
230         // case SEEK_SET: break;
231     }
232     return fsetpos(fp, &offset);
233     #else
234     #error "Large file support, but no way to fseek."
235     #endif
236 }
237
238
239 /* A portable ftell() function
240    Return -1 on failure with errno set appropriately, current file
241    position on success */
242 my_off_t my_ftell (FILE* fp) {
243     #if defined(_MSC_VER) || defined(WIN32)
244     return _ftelli64 (fp);
245     #elif defined(HAVE_FTELLO) && SIZEOF_OFF_T >= 8
246     return ftello (fp);
247     #elif defined(HAVE_FTELL64)
248     return ftell64 (fp);
249     #elif SIZEOF_FPOS_T >= 8
250     fpos_t pos;
251
252     if (fgetpos (fp, &pos) != 0)
253         return -1;
254
255     return pos;
256     #else
257     #error "Large file support, but no way to ftell."
258     #endif
259 }
260
261 #endif
262
263
264
265 /*** STUFF FOR DROPPING PRIVILEGES ***/
266
267 /* WARNING: I'm not sure at all that the privileges-dropping system I have implemented is secure, so don't rely too much on it. */
268
269 #ifndef WIN32
270 #include <unistd.h>
271 #endif
272
273 /**
274  * Drops privileges to those of the real user (i. e. set euid to ruid).
275  */
276 void drop_euid () {
277 #ifndef WIN32
278         uid_t uid, euid;
279
280         uid = getuid ();
281         euid = geteuid ();
282         if (uid != 0 && uid != euid) {
283 #if 1
284                 seteuid (uid);
285 #else
286                 if (seteuid (uid) != 0)
287                         debug ("seteuid() to uid %d failed", uid);
288                 else
289                         debug ("Changed euid from %d to %d", euid, uid);
290 #endif
291         }
292 #endif
293
294         return;
295 }
296
297
298 /**
299  * Upgrades priviles to those of root (i. e. set euid to 0).
300  */
301 void upgrade_euid () {
302 #ifndef WIN32
303         if (getuid () != 0) {
304 #if 1
305                 seteuid (0);
306 #else
307                 if (seteuid (0) != 0)
308                         debug ("seteuid() to root failed");
309                 else
310                         debug ("Changed euid to root");
311 #endif
312         }
313 #endif
314
315        return;
316 }