Fossil SCM

fossil-scm / src / util.c
Blame History Raw 1051 lines
1
/*
2
** Copyright (c) 2006 D. Richard Hipp
3
**
4
** This program is free software; you can redistribute it and/or
5
** modify it under the terms of the Simplified BSD License (also
6
** known as the "2-Clause License" or "FreeBSD License".)
7
8
** This program is distributed in the hope that it will be useful,
9
** but without any warranty; without even the implied warranty of
10
** merchantability or fitness for a particular purpose.
11
**
12
** Author contact information:
13
** [email protected]
14
** http://www.hwaci.com/drh/
15
**
16
*******************************************************************************
17
**
18
** This file contains code for miscellaneous utility routines.
19
*/
20
#include "config.h"
21
#include "util.h"
22
#if defined(USE_MMAN_H)
23
# include <sys/mman.h>
24
# include <unistd.h>
25
#endif
26
#include <math.h>
27
28
/*
29
** For the fossil_timer_xxx() family of functions...
30
*/
31
#ifdef _WIN32
32
# include <windows.h>
33
# include <io.h>
34
#else
35
# include <sys/time.h>
36
# include <sys/resource.h>
37
# include <sys/types.h>
38
# include <sys/stat.h>
39
# include <unistd.h>
40
# include <fcntl.h>
41
# include <errno.h>
42
#endif
43
44
/*
45
** Returns the same as the platform's isatty() or _isatty() function.
46
*/
47
int fossil_isatty(int fd){
48
#ifdef _WIN32
49
return _isatty(fd);
50
#else
51
return isatty(fd);
52
#endif
53
}
54
55
/*
56
** Returns the same as the platform's fileno() or _fileno() function.
57
*/
58
int fossil_fileno(FILE *p){
59
#ifdef _WIN32
60
return _fileno(p);
61
#else
62
return fileno(p);
63
#endif
64
}
65
66
/*
67
** Exit. Take care to close the database first.
68
*/
69
NORETURN void fossil_exit(int rc){
70
db_close(1);
71
#ifndef _WIN32
72
if( g.fAnyTrace ){
73
fprintf(stderr, "/***** Subprocess %d exit(%d) *****/\n", getpid(), rc);
74
fflush(stderr);
75
}
76
#endif
77
exit(rc);
78
}
79
80
/*
81
** Malloc and free routines that cannot fail
82
*/
83
void *fossil_malloc(size_t n){
84
void *p = malloc(n==0 ? 1 : n);
85
if( p==0 ) fossil_fatal("out of memory");
86
return p;
87
}
88
void *fossil_malloc_zero(size_t n){
89
void *p = malloc(n==0 ? 1 : n);
90
if( p==0 ) fossil_fatal("out of memory");
91
memset(p, 0, n);
92
return p;
93
}
94
void fossil_free(void *p){
95
free(p);
96
}
97
void *fossil_realloc(void *p, size_t n){
98
p = realloc(p, n);
99
if( p==0 ) fossil_fatal("out of memory");
100
return p;
101
}
102
void fossil_secure_zero(void *p, size_t n){
103
volatile unsigned char *vp = (volatile unsigned char *)p;
104
size_t i;
105
106
if( p==0 ) return;
107
assert( n>0 );
108
if( n==0 ) return;
109
for(i=0; i<n; i++){ vp[i] ^= 0xFF; }
110
for(i=0; i<n; i++){ vp[i] ^= vp[i]; }
111
}
112
void fossil_get_page_size(size_t *piPageSize){
113
#if defined(_WIN32)
114
SYSTEM_INFO sysInfo;
115
memset(&sysInfo, 0, sizeof(SYSTEM_INFO));
116
GetSystemInfo(&sysInfo);
117
*piPageSize = (size_t)sysInfo.dwPageSize;
118
#elif defined(USE_MMAN_H)
119
*piPageSize = (size_t)sysconf(_SC_PAGE_SIZE);
120
#else
121
*piPageSize = 4096; /* FIXME: What for POSIX? */
122
#endif
123
}
124
void *fossil_secure_alloc_page(size_t *pN){
125
void *p;
126
size_t pageSize = 0;
127
128
fossil_get_page_size(&pageSize);
129
assert( pageSize>0 );
130
assert( pageSize%2==0 );
131
#if defined(_WIN32)
132
p = VirtualAlloc(NULL, pageSize, MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE);
133
if( p==NULL ){
134
fossil_fatal("VirtualAlloc failed: %lu\n", GetLastError());
135
}
136
if( !VirtualLock(p, pageSize) ){
137
fossil_fatal("VirtualLock failed: %lu\n", GetLastError());
138
}
139
#elif defined(USE_MMAN_H)
140
p = mmap(0, pageSize, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
141
if( p==MAP_FAILED ){
142
fossil_fatal("mmap failed: %d\n", errno);
143
}
144
if( mlock(p, pageSize) ){
145
fossil_fatal("mlock failed: %d\n", errno);
146
}
147
#else
148
p = fossil_malloc(pageSize);
149
#endif
150
fossil_secure_zero(p, pageSize);
151
if( pN ) *pN = pageSize;
152
return p;
153
}
154
void fossil_secure_free_page(void *p, size_t n){
155
if( !p ) return;
156
assert( n>0 );
157
fossil_secure_zero(p, n);
158
#if defined(_WIN32)
159
if( !VirtualUnlock(p, n) ){
160
fossil_panic("VirtualUnlock failed: %lu\n", GetLastError());
161
}
162
if( !VirtualFree(p, 0, MEM_RELEASE) ){
163
fossil_panic("VirtualFree failed: %lu\n", GetLastError());
164
}
165
#elif defined(USE_MMAN_H)
166
if( munlock(p, n) ){
167
fossil_panic("munlock failed: %d\n", errno);
168
}
169
if( munmap(p, n) ){
170
fossil_panic("munmap failed: %d\n", errno);
171
}
172
#else
173
fossil_free(p);
174
#endif
175
}
176
177
/*
178
** Duplicate a string.
179
*/
180
char *fossil_strndup(const char *zOrig, ssize_t len){
181
char *z = 0;
182
if( zOrig ){
183
if( len<0 ) len = strlen(zOrig);
184
z = fossil_malloc( len+1 );
185
memcpy(z, zOrig, len);
186
z[len] = 0;
187
}
188
return z;
189
}
190
char *fossil_strdup(const char *zOrig){
191
return fossil_strndup(zOrig, -1);
192
}
193
char *fossil_strdup_nn(const char *zOrig){
194
if( zOrig==0 ) return fossil_strndup("", 0);
195
return fossil_strndup(zOrig, -1);
196
}
197
198
/*
199
** strcpy() workalike to squelch an unwarranted warning from OpenBSD.
200
*/
201
void fossil_strcpy(char *dest, const char *src){
202
while( (*(dest++) = *(src++))!=0 ){}
203
}
204
205
/*
206
** Translate every upper-case character in the input string into
207
** its equivalent lower-case.
208
*/
209
char *fossil_strtolwr(char *zIn){
210
char *zStart = zIn;
211
if( zIn ){
212
while( *zIn ){
213
*zIn = fossil_tolower(*zIn);
214
zIn++;
215
}
216
}
217
return zStart;
218
}
219
220
/*
221
** This local variable determines the behavior of
222
** fossil_assert_safe_command_string():
223
**
224
** 0 (default) fossil_panic() on an unsafe command string
225
**
226
** 1 Print an error but continue process. Used for
227
** testing of fossil_assert_safe_command_string().
228
**
229
** 2 No-op. Used to allow any arbitrary command string
230
** through fossil_system(), such as when invoking
231
** COMMAND in "fossil bisect run COMMAND".
232
*/
233
static int safeCmdStrTest = 0;
234
235
/*
236
** Check the input string to ensure that it is safe to pass into system().
237
** A string is unsafe for system() on unix if it contains any of the following:
238
**
239
** * Any occurrence of '$' or '`' except single-quoted or after \
240
** * Any of the following characters, unquoted: ;|& or \n except
241
** these characters are allowed as the very last character in the
242
** string.
243
** * Unbalanced single or double quotes
244
**
245
** This routine is intended as a second line of defense against attack.
246
** It should never fail. Dangerous shell strings should be detected and
247
** fixed before calling fossil_system(). This routine serves only as a
248
** safety net in case of bugs elsewhere in the system.
249
**
250
** If an unsafe string is seen, either abort (default) or print
251
** a warning message (if safeCmdStrTest is true).
252
*/
253
static void fossil_assert_safe_command_string(const char *z){
254
int unsafe = 0;
255
#ifndef _WIN32
256
/* Unix */
257
int inQuote = 0;
258
int i, c;
259
for(i=0; !unsafe && (c = z[i])!=0; i++){
260
switch( c ){
261
case '$':
262
case '`': {
263
if( inQuote!='\'' ) unsafe = i+1;
264
break;
265
}
266
case ';':
267
case '|':
268
case '&':
269
case '\n': {
270
if( inQuote!='\'' && z[i+1]!=0 ) unsafe = i+1;
271
break;
272
}
273
case '"':
274
case '\'': {
275
if( inQuote==0 ){
276
inQuote = c;
277
}else if( inQuote==c ){
278
inQuote = 0;
279
}
280
break;
281
}
282
case '\\': {
283
if( z[i+1]==0 ){
284
unsafe = i+1;
285
}else if( inQuote!='\'' ){
286
i++;
287
}
288
break;
289
}
290
}
291
}
292
if( inQuote ) unsafe = i;
293
#else
294
/* Windows */
295
int i, c;
296
int inQuote = 0;
297
for(i=0; !unsafe && (c = z[i])!=0; i++){
298
switch( c ){
299
case '>':
300
case '<':
301
case '|':
302
case '&':
303
case '\n': {
304
if( inQuote==0 && z[i+1]!=0 ) unsafe = i+1;
305
break;
306
}
307
case '"': {
308
if( inQuote==c ){
309
inQuote = 0;
310
}else{
311
inQuote = c;
312
}
313
break;
314
}
315
case '^': {
316
if( !inQuote && z[i+1]!=0 ){
317
i++;
318
}
319
break;
320
}
321
}
322
}
323
if( inQuote ) unsafe = i;
324
#endif
325
if( unsafe && safeCmdStrTest<2 ){
326
char *zMsg = mprintf("Unsafe command string: %s\n%*shere ----^",
327
z, unsafe+13, "");
328
if( safeCmdStrTest ){
329
fossil_print("%z\n", zMsg);
330
fossil_free(zMsg);
331
}else{
332
fossil_panic("%s", zMsg);
333
}
334
}
335
}
336
337
/*
338
** This function implements a cross-platform "system()" interface.
339
*/
340
int fossil_system(const char *zOrigCmd){
341
int rc;
342
#if defined(_WIN32)
343
/* On windows, we have to put double-quotes around the entire command.
344
** Who knows why - this is just the way windows works.
345
*/
346
char *zNewCmd = mprintf("\"%s\"", zOrigCmd);
347
wchar_t *zUnicode = fossil_utf8_to_unicode(zNewCmd);
348
if( g.fSystemTrace ) {
349
fossil_trace("SYSTEM: %s\n", zNewCmd);
350
}
351
fossil_assert_safe_command_string(zOrigCmd);
352
rc = _wsystem(zUnicode);
353
fossil_unicode_free(zUnicode);
354
free(zNewCmd);
355
#else
356
/* On unix, evaluate the command directly.
357
*/
358
if( g.fSystemTrace ) fprintf(stderr, "SYSTEM: %s\n", zOrigCmd);
359
fossil_assert_safe_command_string(zOrigCmd);
360
361
/* Unix systems should never shell-out while processing an HTTP request,
362
** either via CGI, SCGI, or direct HTTP. The following assert verifies
363
** this. And the following assert proves that Fossil is not vulnerable
364
** to the ShellShock or BashDoor bug.
365
*/
366
assert( g.cgiOutput==0 );
367
368
/* The regular system() call works to get a shell on unix */
369
fossil_limit_memory(0);
370
rc = system(zOrigCmd);
371
fossil_limit_memory(1);
372
#endif
373
return rc;
374
}
375
376
/*
377
** Like "fossil_system()" but does not check the command-string for
378
** potential security problems.
379
*/
380
int fossil_unsafe_system(const char *zOrigCmd){
381
int rc;
382
safeCmdStrTest = 2;
383
rc = fossil_system(zOrigCmd);
384
safeCmdStrTest = 0;
385
return rc;
386
}
387
388
/*
389
** COMMAND: test-fossil-system
390
**
391
** Read lines of input and send them to fossil_system() for evaluation.
392
** Use this command to verify that fossil_system() will not run "unsafe"
393
** commands.
394
*/
395
void test_fossil_system_cmd(void){
396
char zLine[10000];
397
safeCmdStrTest = 1;
398
while(1){
399
size_t n;
400
int rc;
401
printf("system-test> ");
402
fflush(stdout);
403
if( !fgets(zLine, sizeof(zLine), stdin) ) break;
404
n = strlen(zLine);
405
while( n>0 && fossil_isspace(zLine[n-1]) ) n--;
406
zLine[n] = 0;
407
printf("cmd: [%s]\n", zLine);
408
fflush(stdout);
409
rc = fossil_system(zLine);
410
printf("result: %d\n", rc);
411
}
412
}
413
414
/*
415
** Like strcmp() except that it accepts NULL pointers. NULL sorts before
416
** all non-NULL string pointers. Also, this strcmp() is a binary comparison
417
** that does not consider locale.
418
*/
419
int fossil_strcmp(const char *zA, const char *zB){
420
if( zA==0 ){
421
if( zB==0 ) return 0;
422
return -1;
423
}else if( zB==0 ){
424
return +1;
425
}else{
426
return strcmp(zA,zB);
427
}
428
}
429
int fossil_strncmp(const char *zA, const char *zB, int nByte){
430
if( zA==0 ){
431
if( zB==0 ) return 0;
432
return -1;
433
}else if( zB==0 ){
434
return +1;
435
}else if( nByte>0 ){
436
int a, b;
437
do{
438
a = *zA++;
439
b = *zB++;
440
}while( a==b && a!=0 && (--nByte)>0 );
441
return ((unsigned char)a) - (unsigned char)b;
442
}else{
443
return 0;
444
}
445
}
446
447
/*
448
** Case insensitive string comparison.
449
*/
450
int fossil_strnicmp(const char *zA, const char *zB, int nByte){
451
if( zA==0 ){
452
if( zB==0 ) return 0;
453
return -1;
454
}else if( zB==0 ){
455
return +1;
456
}
457
if( nByte<0 ) nByte = strlen(zB);
458
return sqlite3_strnicmp(zA, zB, nByte);
459
}
460
int fossil_stricmp(const char *zA, const char *zB){
461
int nByte;
462
int rc;
463
if( zA==0 ){
464
if( zB==0 ) return 0;
465
return -1;
466
}else if( zB==0 ){
467
return +1;
468
}
469
nByte = strlen(zB);
470
rc = sqlite3_strnicmp(zA, zB, nByte);
471
if( rc==0 && zA[nByte] ) rc = 1;
472
return rc;
473
}
474
475
/*
476
** Get user and kernel times in microseconds.
477
*/
478
void fossil_cpu_times(sqlite3_uint64 *piUser, sqlite3_uint64 *piKernel){
479
#ifdef _WIN32
480
FILETIME not_used;
481
FILETIME kernel_time;
482
FILETIME user_time;
483
GetProcessTimes(GetCurrentProcess(), &not_used, &not_used,
484
&kernel_time, &user_time);
485
if( piUser ){
486
*piUser = ((((sqlite3_uint64)user_time.dwHighDateTime)<<32) +
487
(sqlite3_uint64)user_time.dwLowDateTime + 5)/10;
488
}
489
if( piKernel ){
490
*piKernel = ((((sqlite3_uint64)kernel_time.dwHighDateTime)<<32) +
491
(sqlite3_uint64)kernel_time.dwLowDateTime + 5)/10;
492
}
493
#else
494
struct rusage s;
495
getrusage(RUSAGE_SELF, &s);
496
if( piUser ){
497
*piUser = ((sqlite3_uint64)s.ru_utime.tv_sec)*1000000 + s.ru_utime.tv_usec;
498
}
499
if( piKernel ){
500
*piKernel =
501
((sqlite3_uint64)s.ru_stime.tv_sec)*1000000 + s.ru_stime.tv_usec;
502
}
503
#endif
504
}
505
506
/*
507
** Return the resident set size for this process
508
*/
509
sqlite3_uint64 fossil_rss(void){
510
#ifdef _WIN32
511
return 0;
512
#else
513
struct rusage s;
514
getrusage(RUSAGE_SELF, &s);
515
return s.ru_maxrss*1024;
516
#endif
517
}
518
519
520
/*
521
** Internal helper type for fossil_timer_xxx().
522
*/
523
enum FossilTimerEnum {
524
FOSSIL_TIMER_COUNT = 10 /* Number of timers we can track. */
525
};
526
static struct FossilTimer {
527
sqlite3_uint64 u; /* "User" CPU times */
528
sqlite3_uint64 s; /* "System" CPU times */
529
int id; /* positive if allocated, else 0. */
530
} fossilTimerList[FOSSIL_TIMER_COUNT] = {{0,0,0}};
531
532
/*
533
** Stores the current CPU times into the shared timer list
534
** and returns that timer's internal ID. Pass that ID to
535
** fossil_timer_fetch() to get the elapsed time for that
536
** timer.
537
**
538
** The system has a fixed number of timers, and they can be
539
** "deallocated" by passing this function's return value to
540
** fossil_timer_stop() Adjust FOSSIL_TIMER_COUNT to set the number of
541
** available timers.
542
**
543
** Returns 0 on error (no more timers available), with 1+ being valid
544
** timer IDs.
545
*/
546
int fossil_timer_start(){
547
int i;
548
for( i = 0; i < FOSSIL_TIMER_COUNT; ++i ){
549
struct FossilTimer * ft = &fossilTimerList[i];
550
if(ft->id) continue;
551
ft->id = i+1;
552
fossil_cpu_times( &ft->u, &ft->s );
553
break;
554
}
555
return (i<FOSSIL_TIMER_COUNT) ? i+1 : 0;
556
}
557
558
/*
559
** Returns the difference in CPU times in microseconds since
560
** fossil_timer_start() was called and returned the given timer ID (or
561
** since it was last reset). Returns 0 if timerId is out of range.
562
*/
563
sqlite3_uint64 fossil_timer_fetch(int timerId){
564
if( timerId>0 && timerId<=FOSSIL_TIMER_COUNT ){
565
struct FossilTimer * start = &fossilTimerList[timerId-1];
566
if( !start->id ){
567
fossil_panic("Invalid call to fetch a non-allocated "
568
"timer (#%d)", timerId);
569
/*NOTREACHED*/
570
}else{
571
sqlite3_uint64 eu = 0, es = 0;
572
fossil_cpu_times( &eu, &es );
573
return (eu - start->u) + (es - start->s);
574
}
575
}
576
return 0;
577
}
578
579
/*
580
** Resets the timer associated with the given ID, as obtained via
581
** fossil_timer_start(), to the current CPU time values.
582
*/
583
sqlite3_uint64 fossil_timer_reset(int timerId){
584
if( timerId>0 && timerId<=FOSSIL_TIMER_COUNT ){
585
struct FossilTimer * start = &fossilTimerList[timerId-1];
586
if( !start->id ){
587
fossil_panic("Invalid call to reset a non-allocated "
588
"timer (#%d)", timerId);
589
/*NOTREACHED*/
590
}else{
591
sqlite3_uint64 const rc = fossil_timer_fetch(timerId);
592
fossil_cpu_times( &start->u, &start->s );
593
return rc;
594
}
595
}
596
return 0;
597
}
598
599
/**
600
"Deallocates" the fossil timer identified by the given timer ID.
601
returns the difference (in uSec) between the last time that timer
602
was started or reset. Returns 0 if timerId is out of range (but
603
note that, due to system-level precision restrictions, this
604
function might return 0 on success, too!). It is not legal to
605
re-use the passed-in timerId after calling this until/unless it is
606
re-initialized using fossil_timer_start() (NOT
607
fossil_timer_reset()).
608
*/
609
sqlite3_uint64 fossil_timer_stop(int timerId){
610
if(timerId<1 || timerId>FOSSIL_TIMER_COUNT){
611
return 0;
612
}else{
613
sqlite3_uint64 const rc = fossil_timer_fetch(timerId);
614
struct FossilTimer * t = &fossilTimerList[timerId-1];
615
t->id = 0;
616
t->u = t->s = 0U;
617
return rc;
618
}
619
}
620
621
/*
622
** Returns true (non-0) if the given timer ID (as returned from
623
** fossil_timer_start() is currently active.
624
*/
625
int fossil_timer_is_active( int timerId ){
626
if(timerId<1 || timerId>FOSSIL_TIMER_COUNT){
627
return 0;
628
}else{
629
const int rc = fossilTimerList[timerId-1].id;
630
assert(!rc || (rc == timerId));
631
return fossilTimerList[timerId-1].id;
632
}
633
}
634
635
/*
636
** Return TRUE if fd is a valid open file descriptor. This only
637
** works on unix. The function always returns true on Windows.
638
*/
639
int is_valid_fd(int fd){
640
#ifdef _WIN32
641
return 1;
642
#else
643
return fcntl(fd, F_GETFL)!=(-1) || errno!=EBADF;
644
#endif
645
}
646
647
/*
648
** Returns TRUE if zSym is exactly HNAME_LEN_SHA1 or HNAME_LEN_K256
649
** bytes long and contains only lower-case ASCII hexadecimal values.
650
*/
651
int fossil_is_artifact_hash(const char *zSym){
652
int sz = zSym ? (int)strlen(zSym) : 0;
653
return (HNAME_LEN_SHA1==sz || HNAME_LEN_K256==sz) && validate16(zSym, sz);
654
}
655
656
/*
657
** Return true if the input string is NULL or all whitespace.
658
** Return false if the input string contains text.
659
*/
660
int fossil_all_whitespace(const char *z){
661
if( z==0 ) return 1;
662
while( fossil_isspace(z[0]) ){ z++; }
663
return z[0]==0;
664
}
665
666
/*
667
** Return the name of the users preferred text editor. Return NULL if
668
** not found.
669
**
670
** Search algorithm:
671
** (1) The value of the --editor command-line argument
672
** (2) The local "editor" setting
673
** (3) The global "editor" setting
674
** (4) The VISUAL environment variable
675
** (5) The EDITOR environment variable
676
** (6) Any of several common editors that might be available, such as:
677
** notepad, nano, pico, jove, edit, vi, vim, ed
678
**
679
** The search only occurs once, the first time this routine is called.
680
** Second and subsequent invocations always return the same value.
681
*/
682
const char *fossil_text_editor(void){
683
static const char *zEditor = 0;
684
const char *azStdEd[] = {
685
#ifdef _WIN32
686
"notepad",
687
#endif
688
"nano", "pico", "jove", "edit", "vi", "vim", "ed"
689
};
690
int i = 0;
691
if( zEditor==0 ){
692
zEditor = find_option("editor",0,1);
693
}
694
if( zEditor==0 ){
695
zEditor = db_get("editor", 0);
696
}
697
if( zEditor==0 ){
698
zEditor = fossil_getenv("VISUAL");
699
}
700
if( zEditor==0 ){
701
zEditor = fossil_getenv("EDITOR");
702
}
703
while( zEditor==0 && i<count(azStdEd) ){
704
if( fossil_app_on_path(azStdEd[i],0) ){
705
zEditor = azStdEd[i];
706
}else{
707
i++;
708
}
709
}
710
if( zEditor && is_false(zEditor) ) zEditor = 0;
711
return zEditor;
712
}
713
714
/*
715
** Construct a temporary filename.
716
**
717
** The returned string is obtained from sqlite3_malloc() and must be
718
** freed by the caller.
719
**
720
** See also: file_tempname() and file_time_timename();
721
*/
722
char *fossil_temp_filename(void){
723
char *zTFile = 0;
724
const char *zDir;
725
char cDirSep;
726
char zSep[2];
727
size_t nDir;
728
u64 r[2];
729
#ifdef _WIN32
730
char *zTempDirA = NULL;
731
WCHAR zTempDirW[MAX_PATH+1];
732
const DWORD dwTempSizeW = sizeof(zTempDirW)/sizeof(zTempDirW[0]);
733
DWORD dwTempLenW;
734
#else
735
int i;
736
static const char *azTmp[] = {"/var/tmp","/usr/tmp","/tmp"};
737
#endif
738
if( g.db ){
739
sqlite3_file_control(g.db, 0, SQLITE_FCNTL_TEMPFILENAME, (void*)&zTFile);
740
if( zTFile ) return zTFile;
741
}
742
sqlite3_randomness(sizeof(r), &r);
743
#if _WIN32
744
cDirSep = '\\';
745
dwTempLenW = GetTempPathW(dwTempSizeW, zTempDirW);
746
if( dwTempLenW>0 && dwTempLenW<dwTempSizeW
747
&& ( zTempDirA = fossil_path_to_utf8(zTempDirW) )){
748
zDir = zTempDirA;
749
}else{
750
zDir = fossil_getenv("LOCALAPPDATA");
751
if( zDir==0 ) zDir = ".";
752
}
753
#else
754
for(i=0; i<(int)(sizeof(azTmp)/sizeof(azTmp[0])); i++){
755
struct stat buf;
756
zDir = azTmp[i];
757
if( stat(zDir,&buf)==0 && S_ISDIR(buf.st_mode) && access(zDir,03)==0 ){
758
break;
759
}
760
}
761
if( i>=(int)(sizeof(azTmp)/sizeof(azTmp[0])) ) zDir = ".";
762
cDirSep = '/';
763
#endif
764
nDir = strlen(zDir);
765
zSep[1] = 0;
766
zSep[0] = (nDir && zDir[nDir-1]==cDirSep) ? 0 : cDirSep;
767
zTFile = sqlite3_mprintf("%s%sfossil%016llx%016llx", zDir,zSep,r[0],r[1]);
768
#ifdef _WIN32
769
if( zTempDirA ) fossil_path_free(zTempDirA);
770
#endif
771
return zTFile;
772
}
773
774
/*
775
** Turn memory limits for stack and heap on and off. The argument
776
** is true to turn memory limits on and false to turn them off.
777
**
778
** Memory limits should be enabled at startup, but then turned off
779
** before starting subprocesses.
780
*/
781
void fossil_limit_memory(int onOff){
782
#if defined(__unix__)
783
static sqlite3_int64 origHeap = 10000000000LL; /* 10GB */
784
static sqlite3_int64 origStack = 8000000 ; /* 8MB */
785
struct rlimit x;
786
787
#if defined(RLIMIT_DATA)
788
getrlimit(RLIMIT_DATA, &x);
789
if( onOff ){
790
origHeap = x.rlim_cur;
791
if( sizeof(void*)<8 || sizeof(x.rlim_cur)<8 ){
792
x.rlim_cur = 1000000000 ; /* 1GB on 32-bit systems */
793
}else{
794
x.rlim_cur = 10000000000LL; /* 10GB on 64-bit systems */
795
}
796
}else{
797
x.rlim_cur = origHeap;
798
}
799
setrlimit(RLIMIT_DATA, &x);
800
#endif /* defined(RLIMIT_DATA) */
801
#if defined(RLIMIT_STACK)
802
getrlimit(RLIMIT_STACK, &x);
803
if( onOff ){
804
origStack = x.rlim_cur;
805
x.rlim_cur = 8000000; /* 8MB */
806
}else{
807
x.rlim_cur = origStack;
808
}
809
setrlimit(RLIMIT_STACK, &x);
810
#endif /* defined(RLIMIT_STACK) */
811
#endif /* defined(__unix__) */
812
}
813
814
#if defined(HAVE_PLEDGE)
815
/*
816
** Interface to pledge() on OpenBSD 5.9 and later.
817
**
818
** On platforms that have pledge(), use this routine.
819
** On all other platforms, this routine does not exist, but instead
820
** a macro defined in config.h is used to provide a no-op.
821
*/
822
void fossil_pledge(const char *promises){
823
if( pledge(promises, 0) ){
824
fossil_panic("pledge(\"%s\",NULL) fails with errno=%d",
825
promises, (int)errno);
826
}
827
}
828
#endif /* defined(HAVE_PLEDGE) */
829
830
/*
831
** Construct a random password and return it as a string. N is the
832
** recommended number of characters for the password.
833
**
834
** Space to hold the returned string is obtained from fossil_malloc()
835
** and should be freed by the caller.
836
*/
837
char *fossil_random_password(int N){
838
char zSrc[60];
839
int nSrc;
840
int i;
841
char z[60];
842
843
/* Source characters for the password. Omit characters like "0", "O",
844
** "1" and "I" that might be easily confused */
845
static const char zAlphabet[] =
846
/* 0 1 2 3 4 5 */
847
/* 123456789 123456789 123456789 123456789 123456789 123456 */
848
"23456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ";
849
850
if( N<8 ) N = 8;
851
nSrc = sizeof(zAlphabet) - 1;
852
if( N>nSrc ) N = nSrc;
853
memcpy(zSrc, zAlphabet, nSrc);
854
855
for(i=0; i<N; i++){
856
unsigned r;
857
sqlite3_randomness(sizeof(r), &r);
858
r %= nSrc;
859
z[i] = zSrc[r];
860
zSrc[r] = zSrc[--nSrc];
861
}
862
z[i] = 0;
863
return fossil_strdup(z);
864
}
865
866
/*
867
** COMMAND: test-random-password
868
**
869
** Usage: %fossil test-random-password [N] [--entropy]
870
**
871
** Generate a random password string of approximately N characters in length.
872
** If N is omitted, use 12. Values of N less than 8 are changed to 8
873
** and greater than 57 and changed to 57.
874
**
875
** If the --entropy flag is included, the number of bits of entropy in
876
** the password is show as well.
877
*/
878
void test_random_password(void){
879
int N = 12;
880
int showEntropy = 0;
881
int i;
882
char *zPassword;
883
for(i=2; i<g.argc; i++){
884
const char *z = g.argv[i];
885
if( z[0]=='-' && z[1]=='-' ) z++;
886
if( strcmp(z,"-entropy")==0 ){
887
showEntropy = 1;
888
}else if( fossil_isdigit(z[0]) ){
889
N = atoi(z);
890
if( N<8 ) N = 8;
891
if( N>57 ) N = 57;
892
}else{
893
usage("[N] [--entropy]");
894
}
895
}
896
zPassword = fossil_random_password(N);
897
if( showEntropy ){
898
double et = 57.0;
899
for(i=1; i<N; i++) et *= 57-i;
900
fossil_print("%s (%d bits of entropy)\n", zPassword,
901
(int)(log(et)/log(2.0)));
902
}else{
903
fossil_print("%s\n", zPassword);
904
}
905
fossil_free(zPassword);
906
}
907
908
/*
909
** Generate a version 4 ("random"), variant 1 UUID (RFC 9562, Section 5.4).
910
**
911
** Format: xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx
912
** where M=4 and N=8, 9, a, or b (this leaves 122 random bits)
913
*/
914
char* fossil_generate_uuid() {
915
static const char zDigits[] = "0123456789abcdef";
916
unsigned char aBlob[16];
917
unsigned char zStr[37];
918
unsigned char *p = zStr;
919
int i, k;
920
921
sqlite3_randomness(16, aBlob);
922
aBlob[6] = (aBlob[6]&0x0f) + 0x40; /* Version byte: 0100 xxxx */
923
aBlob[8] = (aBlob[8]&0x3f) + 0x80; /* Variant byte: 10xx xxxx */
924
925
for(i=0, k=0x550; i<16; i++, k=k>>1){
926
if( k&1 ){
927
*p++ = '-'; /* Add a dash after byte 4, 6, 8, and 12 */
928
}
929
*p++ = zDigits[aBlob[i]>>4];
930
*p++ = zDigits[aBlob[i]&0xf];
931
}
932
*p = 0;
933
934
return fossil_strdup((char*)zStr);
935
}
936
937
/*
938
** COMMAND: test-generate-uuid
939
**
940
** Usage: %fossil test-generate-uuid
941
**
942
** Generate a version 4 ("random"), variant 1 UUID (RFC 9562, Section 5.4):
943
**
944
** xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx - where M=4 and N=8, 9, a, or b
945
*/
946
void test_generate_uuid(void){
947
fossil_print("%s\n", fossil_generate_uuid());
948
}
949
950
/*
951
** Return the number of decimal digits in a nonnegative integer. This is useful
952
** when formatting text.
953
*/
954
int fossil_num_digits(int n){
955
return n< 10 ? 1 : n< 100 ? 2 : n< 1000 ? 3
956
: n< 10000 ? 4 : n< 100000 ? 5 : n< 1000000 ? 6
957
: n<10000000 ? 7 : n<100000000 ? 8 : n<1000000000 ? 9 : 10;
958
}
959
960
/*
961
** Search for an executable on the PATH environment variable.
962
** Return true (1) if found and false (0) if not found.
963
**
964
** Print the full pathname of the first location if ePrint==1. Print
965
** all pathnames for the executable if ePrint==2 or more.
966
*/
967
int fossil_app_on_path(const char *zBinary, int ePrint){
968
const char *zPath = fossil_getenv("PATH");
969
char *zFull;
970
int i;
971
int bExists;
972
int bFound = 0;
973
while( zPath && zPath[0] ){
974
#ifdef _WIN32
975
while( zPath[0]==';' ) zPath++;
976
for(i=0; zPath[i] && zPath[i]!=';'; i++){}
977
zFull = mprintf("%.*s\\%s.exe", i, zPath, zBinary);
978
bExists = file_access(zFull, R_OK);
979
if( bExists!=0 ){
980
fossil_free(zFull);
981
zFull = mprintf("%.*s\\%s.bat", i, zPath, zBinary);
982
bExists = file_access(zFull, R_OK);
983
}
984
#else
985
while( zPath[0]==':' ) zPath++;
986
for(i=0; zPath[i] && zPath[i]!=':'; i++){}
987
zFull = mprintf("%.*s/%s", i, zPath, zBinary);
988
bExists = file_access(zFull, X_OK);
989
#endif
990
if( bExists==0 && ePrint ){
991
fossil_print("%s\n", zFull);
992
}
993
fossil_free(zFull);
994
if( bExists==0 ){
995
if( ePrint<2 ) return 1;
996
bFound = 1;
997
}
998
zPath += i;
999
}
1000
return bFound;
1001
}
1002
1003
/*
1004
** Return the name of a command that will launch a web-browser.
1005
*/
1006
const char *fossil_web_browser(void){
1007
const char *zBrowser = 0;
1008
#if defined(_WIN32)
1009
zBrowser = db_get("web-browser", "start \"\"");
1010
#elif defined(__DARWIN__) || defined(__APPLE__) || defined(__HAIKU__)
1011
zBrowser = db_get("web-browser", "open");
1012
#else
1013
zBrowser = db_get("web-browser", 0);
1014
if( zBrowser==0 ){
1015
static const char *const azBrowserProg[] =
1016
{ "xdg-open", "gnome-open", "firefox", "google-chrome" };
1017
int i;
1018
zBrowser = "echo";
1019
for(i=0; i<count(azBrowserProg); i++){
1020
if( fossil_app_on_path(azBrowserProg[i],0) ){
1021
zBrowser = azBrowserProg[i];
1022
break;
1023
}
1024
}
1025
zBrowser = mprintf("%s 2>/dev/null", zBrowser);
1026
}
1027
#endif
1028
return zBrowser;
1029
}
1030
1031
/*
1032
** On non-Windows systems, calls nice(2) with the given level. Errors
1033
** are ignored. On Windows this is a no-op.
1034
*/
1035
void fossil_nice(int level){
1036
#ifndef _WIN32
1037
/* dummy if() condition to avoid nuisance warning about unused result on
1038
certain compiler */
1039
if( nice(level) ){ /*ignored*/ }
1040
#else
1041
(void)level;
1042
#endif
1043
}
1044
1045
/*
1046
** Calls fossil_nice() with a default level.
1047
*/
1048
void fossil_nice_default(void){
1049
fossil_nice(19);
1050
}
1051

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button