LCOV - code coverage report
Current view: top level - cmdline - support.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 449 559 80.3 %
Date: 2017-11-06 22:14:04 Functions: 61 63 96.8 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (C) 2011 Andrea Mazzoleni
       3             :  *
       4             :  * This program is free software: you can redistribute it and/or modify
       5             :  * it under the terms of the GNU General Public License as published by
       6             :  * the Free Software Foundation, either version 3 of the License, or
       7             :  * (at your option) any later version.
       8             :  *
       9             :  * This program is distributed in the hope that it will be useful,
      10             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12             :  * GNU General Public License for more details.
      13             :  *
      14             :  * You should have received a copy of the GNU General Public License
      15             :  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
      16             :  */
      17             : 
      18             : #include "portable.h"
      19             : 
      20             : #include "support.h"
      21             : 
      22             : /****************************************************************************/
      23             : /* lock */
      24             : 
      25             : /**
      26             :  * Locks used externally.
      27             :  */
      28             : #if HAVE_PTHREAD
      29             : static pthread_mutex_t msg_lock;
      30             : static pthread_mutex_t memory_lock;
      31             : #endif
      32             : 
      33     3896497 : void lock_msg(void)
      34             : {
      35             : #if HAVE_PTHREAD
      36     3896497 :         thread_mutex_lock(&msg_lock);
      37             : #endif
      38     3896500 : }
      39             : 
      40     3896500 : void unlock_msg(void)
      41             : {
      42             : #if HAVE_PTHREAD
      43     3896500 :         thread_mutex_unlock(&msg_lock);
      44             : #endif
      45     3896500 : }
      46             : 
      47    20178753 : void lock_memory(void)
      48             : {
      49             : #if HAVE_PTHREAD
      50    20178753 :         thread_mutex_lock(&memory_lock);
      51             : #endif
      52    20178753 : }
      53             : 
      54    20178753 : void unlock_memory(void)
      55             : {
      56             : #if HAVE_PTHREAD
      57    20178753 :         thread_mutex_unlock(&memory_lock);
      58             : #endif
      59    20178753 : }
      60             : 
      61         299 : void lock_init(void)
      62             : {
      63             : #if HAVE_PTHREAD
      64             :         /* initialize the locks as first operation as log_fatal depends on them */
      65         299 :         thread_mutex_init(&msg_lock, 0);
      66         299 :         thread_mutex_init(&memory_lock, 0);
      67             : #endif
      68         299 : }
      69             : 
      70         264 : void lock_done(void)
      71             : {
      72             : #if HAVE_PTHREAD
      73         264 :         thread_mutex_destroy(&msg_lock);
      74         264 :         thread_mutex_destroy(&memory_lock);
      75             : #endif
      76         264 : }
      77             : 
      78             : /****************************************************************************/
      79             : /* print */
      80             : 
      81             : int msg_level = 0;
      82             : 
      83             : /*
      84             :  * Note that in the following functions we always flush both
      85             :  * stdout and stderr, because we want to ensure that they mixes
      86             :  * well when redirected to files
      87             :  *
      88             :  * The buffering is similar at the "line buffered" one, that
      89             :  * is not available on Windows, so we emulate it in this way.
      90             :  *
      91             :  * For stdlog flushing is limited. To ensure flushing the
      92             :  * caller should use log_flush().
      93             :  */
      94             : 
      95         809 : void log_fatal(const char* format, ...)
      96             : {
      97             :         va_list ap;
      98             : 
      99         809 :         lock_msg();
     100             : 
     101         809 :         if (stdlog) {
     102          95 :                 va_start(ap, format);
     103          95 :                 fprintf(stdlog, "msg:fatal: ");
     104          95 :                 vfprintf(stdlog, format, ap);
     105          95 :                 fflush(stdlog);
     106          95 :                 va_end(ap);
     107             :         }
     108             : 
     109         809 :         va_start(ap, format);
     110         809 :         vfprintf(stderr, format, ap);
     111         809 :         fflush(stderr);
     112         809 :         va_end(ap);
     113             : 
     114         809 :         unlock_msg();
     115         809 : }
     116             : 
     117      536219 : void log_error(const char* format, ...)
     118             : {
     119             :         va_list ap;
     120             : 
     121      536219 :         lock_msg();
     122             : 
     123      536219 :         if (stdlog) {
     124      534338 :                 va_start(ap, format);
     125      534338 :                 fprintf(stdlog, "msg:error: ");
     126      534338 :                 vfprintf(stdlog, format, ap);
     127      534338 :                 fflush(stdlog);
     128      534338 :                 va_end(ap);
     129             :         } else {
     130        1881 :                 va_start(ap, format);
     131        1881 :                 vfprintf(stderr, format, ap);
     132        1881 :                 fflush(stderr);
     133        1881 :                 va_end(ap);
     134             :         }
     135             : 
     136      536219 :         unlock_msg();
     137      536219 : }
     138             : 
     139       11259 : void log_expected(const char* format, ...)
     140             : {
     141             :         va_list ap;
     142             : 
     143       11259 :         lock_msg();
     144             : 
     145       11259 :         if (stdlog) {
     146       11259 :                 va_start(ap, format);
     147       11259 :                 fprintf(stdlog, "msg:expected: ");
     148       11259 :                 vfprintf(stdlog, format, ap);
     149       11259 :                 fflush(stdlog);
     150       11259 :                 va_end(ap);
     151             :         }
     152             : 
     153       11259 :         unlock_msg();
     154       11259 : }
     155             : 
     156     2917036 : void log_tag(const char* format, ...)
     157             : {
     158             :         va_list ap;
     159             : 
     160     2917036 :         lock_msg();
     161             : 
     162     2917039 :         if (stdlog) {
     163     2575300 :                 va_start(ap, format);
     164     2575300 :                 vfprintf(stdlog, format, ap);
     165             :                 /* here we intentionally don't flush */
     166             :                 /* to make the output faster */
     167     2575300 :                 va_end(ap);
     168             :         }
     169             : 
     170     2917039 :         unlock_msg();
     171     2917039 : }
     172             : 
     173        1199 : void log_flush(void)
     174             : {
     175        1199 :         lock_msg();
     176             : 
     177        1199 :         if (stdlog)
     178         338 :                 fflush(stdlog);
     179        1199 :         fflush(stdout);
     180        1199 :         fflush(stderr);
     181             : 
     182        1199 :         unlock_msg();
     183        1199 : }
     184             : 
     185         625 : void msg_status(const char* format, ...)
     186             : {
     187             :         va_list ap;
     188             : 
     189         625 :         lock_msg();
     190             : 
     191         625 :         if (stdlog) {
     192         275 :                 va_start(ap, format);
     193         275 :                 fprintf(stdlog, "msg:status: ");
     194         275 :                 vfprintf(stdlog, format, ap);
     195         275 :                 fflush(stdlog);
     196         275 :                 va_end(ap);
     197             :         }
     198             : 
     199         625 :         if (msg_level >= MSG_STATUS) {
     200         625 :                 va_start(ap, format);
     201         625 :                 vfprintf(stdout, format, ap);
     202         625 :                 fflush(stdout);
     203         625 :                 va_end(ap);
     204             :         }
     205             : 
     206         625 :         unlock_msg();
     207         625 : }
     208             : 
     209      295962 : void msg_info(const char* format, ...)
     210             : {
     211             :         va_list ap;
     212             : 
     213      295962 :         lock_msg();
     214             : 
     215             :         /* don't output in stdlog as these messages */
     216             :         /* are always paired with a msg_tag() call */
     217             : 
     218      295962 :         if (msg_level >= MSG_INFO) {
     219       28818 :                 va_start(ap, format);
     220       28818 :                 vfprintf(stdout, format, ap);
     221       28818 :                 fflush(stdout);
     222       28818 :                 va_end(ap);
     223             :         }
     224             : 
     225      295962 :         unlock_msg();
     226      295962 : }
     227             : 
     228        4452 : void msg_progress(const char* format, ...)
     229             : {
     230             :         va_list ap;
     231             : 
     232        4452 :         lock_msg();
     233             : 
     234        4452 :         if (stdlog) {
     235         819 :                 va_start(ap, format);
     236         819 :                 fprintf(stdlog, "msg:progress: ");
     237         819 :                 vfprintf(stdlog, format, ap);
     238         819 :                 fflush(stdlog);
     239         819 :                 va_end(ap);
     240             :         }
     241             : 
     242        4452 :         if (msg_level >= MSG_PROGRESS) {
     243         161 :                 va_start(ap, format);
     244         161 :                 vfprintf(stdout, format, ap);
     245         161 :                 fflush(stdout);
     246         161 :                 va_end(ap);
     247             :         }
     248             : 
     249        4452 :         unlock_msg();
     250        4452 : }
     251             : 
     252        1462 : void msg_bar(const char* format, ...)
     253             : {
     254             :         va_list ap;
     255             : 
     256        1462 :         lock_msg();
     257             : 
     258             :         /* don't output in stdlog as these messages */
     259             :         /* are intended for screen only */
     260             :         /* also don't flush stdout as they are intended to be partial messages */
     261             : 
     262        1462 :         if (msg_level >= MSG_BAR) {
     263           0 :                 va_start(ap, format);
     264           0 :                 vfprintf(stdout, format, ap);
     265           0 :                 va_end(ap);
     266             :         }
     267             : 
     268        1462 :         unlock_msg();
     269        1462 : }
     270             : 
     271      127025 : void msg_verbose(const char* format, ...)
     272             : {
     273             :         va_list ap;
     274             : 
     275      127025 :         lock_msg();
     276             : 
     277      127025 :         if (stdlog) {
     278      125159 :                 va_start(ap, format);
     279      125159 :                 fprintf(stdlog, "msg:verbose: ");
     280      125159 :                 vfprintf(stdlog, format, ap);
     281      125159 :                 fflush(stdlog);
     282      125159 :                 va_end(ap);
     283             :         }
     284             : 
     285      127025 :         if (msg_level >= MSG_VERBOSE) {
     286          91 :                 va_start(ap, format);
     287          91 :                 vfprintf(stdout, format, ap);
     288          91 :                 fflush(stdout);
     289          91 :                 va_end(ap);
     290             :         }
     291             : 
     292      127025 :         unlock_msg();
     293      127025 : }
     294             : 
     295         449 : void msg_flush(void)
     296             : {
     297         449 :         lock_msg();
     298             : 
     299         449 :         fflush(stdout);
     300         449 :         fflush(stderr);
     301             : 
     302         449 :         unlock_msg();
     303         449 : }
     304             : 
     305         106 : void printc(char c, size_t pad)
     306             : {
     307         303 :         while (pad) {
     308             :                 /* group writes in long pieces */
     309             :                 char buf[128];
     310          91 :                 size_t len = pad;
     311             : 
     312          91 :                 if (len >= sizeof(buf))
     313           0 :                         len = sizeof(buf) - 1;
     314             : 
     315          91 :                 memset(buf, c, len);
     316          91 :                 buf[len] = 0;
     317             : 
     318          91 :                 fputs(buf, stdout);
     319             : 
     320          91 :                 pad -= len;
     321             :         }
     322         106 : }
     323             : 
     324          34 : void printr(const char* str, size_t pad)
     325             : {
     326             :         size_t len;
     327             : 
     328          34 :         len = strlen(str);
     329             : 
     330          34 :         if (len < pad)
     331          34 :                 printc(' ', pad - len);
     332             : 
     333          34 :         fputs(str, stdout);
     334          34 : }
     335             : 
     336          52 : void printl(const char* str, size_t pad)
     337             : {
     338             :         size_t len;
     339             : 
     340          52 :         fputs(str, stdout);
     341             : 
     342          52 :         len = strlen(str);
     343             : 
     344          52 :         if (len < pad)
     345          29 :                 printc(' ', pad - len);
     346          52 : }
     347             : 
     348          18 : void printp(double v, size_t pad)
     349             : {
     350             :         char buf[64];
     351          18 :         const char* s = "%";
     352             : 
     353          18 :         if (v > 0.1)
     354           4 :                 snprintf(buf, sizeof(buf), "%5.2f%s", v, s);
     355          14 :         else if (v > 0.01)
     356           2 :                 snprintf(buf, sizeof(buf), "%6.3f%s", v, s);
     357          12 :         else if (v > 0.001)
     358           3 :                 snprintf(buf, sizeof(buf), "%7.4f%s", v, s);
     359           9 :         else if (v > 0.0001)
     360           2 :                 snprintf(buf, sizeof(buf), "%8.5f%s", v, s);
     361           7 :         else if (v > 0.00001)
     362           2 :                 snprintf(buf, sizeof(buf), "%9.6f%s", v, s);
     363           5 :         else if (v > 0.000001)
     364           1 :                 snprintf(buf, sizeof(buf), "%10.7f%s", v, s);
     365           4 :         else if (v > 0.0000001)
     366           1 :                 snprintf(buf, sizeof(buf), "%11.8f%s", v, s);
     367           3 :         else if (v > 0.00000001)
     368           1 :                 snprintf(buf, sizeof(buf), "%12.9f%s", v, s);
     369           2 :         else if (v > 0.000000001)
     370           1 :                 snprintf(buf, sizeof(buf), "%13.10f%s", v, s);
     371           1 :         else if (v > 0.0000000001)
     372           0 :                 snprintf(buf, sizeof(buf), "%14.11f%s", v, s);
     373           1 :         else if (v > 0.00000000001)
     374           1 :                 snprintf(buf, sizeof(buf), "%15.12f%s", v, s);
     375           0 :         else if (v > 0.000000000001)
     376           0 :                 snprintf(buf, sizeof(buf), "%16.13f%s", v, s);
     377             :         else
     378           0 :                 snprintf(buf, sizeof(buf), "%17.14f%s", v, s);
     379          18 :         printl(buf, pad);
     380          18 : }
     381             : 
     382             : #define ESCAPE(from,escape,to) \
     383             :         case from : \
     384             :                 if (p == end) \
     385             :                         goto bail; \
     386             :                 *p++ = escape; \
     387             :                 if (p == end) \
     388             :                         goto bail; \
     389             :                 *p++ = to; \
     390             :                 break
     391             : 
     392     2436696 : const char* esc_tag(const char* str, char* buffer)
     393             : {
     394     2436696 :         char* begin = buffer;
     395     2436696 :         char* end = begin + ESC_MAX;
     396     2436696 :         char* p = begin;
     397             : 
     398             :         /* copy string with escaping */
     399    36500448 :         while (*str) {
     400    31627056 :                 char c = *str;
     401             : 
     402    31627056 :                 switch (c) {
     403             : 
     404           0 :                 ESCAPE('\n', '\\', 'n');
     405           0 :                 ESCAPE('\r', '\\', 'r');
     406           0 :                 ESCAPE(':', '\\', 'd');
     407           0 :                 ESCAPE('\\', '\\', '\\');
     408             : 
     409             :                 default:
     410    31627056 :                         if (p == end)
     411           0 :                                 goto bail;
     412    31627056 :                         *p++ = c;
     413    31627056 :                         break;
     414             :                 }
     415             : 
     416    31627056 :                 ++str;
     417             :         }
     418             : 
     419             :         /* put final 0 */
     420     2436696 :         if (p == end)
     421           0 :                 goto bail;
     422     2436696 :         *p = 0;
     423             : 
     424     4873392 :         return begin;
     425             : 
     426             : bail:
     427             :         /* LCOV_EXCL_START */
     428             :         log_fatal("Escape for log too long\n");
     429             :         exit(EXIT_FAILURE);
     430             :         /* LCOV_EXCL_STOP */
     431             : }
     432             : 
     433      356187 : const char* esc_shell_multi(const char** str_map, unsigned str_max, char* buffer)
     434             : {
     435      356187 :         char* begin = buffer;
     436      356187 :         char* end = begin + ESC_MAX;
     437      356187 :         char* p = begin;
     438             :         unsigned str_mac;
     439             :         const char* str;
     440             : 
     441             : #ifdef _WIN32
     442             :         int has_quote = 0;
     443             : 
     444             :         for (str_mac = 0; str_mac < str_max; ++str_mac) {
     445             :                 str = str_map[str_mac];
     446             :                 if (strchr(str, ' ') != 0)
     447             :                         has_quote = 1;
     448             :         }
     449             : 
     450             :         if (has_quote) {
     451             :                 if (p == end)
     452             :                         goto bail;
     453             :                 *p++ = '"';
     454             :         }
     455             : #endif
     456             : 
     457             :         /* copy string with escaping */
     458      356187 :         str_mac = 0;
     459      356187 :         str = str_map[str_mac];
     460             :         while (1) {
     461             :                 /* get the next char */
     462     5125312 :                 char c = *str;
     463             : 
     464             :                 /* if one string is finished, go to the next */
     465    10286714 :                 while (c == 0 && str_mac + 1 < str_max) {
     466       36090 :                         ++str_mac;
     467       36090 :                         str = str_map[str_mac];
     468       36090 :                         c = *str;
     469             :                 }
     470             : 
     471             :                 /* if we read all the strings, stop */
     472     5125312 :                 if (!c)
     473      356187 :                         break;
     474             : 
     475     4769125 :                 switch (c) {
     476             : #ifdef _WIN32
     477             :                 /*
     478             :                  * Windows shell escape
     479             :                  *
     480             :                  * The Windows NT Command Shell
     481             :                  * https://technet.microsoft.com/en-us/library/cc723564.aspx
     482             :                  */
     483             :                 case '"' :
     484             :                         /* double quote, it needs to be quoted with \ */
     485             :                         if (has_quote) {
     486             :                                 /* " -> "\"" -> (close quote)(quoted with \ ")(reopen quote) */
     487             :                                 if (p == end)
     488             :                                         goto bail;
     489             :                                 *p++ = '"';
     490             :                                 if (p == end)
     491             :                                         goto bail;
     492             :                                 *p++ = '\\';
     493             :                                 if (p == end)
     494             :                                         goto bail;
     495             :                                 *p++ = '"';
     496             :                                 if (p == end)
     497             :                                         goto bail;
     498             :                                 *p++ = '"';
     499             :                         } else {
     500             :                                 /* " -> \" */
     501             :                                 if (p == end)
     502             :                                         goto bail;
     503             :                                 *p++ = '\\';
     504             :                                 if (p == end)
     505             :                                         goto bail;
     506             :                                 *p++ = '"';
     507             :                         }
     508             :                         break;
     509             :                 case '&' :
     510             :                 case '|' :
     511             :                 case '(' :
     512             :                 case ')' :
     513             :                 case '<' :
     514             :                 case '>' :
     515             :                 case '^' :
     516             :                         /* reserved chars, they need to be quoted with ^ */
     517             :                         if (has_quote) {
     518             :                                 if (p == end)
     519             :                                         goto bail;
     520             :                                 *p++ = c;
     521             :                         } else {
     522             :                                 if (p == end)
     523             :                                         goto bail;
     524             :                                 *p++ = '^';
     525             :                                 if (p == end)
     526             :                                         goto bail;
     527             :                                 *p++ = c;
     528             :                         }
     529             :                         break;
     530             : #else
     531             :                 /* special chars that need to be quoted */
     532             :                 case ' ' : /* space */
     533             :                 case '~' : /* home */
     534             :                 case '`' : /* command */
     535             :                 case '#' : /* comment */
     536             :                 case '$' : /* variable */
     537             :                 case '&' : /* background job */
     538             :                 case '*' : /* wildcard */
     539             :                 case '(' : /* shell */
     540             :                 case ')' : /* shell */
     541             :                 case '\\': /* quote */
     542             :                 case '|' : /* pipe */
     543             :                 case '[' : /* wildcard */
     544             :                 case ']' : /* wildcard */
     545             :                 case '{' : /* code */
     546             :                 case '}' : /* code */
     547             :                 case ';' : /* separator */
     548             :                 case '\'': /* quote */
     549             :                 case '"' : /* quote */
     550             :                 case '<' : /* redirect */
     551             :                 case '>' : /* redirect */
     552             :                 case '?' : /* wildcard */
     553       79043 :                         if (p == end)
     554           0 :                                 goto bail;
     555       79043 :                         *p++ = '\\';
     556       79043 :                         if (p == end)
     557           0 :                                 goto bail;
     558       79043 :                         *p++ = c;
     559       79043 :                         break;
     560             : #endif
     561             :                 default :
     562             :                         /* unquoted */
     563     4690082 :                         if (p == end)
     564           0 :                                 goto bail;
     565     4690082 :                         *p++ = c;
     566     4690082 :                         break;
     567             :                 }
     568             : 
     569     4769125 :                 ++str;
     570     4769125 :         }
     571             : 
     572             : #ifdef _WIN32
     573             :         if (has_quote) {
     574             :                 if (p == end)
     575             :                         goto bail;
     576             :                 *p++ = '"';
     577             :         }
     578             : #endif
     579             : 
     580             :         /* put final 0 */
     581      356187 :         if (p == end)
     582           0 :                 goto bail;
     583      356187 :         *p = 0;
     584             : 
     585      712374 :         return begin;
     586             : 
     587             : bail:
     588             :         /* LCOV_EXCL_START */
     589             :         log_fatal("Escape for shell too long\n");
     590             :         exit(EXIT_FAILURE);
     591             :         /* LCOV_EXCL_STOP */
     592             : }
     593             : 
     594           0 : char* strpolish(char* s)
     595             : {
     596           0 :         char* i = s;
     597             : 
     598           0 :         while (*i) {
     599           0 :                 if (isspace(*i) || !isprint(*i))
     600           0 :                         *i = ' ';
     601           0 :                 ++i;
     602             :         }
     603             : 
     604           0 :         return s;
     605             : }
     606             : 
     607        1576 : unsigned strsplit(char** split_map, unsigned split_max, char* str, const char* delimiters)
     608             : {
     609        1576 :         unsigned mac = 0;
     610             : 
     611             :         /* skip initial delimiters */
     612        1576 :         str += strspn(str, delimiters);
     613             : 
     614        9608 :         while (*str != 0 || mac == split_max) {
     615             :                 /* start of the token */
     616        6456 :                 split_map[mac] = str;
     617        6456 :                 ++mac;
     618             : 
     619             :                 /* find the first delimiter or the end of the string */
     620        6456 :                 str += strcspn(str, delimiters);
     621             : 
     622             :                 /* put the final terminator if missing */
     623        6456 :                 if (*str != 0)
     624        5032 :                         *str++ = 0;
     625             : 
     626             :                 /* skip trailing delimiters */
     627        6456 :                 str += strspn(str, delimiters);
     628             :         }
     629             : 
     630        1576 :         return mac;
     631             : }
     632             : 
     633             : /****************************************************************************/
     634             : /* path */
     635             : 
     636     7877913 : void pathcpy(char* dst, size_t size, const char* src)
     637             : {
     638     7877913 :         size_t len = strlen(src);
     639             : 
     640     7877913 :         if (len + 1 > size) {
     641             :                 /* LCOV_EXCL_START */
     642             :                 log_fatal("Path too long '%s'\n", src);
     643             :                 os_abort();
     644             :                 /* LCOV_EXCL_STOP */
     645             :         }
     646             : 
     647     7877913 :         memcpy(dst, src, len + 1);
     648     7877913 : }
     649             : 
     650         267 : void pathcat(char* dst, size_t size, const char* src)
     651             : {
     652         267 :         size_t dst_len = strlen(dst);
     653         267 :         size_t src_len = strlen(src);
     654             : 
     655         267 :         if (dst_len + src_len + 1 > size) {
     656             :                 /* LCOV_EXCL_START */
     657             :                 log_fatal("Path too long '%s%s'\n", dst, src);
     658             :                 os_abort();
     659             :                 /* LCOV_EXCL_STOP */
     660             :         }
     661             : 
     662         267 :         memcpy(dst + dst_len, src, src_len + 1);
     663         267 : }
     664             : 
     665         788 : void pathcatc(char* dst, size_t size, char c)
     666             : {
     667         788 :         size_t dst_len = strlen(dst);
     668             : 
     669         788 :         if (dst_len + 2 > size) {
     670             :                 /* LCOV_EXCL_START */
     671             :                 log_fatal("Path too long '%s%c'\n", dst, c);
     672             :                 os_abort();
     673             :                 /* LCOV_EXCL_STOP */
     674             :         }
     675             : 
     676         788 :         dst[dst_len] = c;
     677         788 :         dst[dst_len + 1] = 0;
     678         788 : }
     679             : 
     680       16572 : void pathimport(char* dst, size_t size, const char* src)
     681             : {
     682       16572 :         pathcpy(dst, size, src);
     683             : 
     684             : #ifdef _WIN32
     685             :         /* convert the  Windows dir separator '\' to C '/', */
     686             :         /* and the Windows escaping  char '^' to the fnmatch '\' */
     687             :         while (*dst) {
     688             :                 switch (*dst) {
     689             :                 case '\\' :
     690             :                         *dst = '/';
     691             :                         break;
     692             :                 case '^' :
     693             :                         *dst = '\\';
     694             :                         break;
     695             :                 }
     696             :                 ++dst;
     697             :         }
     698             : #endif
     699       16572 : }
     700             : 
     701       12234 : void pathexport(char* dst, size_t size, const char* src)
     702             : {
     703       12234 :         pathcpy(dst, size, src);
     704             : 
     705             : #ifdef _WIN32
     706             :         /* invert the import */
     707             :         while (*dst) {
     708             :                 switch (*dst) {
     709             :                 case '/' :
     710             :                         *dst = '\\';
     711             :                         break;
     712             :                 case '\\' :
     713             :                         *dst = '^';
     714             :                         break;
     715             :                 }
     716             :                 ++dst;
     717             :         }
     718             : #endif
     719       12234 : }
     720             : 
     721    51583265 : void pathprint(char* dst, size_t size, const char* format, ...)
     722             : {
     723             :         size_t len;
     724             :         va_list ap;
     725             : 
     726    51583265 :         va_start(ap, format);
     727    51583265 :         len = vsnprintf(dst, size, format, ap);
     728    51583265 :         va_end(ap);
     729             : 
     730    51583265 :         if (len >= size) {
     731             :                 /* LCOV_EXCL_START */
     732             :                 if (size > 0) {
     733             :                         dst[size - 1] = 0;
     734             :                         log_fatal("Path too long '%s...'\n", dst);
     735             :                 } else {
     736             :                         log_fatal("Path too long for empty size'\n");
     737             :                 }
     738             :                 os_abort();
     739             :                 /* LCOV_EXCL_STOP */
     740             :         }
     741    51583265 : }
     742             : 
     743        7707 : void pathslash(char* dst, size_t size)
     744             : {
     745        7707 :         size_t len = strlen(dst);
     746             : 
     747        7707 :         if (len > 0 && dst[len - 1] != '/') {
     748        6116 :                 if (len + 2 >= size) {
     749             :                         /* LCOV_EXCL_START */
     750             :                         log_fatal("Path too long '%s/'\n", dst);
     751             :                         os_abort();
     752             :                         /* LCOV_EXCL_STOP */
     753             :                 }
     754             : 
     755        6116 :                 dst[len] = '/';
     756        6116 :                 dst[len + 1] = 0;
     757             :         }
     758        7707 : }
     759             : 
     760         100 : void pathcut(char* dst)
     761             : {
     762         100 :         char* slash = strrchr(dst, '/');
     763             : 
     764         100 :         if (slash)
     765         100 :                 slash[1] = 0;
     766             :         else
     767           0 :                 dst[0] = 0;
     768         100 : }
     769             : 
     770    51887573 : int pathcmp(const char* a, const char* b)
     771             : {
     772             : #ifdef _WIN32
     773             :         char ai[PATH_MAX];
     774             :         char bi[PATH_MAX];
     775             : 
     776             :         /* import to convert \ to / */
     777             :         pathimport(ai, sizeof(ai), a);
     778             :         pathimport(bi, sizeof(bi), b);
     779             : 
     780             :         /* case insensitive compare in Windows */
     781             :         return stricmp(ai, bi);
     782             : #else
     783    51887573 :         return strcmp(a, b);
     784             : #endif
     785             : }
     786             : 
     787             : /****************************************************************************/
     788             : /* file-system */
     789             : 
     790      787691 : int mkancestor(const char* file)
     791             : {
     792             :         char dir[PATH_MAX];
     793             :         struct stat st;
     794             :         char* c;
     795             : 
     796      787691 :         pathcpy(dir, sizeof(dir), file);
     797             : 
     798      787691 :         c = strrchr(dir, '/');
     799      787691 :         if (!c) {
     800             :                 /* no ancestor */
     801           0 :                 return 0;
     802             :         }
     803             : 
     804             :         /* clear the file */
     805      787691 :         *c = 0;
     806             : 
     807             :         /* if it's the root dir */
     808      787691 :         if (*dir == 0) {
     809             :                 /* nothing more to do */
     810           0 :                 return 0;
     811             :         }
     812             : 
     813             : #ifdef _WIN32
     814             :         /* if it's a drive specificaion like "C:" */
     815             :         if (isalpha(dir[0]) && dir[1] == ':' && dir[2] == 0) {
     816             :                 /* nothing more to do */
     817             :                 return 0;
     818             :         }
     819             : #endif
     820             : 
     821             :         /*
     822             :          * Check if the dir already exists using lstat().
     823             :          *
     824             :          * Note that in Windows when dealing with read-only media
     825             :          * you cannot try to create the directory, and expecting
     826             :          * the EEXIST error because the call will fail with ERROR_WRITE_PROTECTED.
     827             :          *
     828             :          * Also in Windows it's better to use lstat() than stat() because it
     829             :          * doesn't need to open the dir with CreateFile().
     830             :          */
     831      787691 :         if (lstat(dir, &st) == 0) {
     832             :                 /* it already exists */
     833      787613 :                 return 0;
     834             :         }
     835             : 
     836             :         /* recursively create them all */
     837          78 :         if (mkancestor(dir) != 0) {
     838             :                 /* LCOV_EXCL_START */
     839             :                 return -1;
     840             :                 /* LCOV_EXCL_STOP */
     841             :         }
     842             : 
     843             :         /* create it */
     844          78 :         if (mkdir(dir, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) != 0) {
     845             :                 /* LCOV_EXCL_START */
     846             :                 log_fatal("Error creating directory '%s'. %s.\n", dir, strerror(errno));
     847             :                 return -1;
     848             :                 /* LCOV_EXCL_STOP */
     849             :         }
     850             : 
     851          78 :         return 0;
     852             : }
     853             : 
     854      119633 : int fmtime(int f, int64_t mtime_sec, int mtime_nsec)
     855             : {
     856             : #if HAVE_FUTIMENS
     857             :         struct timespec tv[2];
     858             : #else
     859             :         struct timeval tv[2];
     860             : #endif
     861             :         int ret;
     862             : 
     863             : #if HAVE_FUTIMENS /* futimens() is preferred because it gives nanosecond precision */
     864      119633 :         tv[0].tv_sec = mtime_sec;
     865      119633 :         if (mtime_nsec != STAT_NSEC_INVALID)
     866      119633 :                 tv[0].tv_nsec = mtime_nsec;
     867             :         else
     868           0 :                 tv[0].tv_nsec = 0;
     869      119633 :         tv[1].tv_sec = tv[0].tv_sec;
     870      119633 :         tv[1].tv_nsec = tv[0].tv_nsec;
     871             : 
     872      119633 :         ret = futimens(f, tv);
     873             : #elif HAVE_FUTIMES /* fallback to futimes() if nanosecond precision is not available */
     874             :         tv[0].tv_sec = mtime_sec;
     875             :         if (mtime_nsec != STAT_NSEC_INVALID)
     876             :                 tv[0].tv_usec = mtime_nsec / 1000;
     877             :         else
     878             :                 tv[0].tv_usec = 0;
     879             :         tv[1].tv_sec = tv[0].tv_sec;
     880             :         tv[1].tv_usec = tv[0].tv_usec;
     881             : 
     882             :         ret = futimes(f, tv);
     883             : #elif HAVE_FUTIMESAT /* fallback to futimesat() for Solaris, it only has futimesat() */
     884             :         tv[0].tv_sec = mtime_sec;
     885             :         if (mtime_nsec != STAT_NSEC_INVALID)
     886             :                 tv[0].tv_usec = mtime_nsec / 1000;
     887             :         else
     888             :                 tv[0].tv_usec = 0;
     889             :         tv[1].tv_sec = tv[0].tv_sec;
     890             :         tv[1].tv_usec = tv[0].tv_usec;
     891             : 
     892             :         ret = futimesat(f, 0, tv);
     893             : #else
     894             : #error No function available to set file timestamps with sub-second precision
     895             : #endif
     896             : 
     897      119633 :         return ret;
     898             : }
     899             : 
     900       11645 : int lmtime(const char* path, int64_t mtime_sec, int mtime_nsec)
     901             : {
     902             : #if HAVE_UTIMENSAT
     903             :         struct timespec tv[2];
     904             : #else
     905             :         struct timeval tv[2];
     906             : #endif
     907             :         int ret;
     908             : 
     909             : #if HAVE_UTIMENSAT /* utimensat() is preferred because it gives nanosecond precision */
     910       11645 :         tv[0].tv_sec = mtime_sec;
     911       11645 :         if (mtime_nsec != STAT_NSEC_INVALID)
     912       11645 :                 tv[0].tv_nsec = mtime_nsec;
     913             :         else
     914           0 :                 tv[0].tv_nsec = 0;
     915       11645 :         tv[1].tv_sec = tv[0].tv_sec;
     916       11645 :         tv[1].tv_nsec = tv[0].tv_nsec;
     917             : 
     918       11645 :         ret = utimensat(AT_FDCWD, path, tv, AT_SYMLINK_NOFOLLOW);
     919             : #elif HAVE_LUTIMES /* fallback to lutimes() if nanosecond precision is not available */
     920             :         tv[0].tv_sec = mtime_sec;
     921             :         if (mtime_nsec != STAT_NSEC_INVALID)
     922             :                 tv[0].tv_usec = mtime_nsec / 1000;
     923             :         else
     924             :                 tv[0].tv_usec = 0;
     925             :         tv[1].tv_sec = tv[0].tv_sec;
     926             :         tv[1].tv_usec = tv[0].tv_usec;
     927             : 
     928             :         ret = lutimes(path, tv);
     929             : #elif HAVE_FUTIMESAT /* fallback to futimesat() for Solaris, it only has futimesat() */
     930             :         tv[0].tv_sec = mtime_sec;
     931             :         if (mtime_nsec != STAT_NSEC_INVALID)
     932             :                 tv[0].tv_usec = mtime_nsec / 1000;
     933             :         else
     934             :                 tv[0].tv_usec = 0;
     935             :         tv[1].tv_sec = tv[0].tv_sec;
     936             :         tv[1].tv_usec = tv[0].tv_usec;
     937             : 
     938             :         ret = futimesat(AT_FDCWD, path, tv);
     939             : #else
     940             : #error No function available to set file timestamps with sub-second precision
     941             : #endif
     942             : 
     943       11645 :         return ret;
     944             : }
     945             : 
     946             : /****************************************************************************/
     947             : /* advise */
     948             : 
     949     2492271 : void advise_init(struct advise_struct* advise, int mode)
     950             : {
     951     2492271 :         advise->mode = mode;
     952     2492271 :         advise->dirty_begin = 0;
     953     2492271 :         advise->dirty_end = 0;
     954     2492271 : }
     955             : 
     956     2494305 : int advise_flags(struct advise_struct* advise)
     957             : {
     958     2494305 :         int flags = 0;
     959             : 
     960     2494305 :         if (advise->mode == ADVISE_SEQUENTIAL
     961     2482498 :                 || advise->mode == ADVISE_FLUSH
     962       33857 :                 || advise->mode == ADVISE_FLUSH_WINDOW
     963       22598 :                 || advise->mode == ADVISE_DISCARD
     964       22607 :                 || advise->mode == ADVISE_DISCARD_WINDOW
     965             :         )
     966     2482594 :                 flags |= O_SEQUENTIAL;
     967             : 
     968             : #if HAVE_DIRECT_IO
     969     2494305 :         if (advise->mode == ADVISE_DIRECT)
     970           0 :                 flags |= O_DIRECT;
     971             : #endif
     972             : 
     973     2494305 :         return flags;
     974             : }
     975             : 
     976     2406929 : int advise_open(struct advise_struct* advise, int f)
     977             : {
     978             :         (void)advise;
     979             :         (void)f;
     980             : 
     981             : #if HAVE_POSIX_FADVISE
     982     2406929 :         if (advise->mode == ADVISE_SEQUENTIAL
     983     2400310 :                 || advise->mode == ADVISE_FLUSH
     984       33645 :                 || advise->mode == ADVISE_FLUSH_WINDOW
     985       22352 :                 || advise->mode == ADVISE_DISCARD
     986       22437 :                 || advise->mode == ADVISE_DISCARD_WINDOW
     987             :         ) {
     988             :                 int ret;
     989             : 
     990             :                 /* advise sequential access */
     991     2399097 :                 ret = posix_fadvise(f, 0, 0, POSIX_FADV_SEQUENTIAL);
     992     2401786 :                 if (ret == ENOSYS) {
     993             :                         /* call is not supported, like in armhf, see posix_fadvise manpage */
     994           0 :                         ret = 0;
     995             :                 }
     996     2401786 :                 if (ret != 0) {
     997             :                         /* LCOV_EXCL_START */
     998             :                         errno = ret; /* posix_fadvise return the error code */
     999             :                         return -1;
    1000             :                         /* LCOV_EXCL_STOP */
    1001             :                 }
    1002             :         }
    1003             : #endif
    1004             : 
    1005     2409618 :         return 0;
    1006             : }
    1007             : 
    1008      892211 : int advise_write(struct advise_struct* advise, int f, data_off_t offset, data_off_t size)
    1009             : {
    1010             :         data_off_t flush_offset;
    1011             :         data_off_t flush_size;
    1012             :         data_off_t discard_offset;
    1013             :         data_off_t discard_size;
    1014             : 
    1015             :         (void)f;
    1016             :         (void)flush_offset;
    1017             :         (void)flush_size;
    1018             :         (void)discard_offset;
    1019             :         (void)discard_size;
    1020             : 
    1021      892211 :         flush_offset = 0;
    1022      892211 :         flush_size = 0;
    1023      892211 :         discard_offset = 0;
    1024      892211 :         discard_size = 0;
    1025             : 
    1026             :         /*
    1027             :          * Follow Linus recommendations about fast writes.
    1028             :          *
    1029             :          * Linus "Unexpected splice "always copy" behavior observed"
    1030             :          * http://thread.gmane.org/gmane.linux.kernel/987247/focus=988070
    1031             :          * ---
    1032             :          * I have had _very_ good experiences with even a rather trivial
    1033             :          * file writer that basically used (iirc) 8MB windows, and the logic was very
    1034             :          * trivial:
    1035             :          *
    1036             :          *  - before writing a new 8M window, do "start writeback"
    1037             :          *    (SYNC_FILE_RANGE_WRITE) on the previous window, and do
    1038             :          *    a wait (SYNC_FILE_RANGE_WAIT_AFTER) on the window before that.
    1039             :          *
    1040             :          * in fact, in its simplest form, you can do it like this (this is from my
    1041             :          * "overwrite disk images" program that I use on old disks):
    1042             :          *
    1043             :          * for (index = 0; index < max_index ;index++) {
    1044             :          *   if (write(fd, buffer, BUFSIZE) != BUFSIZE)
    1045             :          *     break;
    1046             :          *   // This won't block, but will start writeout asynchronously
    1047             :          *   sync_file_range(fd, index*BUFSIZE, BUFSIZE, SYNC_FILE_RANGE_WRITE);
    1048             :          *   // This does a blocking write-and-wait on any old ranges
    1049             :          *   if (index)
    1050             :          *     sync_file_range(fd, (index-1)*BUFSIZE, BUFSIZE, SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE|SYNC_FILE_RANGE_WAIT_AFTER);
    1051             :          * }
    1052             :          *
    1053             :          * and even if you don't actually do a discard (maybe we should add a
    1054             :          * SYNC_FILE_RANGE_DISCARD bit, right now you'd need to do a separate
    1055             :          * fadvise(FADV_DONTNEED) to throw it out) the system behavior is pretty
    1056             :          * nice, because the heavy writer gets good IO performance _and_ leaves only
    1057             :          * easy-to-free pages around after itself.
    1058             :          * ---
    1059             :          *
    1060             :          * Linus "Unexpected splice "always copy" behavior observed"
    1061             :          * http://thread.gmane.org/gmane.linux.kernel/987247/focus=988176
    1062             :          * ---
    1063             :          * The behavior for dirty page writeback is _not_ well defined, and
    1064             :          * if you do POSIX_FADV_DONTNEED, I would suggest you do it as part of that
    1065             :          * writeback logic, ie you do it only on ranges that you have just waited on.
    1066             :          *
    1067             :          * IOW, in my example, you'd couple the
    1068             :          *
    1069             :          *   sync_file_range(fd, (index-1)*BUFSIZE, BUFSIZE, SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE|SYNC_FILE_RANGE_WAIT_AFTER);
    1070             :          *
    1071             :          * with a
    1072             :          *
    1073             :          *   posix_fadvise(fd, (index-1)*BUFSIZE, BUFSIZE, POSIX_FADV_DONTNEED);
    1074             :          *
    1075             :          * afterwards to throw out the pages that you just waited for.
    1076             :          * ---
    1077             :          */
    1078             : 
    1079      892211 :         switch (advise->mode) {
    1080             :         case ADVISE_FLUSH :
    1081      876331 :                 flush_offset = offset;
    1082      876331 :                 flush_size = size;
    1083      876331 :                 break;
    1084             :         case ADVISE_DISCARD :
    1085           0 :                 discard_offset = offset;
    1086           0 :                 discard_size = size;
    1087           0 :                 break;
    1088             :         case ADVISE_FLUSH_WINDOW :
    1089             :                 /* if the dirty range can be extended */
    1090        4687 :                 if (advise->dirty_end == offset) {
    1091             :                         /* extent the dirty range */
    1092        4687 :                         advise->dirty_end += size;
    1093             : 
    1094             :                         /* if we reached the window size */
    1095        4687 :                         if (advise->dirty_end - advise->dirty_begin >= ADVISE_WINDOW_SIZE) {
    1096             :                                 /* flush the window  */
    1097           0 :                                 flush_offset = advise->dirty_begin;
    1098           0 :                                 flush_size = ADVISE_WINDOW_SIZE;
    1099             : 
    1100             :                                 /* remove it from the dirty range */
    1101           0 :                                 advise->dirty_begin += ADVISE_WINDOW_SIZE;
    1102             :                         }
    1103             :                 } else {
    1104             :                         /* otherwise flush the existing dirty */
    1105           0 :                         flush_offset = advise->dirty_begin;
    1106           0 :                         flush_size = advise->dirty_end - advise->dirty_begin;
    1107             : 
    1108             :                         /* and set the new range as dirty */
    1109           0 :                         advise->dirty_begin = offset;
    1110           0 :                         advise->dirty_end = offset + size;
    1111             :                 }
    1112        4687 :                 break;
    1113             :         case ADVISE_DISCARD_WINDOW :
    1114             :                 /* if the dirty range can be extended */
    1115        4687 :                 if (advise->dirty_end == offset) {
    1116             :                         /* extent the dirty range */
    1117        4687 :                         advise->dirty_end += size;
    1118             : 
    1119             :                         /* if we reached the double window size */
    1120        4687 :                         if (advise->dirty_end - advise->dirty_begin >= 2 * ADVISE_WINDOW_SIZE) {
    1121             :                                 /* discard the first window */
    1122           0 :                                 discard_offset = advise->dirty_begin;
    1123           0 :                                 discard_size = ADVISE_WINDOW_SIZE;
    1124             : 
    1125             :                                 /* remove it from the dirty range */
    1126           0 :                                 advise->dirty_begin += ADVISE_WINDOW_SIZE;
    1127             : 
    1128             :                                 /* flush the second window */
    1129           0 :                                 flush_offset = advise->dirty_begin;
    1130           0 :                                 flush_size = ADVISE_WINDOW_SIZE;
    1131             :                         }
    1132             :                 } else {
    1133             :                         /* otherwise discard the existing dirty */
    1134           0 :                         discard_offset = advise->dirty_begin;
    1135           0 :                         discard_size = advise->dirty_end - advise->dirty_begin;
    1136             : 
    1137             :                         /* and set the new range as dirty */
    1138           0 :                         advise->dirty_begin = offset;
    1139           0 :                         advise->dirty_end = offset + size;
    1140             :                 }
    1141        4687 :                 break;
    1142             :         }
    1143             : 
    1144             : #if HAVE_SYNC_FILE_RANGE
    1145      892211 :         if (flush_size != 0) {
    1146             :                 int ret;
    1147             : 
    1148             :                 /* start writing immediately */
    1149      875675 :                 ret = sync_file_range(f, flush_offset, flush_size, SYNC_FILE_RANGE_WRITE);
    1150      880221 :                 if (ret != 0) {
    1151             :                         /* LCOV_EXCL_START */
    1152             :                         return -1;
    1153             :                         /* LCOV_EXCL_STOP */
    1154             :                 }
    1155             :         }
    1156             : #endif
    1157             : 
    1158             : #if HAVE_SYNC_FILE_RANGE && HAVE_POSIX_FADVISE
    1159      896757 :         if (discard_size != 0) {
    1160             :                 int ret;
    1161             : 
    1162             :                 /* send the data to the disk and wait until it's written */
    1163           0 :                 ret = sync_file_range(f, discard_offset, discard_size, SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE | SYNC_FILE_RANGE_WAIT_AFTER);
    1164           0 :                 if (ret != 0) {
    1165             :                         /* LCOV_EXCL_START */
    1166             :                         return -1;
    1167             :                         /* LCOV_EXCL_STOP */
    1168             :                 }
    1169             : 
    1170             :                 /* flush the data from the cache */
    1171           0 :                 ret = posix_fadvise(f, discard_offset, discard_size, POSIX_FADV_DONTNEED);
    1172             :                 /* for POSIX_FADV_DONTNEED we don't allow failure with ENOSYS */
    1173           0 :                 if (ret != 0) {
    1174             :                         /* LCOV_EXCL_START */
    1175             :                         errno = ret; /* posix_fadvise return the error code */
    1176             :                         return -1;
    1177             :                         /* LCOV_EXCL_STOP */
    1178             :                 }
    1179             :         }
    1180             : #endif
    1181             : 
    1182      896757 :         return 0;
    1183             : }
    1184             : 
    1185     8898102 : int advise_read(struct advise_struct* advise, int f, data_off_t offset, data_off_t size)
    1186             : {
    1187             :         (void)advise;
    1188             :         (void)f;
    1189             :         (void)offset;
    1190             :         (void)size;
    1191             : 
    1192             : #if HAVE_POSIX_FADVISE
    1193     8898102 :         if (advise->mode == ADVISE_DISCARD
    1194     8900394 :                 || advise->mode == ADVISE_DISCARD_WINDOW
    1195             :         ) {
    1196             :                 int ret;
    1197             : 
    1198             :                 /* flush the data from the cache */
    1199       27314 :                 ret = posix_fadvise(f, offset, size, POSIX_FADV_DONTNEED);
    1200             :                 /* for POSIX_FADV_DONTNEED we don't allow failure with ENOSYS */
    1201       27325 :                 if (ret != 0) {
    1202             :                         /* LCOV_EXCL_START */
    1203             :                         errno = ret; /* posix_fadvise return the error code */
    1204             :                         return -1;
    1205             :                         /* LCOV_EXCL_STOP */
    1206             :                 }
    1207             :         }
    1208             : #endif
    1209             : 
    1210             :         /*
    1211             :          * Here we cannot call posix_fadvise(..., POSIX_FADV_WILLNEED) for the next block
    1212             :          * because it may be blocking.
    1213             :          *
    1214             :          * Ted Ts'o "posix_fadvise(POSIX_FADV_WILLNEED) waits before returning?"
    1215             :          * https://lkml.org/lkml/2010/12/6/122
    1216             :          * ---
    1217             :          * readahead and posix_fadvise(POSIX_FADV_WILLNEED) work exactly the same
    1218             :          * way, and in fact share mostly the same code path (see
    1219             :          * force_page_cache_readahead() in mm/readahead.c).
    1220             :          *
    1221             :          * They are asynchronous in that there is no guarantee the pages will be
    1222             :          * in the page cache by the time they return.  But at the same time, they
    1223             :          * are not guaranteed to be non-blocking.  That is, the work of doing the
    1224             :          * readahead does not take place in a kernel thread.  So if you try to
    1225             :          * request I/O than will fit in the request queue, the system call will
    1226             :          * block until some I/O is completed so that more I/O requested cam be
    1227             :          * loaded onto the request queue.
    1228             :          *
    1229             :          * The only way to fix this would be to either put the work on a kernel
    1230             :          * thread (i.e., some kind of workqueue) or in a userspace thread.  For
    1231             :          * ion programmer wondering what to do today, I'd suggest the
    1232             :          * latter since it will be more portable across various kernel versions.
    1233             :          *
    1234             :          * This does leave the question about whether we should change the kernel
    1235             :          * to allow readahead() and posix_fadvise(POSIX_FADV_WILLNEED) to be
    1236             :          * non-blocking and do this work in a workqueue (or via some kind of
    1237             :          * callback/continuation scheme).  My worry is just doing this if a user
    1238             :          * application does something crazy, like request gigabytes and gigabytes
    1239             :          * of readahead, and then repents of their craziness, there should be a
    1240             :          * way of cancelling the readahead request.  Today, the user can just
    1241             :          * kill the application.  But if we simply shove the work to a kernel
    1242             :          * thread, it becomes a lot harder to cancel the readahead request.  We'd
    1243             :          * have to invent a new API, and then have a way to know whether the user
    1244             :          * has access to kill a particular readahead request, etc.
    1245             :          * ---
    1246             :          */
    1247             : 
    1248     8898113 :         return 0;
    1249             : }
    1250             : 
    1251             : /****************************************************************************/
    1252             : /* memory */
    1253             : 
    1254             : /**
    1255             :  * Total amount of memory allocated.
    1256             :  */
    1257             : static size_t mcounter;
    1258             : 
    1259         476 : size_t malloc_counter_get(void)
    1260             : {
    1261             :         size_t ret;
    1262             : 
    1263         476 :         lock_memory();
    1264             : 
    1265         476 :         ret = mcounter;
    1266             : 
    1267         476 :         unlock_memory();
    1268             : 
    1269         476 :         return ret;
    1270             : }
    1271             : 
    1272    20178277 : void malloc_counter_inc(size_t inc)
    1273             : {
    1274    20178277 :         lock_memory();
    1275             : 
    1276    20178277 :         mcounter += inc;
    1277             : 
    1278    20178277 :         unlock_memory();
    1279    20178277 : }
    1280             : 
    1281             : /* LCOV_EXCL_START */
    1282             : static ssize_t malloc_print(int f, const char* str)
    1283             : {
    1284             :         ssize_t len = 0;
    1285             : 
    1286             :         while (str[len])
    1287             :                 ++len;
    1288             :         return write(f, str, len);
    1289             : }
    1290             : /* LCOV_EXCL_STOP */
    1291             : 
    1292             : /* LCOV_EXCL_START */
    1293             : static ssize_t malloc_printn(int f, size_t value)
    1294             : {
    1295             :         char buf[32];
    1296             :         int i;
    1297             : 
    1298             :         if (!value)
    1299             :                 return write(f, "0", 1);
    1300             : 
    1301             :         i = sizeof(buf);
    1302             :         while (value) {
    1303             :                 buf[--i] = (value % 10) + '0';
    1304             :                 value /= 10;
    1305             :         }
    1306             : 
    1307             :         return write(f, buf + i, sizeof(buf) - i);
    1308             : }
    1309             : /* LCOV_EXCL_STOP */
    1310             : 
    1311             : /* LCOV_EXCL_START */
    1312             : void malloc_fail(size_t size)
    1313             : {
    1314             :         /* don't use printf to avoid any possible extra allocation */
    1315             :         int f = 2; /* stderr */
    1316             : 
    1317             :         malloc_print(f, "Failed for Low Memory!\n");
    1318             :         malloc_print(f, "Allocating ");
    1319             :         malloc_printn(f, size);
    1320             :         malloc_print(f, " bytes.\n");
    1321             :         malloc_print(f, "Already allocated ");
    1322             :         malloc_printn(f, malloc_counter_get());
    1323             :         malloc_print(f, " bytes.\n");
    1324             :         if (sizeof(void*) == 4) {
    1325             :                 malloc_print(f, "You are currently using a 32 bits executable.\n");
    1326             :                 malloc_print(f, "If you have more than 4GB of memory, please upgrade to a 64 bits one.\n");
    1327             :         }
    1328             : }
    1329             : /* LCOV_EXCL_STOP */
    1330             : 
    1331    14369210 : void* malloc_nofail(size_t size)
    1332             : {
    1333    14369210 :         void* ptr = malloc(size);
    1334             : 
    1335    14369210 :         if (!ptr) {
    1336             :                 /* LCOV_EXCL_START */
    1337             :                 malloc_fail(size);
    1338             :                 exit(EXIT_FAILURE);
    1339             :                 /* LCOV_EXCL_STOP */
    1340             :         }
    1341             : 
    1342             : #ifndef CHECKER /* Don't preinitialize when running for valgrind */
    1343             :         /* Here we preinitialize the memory to ensure that the OS is really allocating it */
    1344             :         /* and not only reserving the addressable space. */
    1345             :         /* Otherwise we are risking that the OOM (Out Of Memory) killer in Linux will kill the process. */
    1346             :         /* Filling the memory doesn't ensure to disable OOM, but it increase a lot the chances to */
    1347             :         /* get a real error from malloc() instead than a process killed. */
    1348             :         /* Note that calloc() doesn't have the same effect. */
    1349    14369210 :         memset(ptr, 0xA5, size);
    1350             : #endif
    1351             : 
    1352    14369210 :         malloc_counter_inc(size);
    1353             : 
    1354    14369210 :         return ptr;
    1355             : }
    1356             : 
    1357       10092 : void* calloc_nofail(size_t count, size_t size)
    1358             : {
    1359             :         void* ptr;
    1360             : 
    1361       10092 :         size *= count;
    1362             : 
    1363             :         /* see the note in malloc_nofail() of why we don't use calloc() */
    1364       10092 :         ptr = malloc(size);
    1365             : 
    1366       10092 :         if (!ptr) {
    1367             :                 /* LCOV_EXCL_START */
    1368             :                 malloc_fail(size);
    1369             :                 exit(EXIT_FAILURE);
    1370             :                 /* LCOV_EXCL_STOP */
    1371             :         }
    1372             : 
    1373       10092 :         memset(ptr, 0, size);
    1374             : 
    1375       10092 :         malloc_counter_inc(size);
    1376             : 
    1377       10092 :         return ptr;
    1378             : }
    1379             : 
    1380     5798975 : char* strdup_nofail(const char* str)
    1381             : {
    1382             :         size_t size;
    1383             :         char* ptr;
    1384             : 
    1385     5798975 :         size = strlen(str) + 1;
    1386             : 
    1387     5798975 :         ptr = malloc(size);
    1388             : 
    1389     5798975 :         if (!ptr) {
    1390             :                 /* LCOV_EXCL_START */
    1391             :                 malloc_fail(size);
    1392             :                 exit(EXIT_FAILURE);
    1393             :                 /* LCOV_EXCL_STOP */
    1394             :         }
    1395             : 
    1396     5798975 :         memcpy(ptr, str, size);
    1397             : 
    1398     5798975 :         malloc_counter_inc(size);
    1399             : 
    1400     5798975 :         return ptr;
    1401             : }
    1402             : 
    1403             : /****************************************************************************/
    1404             : /* smartctl */
    1405             : 
    1406             : /**
    1407             :  * Match a string with the specified pattern.
    1408             :  * Like sscanf() a space match any sequence of spaces.
    1409             :  * Return 0 if it matches.
    1410             :  */
    1411           0 : static int smatch(const char* str, const char* pattern)
    1412             : {
    1413           0 :         while (*pattern) {
    1414           0 :                 if (isspace(*pattern)) {
    1415           0 :                         ++pattern;
    1416           0 :                         while (isspace(*str))
    1417           0 :                                 ++str;
    1418           0 :                 } else if (*pattern == *str) {
    1419           0 :                         ++pattern;
    1420           0 :                         ++str;
    1421             :                 } else
    1422           0 :                         return -1;
    1423             :         }
    1424             : 
    1425           0 :         return 0;
    1426             : }
    1427             : 
    1428          43 : int smartctl_attribute(FILE* f, const char* file, const char* name, uint64_t* smart, char* serial, char* vendor, char* model)
    1429             : {
    1430             :         unsigned i;
    1431             :         int inside;
    1432             : 
    1433             :         /* preclear attribute */
    1434          43 :         *serial = 0;
    1435       11223 :         for (i = 0; i < SMART_COUNT; ++i)
    1436       11180 :                 smart[i] = SMART_UNASSIGNED;
    1437             : 
    1438             :         /* read the file */
    1439          43 :         inside = 0;
    1440             :         while (1) {
    1441             :                 char buf[256];
    1442             :                 unsigned id;
    1443             :                 uint64_t raw;
    1444             :                 char* s;
    1445             : 
    1446          43 :                 s = fgets(buf, sizeof(buf), f);
    1447          43 :                 if (s == 0)
    1448          43 :                         break;
    1449             : 
    1450             :                 /* remove extraneous chars */
    1451           0 :                 s = strpolish(buf);
    1452             : 
    1453           0 :                 log_tag("smartctl:%s:%s:out: %s\n", file, name, s);
    1454             : 
    1455             :                 /* skip initial spaces */
    1456           0 :                 while (isspace(*s))
    1457           0 :                         ++s;
    1458             : 
    1459           0 :                 if (*s == 0) {
    1460           0 :                         inside = 0;
    1461             :                 /* common */
    1462           0 :                 } else if (smatch(s, "Rotation Rate: Solid State") == 0) {
    1463           0 :                         smart[SMART_ROTATION_RATE] = 0;
    1464           0 :                 } else if (sscanf(s, "Rotation Rate: %" SCNu64, &smart[SMART_ROTATION_RATE]) == 1) {
    1465           0 :                 } else if (smatch(s, "User Capacity:") == 0) {
    1466           0 :                         char* begin = strchr(s, ':');
    1467           0 :                         char* end = strstr(s, "bytes");
    1468           0 :                         if (begin != 0 && end != 0 && begin < end) {
    1469             :                                 char* p;
    1470           0 :                                 smart[SMART_SIZE] = 0;
    1471           0 :                                 for (p = begin; p != end; ++p) {
    1472           0 :                                         if (isdigit(*p)) {
    1473           0 :                                                 smart[SMART_SIZE] *= 10;
    1474           0 :                                                 smart[SMART_SIZE] += *p - '0';
    1475             :                                         }
    1476             :                                 }
    1477             :                         }
    1478           0 :                 } else if (sscanf(s, "Device Model: %63s %63s", vendor, model) == 2) {
    1479           0 :                 } else if (sscanf(s, "Device Model: %63s", model) == 1) {
    1480             :                 /* SCSI */
    1481           0 :                 } else if (sscanf(s, "Serial number: %63s", serial) == 1) { /* note "n" of "number" lower case */
    1482           0 :                 } else if (sscanf(s, "Elements in grown defect list: %" SCNu64, &smart[SMART_REALLOCATED_SECTOR_COUNT]) == 1) {
    1483           0 :                 } else if (sscanf(s, "Current Drive Temperature: %" SCNu64, &smart[SMART_TEMPERATURE_CELSIUS]) == 1) {
    1484           0 :                 } else if (sscanf(s, "Drive Trip Temperature: %" SCNu64, &smart[SMART_AIRFLOW_TEMPERATURE_CELSIUS]) == 1) {
    1485           0 :                 } else if (sscanf(s, "Accumulated start-stop cycles: %" SCNu64, &smart[SMART_START_STOP_COUNT]) == 1) {
    1486           0 :                 } else if (sscanf(s, "Accumulated load-unload cycles: %" SCNu64, &smart[SMART_LOAD_CYCLE_COUNT]) == 1) {
    1487           0 :                 } else if (sscanf(s, "  number of hours powered up = %" SCNu64, &smart[SMART_POWER_ON_HOURS]) == 1) {
    1488             :                 /* ATA */
    1489           0 :                 } else if (sscanf(s, "Serial Number: %63s", serial) == 1) {
    1490           0 :                 } else if (smatch(s, "ID#") == 0) {
    1491           0 :                         inside = 1;
    1492           0 :                 } else if (smatch(s, "No Errors Logged") == 0) {
    1493           0 :                         smart[SMART_ERROR] = 0;
    1494           0 :                 } else if (sscanf(s, "ATA Error Count: %" SCNu64, &raw) == 1) {
    1495           0 :                         smart[SMART_ERROR] = raw;
    1496           0 :                 } else if (inside) {
    1497           0 :                         if (sscanf(s, "%u %*s %*s %*s %*s %*s %*s %*s %*s %" SCNu64, &id, &raw) != 2) {
    1498             :                                 /* LCOV_EXCL_START */
    1499             :                                 log_fatal("Invalid smartctl line '%s'.\n", s);
    1500             :                                 return -1;
    1501             :                                 /* LCOV_EXCL_STOP */
    1502             :                         }
    1503             : 
    1504           0 :                         if (id >= 256) {
    1505             :                                 /* LCOV_EXCL_START */
    1506             :                                 log_fatal("Invalid SMART id '%u'.\n", id);
    1507             :                                 return -1;
    1508             :                                 /* LCOV_EXCL_STOP */
    1509             :                         }
    1510             : 
    1511           0 :                         smart[id] = raw;
    1512             :                 }
    1513           0 :         }
    1514             : 
    1515          43 :         return 0;
    1516             : }
    1517             : 
    1518           5 : int smartctl_flush(FILE* f, const char* file, const char* name)
    1519             : {
    1520             :         /* read the file */
    1521             :         while (1) {
    1522             :                 char buf[256];
    1523             :                 char* s;
    1524             : 
    1525           5 :                 s = fgets(buf, sizeof(buf), f);
    1526           5 :                 if (s == 0)
    1527           5 :                         break;
    1528             : 
    1529             :                 /* remove extraneous chars */
    1530           0 :                 s = strpolish(buf);
    1531             : 
    1532           0 :                 log_tag("smartctl:%s:%s:out: %s\n", file, name, s);
    1533           0 :         }
    1534             : 
    1535          10 :         return 0;
    1536             : }
    1537             : 
    1538             : /****************************************************************************/
    1539             : /* thread */
    1540             : 
    1541             : #if HAVE_PTHREAD
    1542        2284 : void thread_mutex_init(pthread_mutex_t* mutex, pthread_mutexattr_t* attr)
    1543             : {
    1544        2284 :         if (pthread_mutex_init(mutex, attr) != 0) {
    1545             :                 /* LCOV_EXCL_START */
    1546             :                 log_fatal("Failed call to pthread_mutex_init().\n");
    1547             :                 os_abort();
    1548             :                 /* LCOV_EXCL_STOP */
    1549             :         }
    1550        2284 : }
    1551             : 
    1552        2082 : void thread_mutex_destroy(pthread_mutex_t* mutex)
    1553             : {
    1554        2082 :         if (pthread_mutex_destroy(mutex) != 0) {
    1555             :                 /* LCOV_EXCL_START */
    1556             :                 log_fatal("Failed call to pthread_mutex_destroy().\n");
    1557             :                 os_abort();
    1558             :                 /* LCOV_EXCL_STOP */
    1559             :         }
    1560        2082 : }
    1561             : 
    1562    80838743 : void thread_mutex_lock(pthread_mutex_t* mutex)
    1563             : {
    1564    80838743 :         if (pthread_mutex_lock(mutex) != 0) {
    1565             :                 /* LCOV_EXCL_START */
    1566             :                 log_fatal("Failed call to pthread_mutex_lock().\n");
    1567             :                 os_abort();
    1568             :                 /* LCOV_EXCL_STOP */
    1569             :         }
    1570    80868061 : }
    1571             : 
    1572    80856164 : void thread_mutex_unlock(pthread_mutex_t* mutex)
    1573             : {
    1574    80856164 :         if (pthread_mutex_unlock(mutex) != 0) {
    1575             :                 /* LCOV_EXCL_START */
    1576             :                 log_fatal("Failed call to pthread_mutex_unlock().\n");
    1577             :                 os_abort();
    1578             :                 /* LCOV_EXCL_STOP */
    1579             :         }
    1580    80864919 : }
    1581             : 
    1582         380 : void thread_cond_init(pthread_cond_t* cond, pthread_condattr_t* attr)
    1583             : {
    1584         380 :         if (pthread_cond_init(cond, attr) != 0) {
    1585             :                 /* LCOV_EXCL_START */
    1586             :                 log_fatal("Failed call to pthread_cond_init().\n");
    1587             :                 os_abort();
    1588             :                 /* LCOV_EXCL_STOP */
    1589             :         }
    1590         380 : }
    1591             : 
    1592         380 : void thread_cond_destroy(pthread_cond_t* cond)
    1593             : {
    1594         380 :         if (pthread_cond_destroy(cond) != 0) {
    1595             :                 /* LCOV_EXCL_START */
    1596             :                 log_fatal("Failed call to pthread_cond_destroy().\n");
    1597             :                 os_abort();
    1598             :                 /* LCOV_EXCL_STOP */
    1599             :         }
    1600         380 : }
    1601             : 
    1602        2069 : void thread_cond_signal(pthread_cond_t* cond)
    1603             : {
    1604        2069 :         if (pthread_cond_signal(cond) != 0) {
    1605             :                 /* LCOV_EXCL_START */
    1606             :                 log_fatal("Failed call to pthread_cond_signal().\n");
    1607             :                 os_abort();
    1608             :                 /* LCOV_EXCL_STOP */
    1609             :         }
    1610        2069 : }
    1611             : 
    1612      255557 : void thread_cond_broadcast(pthread_cond_t* cond)
    1613             : {
    1614      255557 :         if (pthread_cond_broadcast(cond) != 0) {
    1615             :                 /* LCOV_EXCL_START */
    1616             :                 log_fatal("Failed call to pthread_cond_broadcast().\n");
    1617             :                 os_abort();
    1618             :                 /* LCOV_EXCL_STOP */
    1619             :         }
    1620      255557 : }
    1621             : 
    1622     1308373 : void thread_cond_wait(pthread_cond_t* cond, pthread_mutex_t* mutex)
    1623             : {
    1624     1308373 :         if (pthread_cond_wait(cond, mutex) != 0) {
    1625             :                 /* LCOV_EXCL_START */
    1626             :                 log_fatal("Failed call to pthread_cond_wait().\n");
    1627             :                 os_abort();
    1628             :                 /* LCOV_EXCL_STOP */
    1629             :         }
    1630     1308373 : }
    1631             : 
    1632             : /**
    1633             :  * Implementation note about conditional variables.
    1634             :  *
    1635             :  * The conditional variables can be signaled inside or ouside the mutex,
    1636             :  * what is better it's debatable but in general doing that ouside the mutex,
    1637             :  * reduces the number of context switches.
    1638             :  *
    1639             :  * But when when testing with helgrind and drd, this disallows such tools to
    1640             :  * to see the dependency between the signal and the wait.
    1641             :  *
    1642             :  * To avoid it we signal everything inside the mutex. And we do this in both
    1643             :  * test mode (with CHERCKER defined) and release mode (CHECKER not defined),
    1644             :  * to be on the safe side and avoid any difference in beaviour between test and
    1645             :  * release.
    1646             :  *
    1647             :  * Here some interesting discussion:
    1648             :  *
    1649             :  * Condvars: signal with mutex locked or not?
    1650             :  * http://www.domaigne.com/blog/computing/condvars-signal-with-mutex-locked-or-not/
    1651             :  *
    1652             :  * Calling pthread_cond_signal without locking mutex
    1653             :  * http://stackoverflow.com/questions/4544234/calling-pthread-cond-signal-without-locking-mutex/4544494#4544494
    1654             :  */
    1655             : 
    1656             : /**
    1657             :  * Control when to signal the condition variables.
    1658             :  */
    1659             : int thread_cond_signal_outside = 0;
    1660             : 
    1661        2069 : void thread_cond_signal_and_unlock(pthread_cond_t* cond, pthread_mutex_t* mutex)
    1662             : {
    1663        2069 :         if (thread_cond_signal_outside) {
    1664             :                 /* without the thread checker unlock before signaling, */
    1665             :                 /* this reduces the number of context switches */
    1666           0 :                 thread_mutex_unlock(mutex);
    1667             :         }
    1668             : 
    1669        2069 :         thread_cond_signal(cond);
    1670             : 
    1671        2069 :         if (!thread_cond_signal_outside) {
    1672             :                 /* with the thread checker unlock after signaling */
    1673             :                 /* to make explicit the condition and mutex relation */
    1674        2069 :                 thread_mutex_unlock(mutex);
    1675             :         }
    1676        2069 : }
    1677             : 
    1678      255367 : void thread_cond_broadcast_and_unlock(pthread_cond_t* cond, pthread_mutex_t* mutex)
    1679             : {
    1680      255367 :         if (thread_cond_signal_outside) {
    1681             :                 /* without the thread checker unlock before signaling, */
    1682             :                 /* this reduces the number of context switches */
    1683           0 :                 thread_mutex_unlock(mutex);
    1684             :         }
    1685             : 
    1686      255367 :         thread_cond_broadcast(cond);
    1687             : 
    1688      255367 :         if (!thread_cond_signal_outside) {
    1689             :                 /* with the thread checker unlock after signaling */
    1690             :                 /* to make explicit the condition and mutex relation */
    1691      255367 :                 thread_mutex_unlock(mutex);
    1692             :         }
    1693      255367 : }
    1694             : 
    1695        2200 : void thread_create(pthread_t* thread, pthread_attr_t* attr, void *(* func)(void *), void *arg)
    1696             : {
    1697        2200 :         if (pthread_create(thread, attr, func, arg) != 0) {
    1698             :                 /* LCOV_EXCL_START */
    1699             :                 log_fatal("Failed call to pthread_create().\n");
    1700             :                 os_abort();
    1701             :                 /* LCOV_EXCL_STOP */
    1702             :         }
    1703        2200 : }
    1704             : 
    1705        2200 : void thread_join(pthread_t thread, void** retval)
    1706             : {
    1707        2200 :         if (pthread_join(thread, retval) != 0) {
    1708             :                 /* LCOV_EXCL_START */
    1709             :                 log_fatal("Failed call to pthread_join().\n");
    1710             :                 os_abort();
    1711             :                 /* LCOV_EXCL_STOP */
    1712             :         }
    1713        2200 : }
    1714             : 
    1715             : #endif
    1716             : 

Generated by: LCOV version 1.13