The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/libkern/OSKextVersion.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright (c) 2000-2016 Apple Inc. All rights reserved.
    3  *
    4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
    5  *
    6  * This file contains Original Code and/or Modifications of Original Code
    7  * as defined in and that are subject to the Apple Public Source License
    8  * Version 2.0 (the 'License'). You may not use this file except in
    9  * compliance with the License. The rights granted to you under the License
   10  * may not be used to create, or enable the creation or redistribution of,
   11  * unlawful or unlicensed copies of an Apple operating system, or to
   12  * circumvent, violate, or enable the circumvention or violation of, any
   13  * terms of an Apple operating system software license agreement.
   14  *
   15  * Please obtain a copy of the License at
   16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
   17  *
   18  * The Original Code and all software distributed under the License are
   19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
   20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
   21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
   22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
   23  * Please see the License for the specific language governing rights and
   24  * limitations under the License.
   25  *
   26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
   27  */
   28 #ifdef KERNEL
   29 #include <sys/systm.h>
   30 #include <libkern/OSKextLib.h>
   31 #include <libkern/OSKextLibPrivate.h>
   32 #else
   33 #include <libc.h>
   34 #include <libkern/OSKextLib.h>
   35 #include <System/libkern/OSKextLibPrivate.h>
   36 #endif /* KERNEL */
   37 
   38 #include <libkern/OSKextLibPrivate.h>
   39 
   40 #define VERS_MAJOR_DIGITS        (4)
   41 #define VERS_MINOR_DIGITS        (4)
   42 #define VERS_REVISION_DIGITS     (4)
   43 #define VERS_STAGE_DIGITS        (1)
   44 #define VERS_STAGE_LEVEL_DIGITS  (3)
   45 
   46 #define VERS_MAJOR_MAX           (9999)
   47 #define VERS_STAGE_LEVEL_MAX      (255)
   48 
   49 #define VERS_MAJOR_MULT  (1000000000000)
   50 #define VERS_MINOR_MULT      (100000000)
   51 #define VERS_REVISION_MULT       (10000)
   52 #define VERS_STAGE_MULT           (1000)
   53 
   54 
   55 typedef enum {
   56         kOSKextVersionStageInvalid     = 0,
   57         kOSKextVersionStageDevelopment = 1,
   58         kOSKextVersionStageAlpha       = 3,
   59         kOSKextVersionStageBeta        = 5,
   60         kOSKextVersionStageCandidate   = 7,
   61         kOSKextVersionStageRelease     = 9,
   62 } OSKextVersionStage;
   63 
   64 
   65 /*********************************************************************
   66 *********************************************************************/
   67 static int
   68 __vers_isdigit(char c)
   69 {
   70         return c == '' ||
   71                c == '1' || c == '2' || c == '3' ||
   72                c == '4' || c == '5' || c == '6' ||
   73                c == '7' || c == '8' || c == '9';
   74 }
   75 
   76 /*********************************************************************
   77 *********************************************************************/
   78 static int
   79 __vers_isspace(char c)
   80 {
   81         return c == ' ' ||
   82                c == '\t' ||
   83                c == '\r' ||
   84                c == '\n';
   85 }
   86 
   87 /*********************************************************************
   88 *********************************************************************/
   89 static int
   90 __vers_digit_for_char(char c)
   91 {
   92         switch (c) {
   93         case '': return 0;
   94         case '1': return 1;
   95         case '2': return 2;
   96         case '3': return 3;
   97         case '4': return 4;
   98         case '5': return 5;
   99         case '6': return 6;
  100         case '7': return 7;
  101         case '8': return 8;
  102         case '9': return 9;
  103         default:  return -1;
  104         }
  105 }
  106 
  107 /*********************************************************************
  108 *********************************************************************/
  109 static int
  110 __VERS_isreleasestate(char c)
  111 {
  112         return c == 'd' || c == 'a' || c == 'b' || c == 'f';
  113 }
  114 
  115 
  116 /*********************************************************************
  117 *********************************************************************/
  118 static OSKextVersionStage
  119 __OSKextVersionStageForString(const char ** string_p)
  120 {
  121         const char * string;
  122 
  123         if (!string_p || !*string_p) {
  124                 return kOSKextVersionStageInvalid;
  125         }
  126 
  127         string = *string_p;
  128 
  129         if (__vers_isspace(string[0]) || string[0] == '\0') {
  130                 return kOSKextVersionStageRelease;
  131         } else {
  132                 switch (string[0]) {
  133                 case 'd':
  134                         if (__vers_isdigit(string[1])) {
  135                                 *string_p = &string[1];
  136                                 return kOSKextVersionStageDevelopment;
  137                         }
  138                         break;
  139                 case 'a':
  140                         if (__vers_isdigit(string[1])) {
  141                                 *string_p = &string[1];
  142                                 return kOSKextVersionStageAlpha;
  143                         }
  144                         break;
  145                 case 'b':
  146                         if (__vers_isdigit(string[1])) {
  147                                 *string_p = &string[1];
  148                                 return kOSKextVersionStageBeta;
  149                         }
  150                         break;
  151                 case 'f':
  152                         if (__vers_isdigit(string[1])) {
  153                                 *string_p = &string[1];
  154                                 return kOSKextVersionStageCandidate;
  155                         } else if (string[1] == 'c' && __vers_isdigit(string[2])) {
  156                                 *string_p = &string[2];
  157                                 return kOSKextVersionStageCandidate;
  158                         } else {
  159                                 return kOSKextVersionStageInvalid;
  160                         }
  161                 default:
  162                         return kOSKextVersionStageInvalid;
  163                 }
  164         }
  165 
  166         return kOSKextVersionStageInvalid;
  167 }
  168 
  169 /*********************************************************************
  170 *********************************************************************/
  171 static const char *
  172 __OSKextVersionStringForStage(OSKextVersion stage)
  173 {
  174         switch (stage) {
  175         default:
  176                 OS_FALLTHROUGH;
  177         case kOSKextVersionStageInvalid:     return NULL;
  178         case kOSKextVersionStageDevelopment: return "d";
  179         case kOSKextVersionStageAlpha:       return "a";
  180         case kOSKextVersionStageBeta:        return "b";
  181         case kOSKextVersionStageCandidate:   return "f";
  182         case kOSKextVersionStageRelease:     return "";
  183         }
  184 }
  185 
  186 /*********************************************************************
  187 *********************************************************************/
  188 OSKextVersion
  189 OSKextParseVersionString(const char * versionString)
  190 {
  191         OSKextVersion   result             = -1;
  192         int             vers_digit         = -1;
  193         int             num_digits_scanned = 0;
  194         OSKextVersion   vers_major         = 0;
  195         OSKextVersion   vers_minor         = 0;
  196         OSKextVersion   vers_revision      = 0;
  197         OSKextVersionStage   vers_stage         = 0;
  198         OSKextVersion   vers_stage_level   = 0;
  199         const char    * current_char_p;
  200 
  201         if (!versionString || *versionString == '\0') {
  202                 return -1;
  203         }
  204 
  205         current_char_p = (const char *)&versionString[0];
  206 
  207         /*****
  208          * Check for an initial digit of the major release number.
  209          */
  210         vers_major = __vers_digit_for_char(*current_char_p);
  211         if (vers_major < 0) {
  212                 return -1;
  213         }
  214 
  215         current_char_p++;
  216         num_digits_scanned = 1;
  217 
  218         /* Complete scan for major version number. Legal characters are
  219          * any digit, period, any buildstage letter.
  220          */
  221         while (num_digits_scanned < VERS_MAJOR_DIGITS) {
  222                 if (__vers_isspace(*current_char_p) || *current_char_p == '\0') {
  223                         vers_stage = kOSKextVersionStageRelease;
  224                         goto finish;
  225                 } else if (__vers_isdigit(*current_char_p)) {
  226                         vers_digit = __vers_digit_for_char(*current_char_p);
  227                         if (vers_digit < 0) {
  228                                 return -1;
  229                         }
  230                         vers_major = (vers_major) * 10 + vers_digit;
  231                         current_char_p++;
  232                         num_digits_scanned++;
  233                 } else if (__VERS_isreleasestate(*current_char_p)) {
  234                         goto release_state;
  235                 } else if (*current_char_p == '.') {
  236                         current_char_p++;
  237                         goto minor_version;
  238                 } else {
  239                         return -1;
  240                 }
  241         }
  242 
  243         /* Check for too many digits.
  244          */
  245         if (num_digits_scanned == VERS_MAJOR_DIGITS) {
  246                 if (*current_char_p == '.') {
  247                         current_char_p++;
  248                 } else if (__vers_isdigit(*current_char_p)) {
  249                         return -1;
  250                 }
  251         }
  252 
  253 minor_version:
  254 
  255         num_digits_scanned = 0;
  256 
  257         /* Scan for minor version number. Legal characters are
  258          * any digit, period, any buildstage letter.
  259          */
  260         while (num_digits_scanned < VERS_MINOR_DIGITS) {
  261                 if (__vers_isspace(*current_char_p) || *current_char_p == '\0') {
  262                         vers_stage = kOSKextVersionStageRelease;
  263                         goto finish;
  264                 } else if (__vers_isdigit(*current_char_p)) {
  265                         vers_digit = __vers_digit_for_char(*current_char_p);
  266                         if (vers_digit < 0) {
  267                                 return -1;
  268                         }
  269                         vers_minor = (vers_minor) * 10 + vers_digit;
  270                         current_char_p++;
  271                         num_digits_scanned++;
  272                 } else if (__VERS_isreleasestate(*current_char_p)) {
  273                         goto release_state;
  274                 } else if (*current_char_p == '.') {
  275                         current_char_p++;
  276                         goto revision;
  277                 } else {
  278                         return -1;
  279                 }
  280         }
  281 
  282         /* Check for too many digits.
  283          */
  284         if (num_digits_scanned == VERS_MINOR_DIGITS) {
  285                 if (*current_char_p == '.') {
  286                         current_char_p++;
  287                 } else if (__vers_isdigit(*current_char_p)) {
  288                         return -1;
  289                 }
  290         }
  291 
  292 revision:
  293 
  294         num_digits_scanned = 0;
  295 
  296         /* Scan for revision version number. Legal characters are
  297          * any digit, any buildstage letter (NOT PERIOD).
  298          */
  299         while (num_digits_scanned < VERS_REVISION_DIGITS) {
  300                 if (__vers_isspace(*current_char_p) || *current_char_p == '\0') {
  301                         vers_stage = kOSKextVersionStageRelease;
  302                         goto finish;
  303                 } else if (__vers_isdigit(*current_char_p)) {
  304                         vers_digit = __vers_digit_for_char(*current_char_p);
  305                         if (vers_digit < 0) {
  306                                 return -1;
  307                         }
  308                         vers_revision = (vers_revision) * 10 + vers_digit;
  309                         current_char_p++;
  310                         num_digits_scanned++;
  311                 } else if (__VERS_isreleasestate(*current_char_p)) {
  312                         goto release_state;
  313                 } else {
  314                         return -1;
  315                 }
  316         }
  317 
  318         /* Check for too many digits.
  319          */
  320         if (num_digits_scanned == VERS_REVISION_DIGITS) {
  321                 if (*current_char_p == '.') {
  322                         current_char_p++;
  323                 } else if (__vers_isdigit(*current_char_p)) {
  324                         return -1;
  325                 }
  326         }
  327 
  328 release_state:
  329 
  330         /*****
  331          * Check for the release state.
  332          */
  333         if (__vers_isspace(*current_char_p) || *current_char_p == '\0') {
  334                 vers_stage = kOSKextVersionStageRelease;
  335                 goto finish;
  336         } else {
  337                 vers_stage = __OSKextVersionStageForString(&current_char_p);
  338                 if (vers_stage == kOSKextVersionStageInvalid) {
  339                         return -1;
  340                 }
  341         }
  342 
  343 
  344 // stage level
  345 
  346         num_digits_scanned = 0;
  347 
  348         /* Scan for stage level number. Legal characters are
  349          * any digit only.
  350          */
  351         while (num_digits_scanned < VERS_STAGE_LEVEL_DIGITS) {
  352                 if (__vers_isspace(*current_char_p) || *current_char_p == '\0') {
  353                         if (num_digits_scanned) {
  354                                 goto finish;
  355                         } else {
  356                                 return -1;
  357                         }
  358                 } else if (__vers_isdigit(*current_char_p)) {
  359                         vers_digit = __vers_digit_for_char(*current_char_p);
  360                         if (vers_digit < 0) {
  361                                 return -1;
  362                         }
  363                         vers_stage_level = (vers_stage_level) * 10 + vers_digit;
  364                         current_char_p++;
  365                         num_digits_scanned++;
  366                 } else {
  367                         return -1;
  368                 }
  369         }
  370 
  371         /* Check for too many digits.
  372          */
  373         if ((num_digits_scanned == VERS_STAGE_LEVEL_DIGITS) &&
  374             !(__vers_isspace(*current_char_p) || (*current_char_p == '\0'))) {
  375                 return -1;
  376         }
  377 
  378         if (vers_stage_level > VERS_STAGE_LEVEL_MAX) {
  379                 return -1;
  380         }
  381 
  382 finish:
  383 
  384         if (vers_stage == kOSKextVersionStageCandidate && vers_stage_level == 0) {
  385                 return -1;
  386         }
  387 
  388         result = (vers_major * VERS_MAJOR_MULT) +
  389             (vers_minor * VERS_MINOR_MULT) +
  390             (vers_revision * VERS_REVISION_MULT) +
  391             (vers_stage * VERS_STAGE_MULT) +
  392             vers_stage_level;
  393 
  394         return result;
  395 }
  396 
  397 /*********************************************************************
  398 * This function must be safe to call in panic context.
  399 *********************************************************************/
  400 Boolean
  401 OSKextVersionGetString(
  402         OSKextVersion   aVersion,
  403         char          * buffer,
  404         uint32_t        bufferLength)
  405 {
  406         int             cpos = 0;
  407         OSKextVersion   vers_major = 0;
  408         OSKextVersion   vers_minor = 0;
  409         OSKextVersion   vers_revision = 0;
  410         OSKextVersion   vers_stage = 0;
  411         OSKextVersion   vers_stage_level = 0;
  412         const char    * stage_string = NULL;// don't free
  413 
  414         /* No buffer or length less than longest possible vers string,
  415          * return 0.
  416          */
  417         if (!buffer || bufferLength < kOSKextVersionMaxLength) {
  418                 return FALSE;
  419         }
  420 
  421         bzero(buffer, bufferLength * sizeof(char));
  422 
  423         if (aVersion < 0) {
  424                 strlcpy(buffer, "(invalid)", bufferLength);
  425                 return TRUE;
  426         }
  427         if (aVersion == 0) {
  428                 strlcpy(buffer, "(missing)", bufferLength);
  429                 return TRUE;
  430         }
  431 
  432         vers_major = aVersion / VERS_MAJOR_MULT;
  433         if (vers_major > VERS_MAJOR_MAX) {
  434                 strlcpy(buffer, "(invalid)", bufferLength);
  435                 return TRUE;
  436         }
  437 
  438         vers_minor = aVersion - (vers_major * VERS_MAJOR_MULT);
  439         vers_minor /= VERS_MINOR_MULT;
  440 
  441         vers_revision = aVersion -
  442             ((vers_major * VERS_MAJOR_MULT) + (vers_minor * VERS_MINOR_MULT));
  443         vers_revision /= VERS_REVISION_MULT;
  444 
  445         vers_stage = aVersion -
  446             ((vers_major * VERS_MAJOR_MULT) + (vers_minor * VERS_MINOR_MULT) +
  447             (vers_revision * VERS_REVISION_MULT));
  448         vers_stage /= VERS_STAGE_MULT;
  449 
  450         vers_stage_level = aVersion -
  451             ((vers_major * VERS_MAJOR_MULT) + (vers_minor * VERS_MINOR_MULT) +
  452             (vers_revision * VERS_REVISION_MULT) + (vers_stage * VERS_STAGE_MULT));
  453         if (vers_stage_level > VERS_STAGE_LEVEL_MAX) {
  454                 strlcpy(buffer, "(invalid)", bufferLength);
  455                 return TRUE;
  456         }
  457 
  458         cpos = scnprintf(buffer, bufferLength, "%u", (uint32_t)vers_major);
  459 
  460         /* Always include the minor version; it just looks weird without.
  461          */
  462         buffer[cpos] = '.';
  463         cpos++;
  464         cpos += scnprintf(buffer + cpos, bufferLength - cpos, "%u", (uint32_t)vers_minor);
  465 
  466         /* The revision is displayed only if nonzero.
  467          */
  468         if (vers_revision) {
  469                 buffer[cpos] = '.';
  470                 cpos++;
  471                 cpos += scnprintf(buffer + cpos, bufferLength - cpos, "%u",
  472                     (uint32_t)vers_revision);
  473         }
  474 
  475         stage_string = __OSKextVersionStringForStage(vers_stage);
  476         if (!stage_string) {
  477                 strlcpy(buffer, "(invalid)", bufferLength);
  478                 return TRUE;
  479         }
  480         if (stage_string[0]) {
  481                 strlcat(buffer, stage_string, bufferLength);
  482                 cpos += strlen(stage_string);
  483         }
  484 
  485         if (vers_stage < kOSKextVersionStageRelease) {
  486                 snprintf(buffer + cpos, bufferLength - cpos, "%u", (uint32_t)vers_stage_level);
  487         }
  488 
  489         return TRUE;
  490 }
  491 
  492 /*********************************************************************
  493 *********************************************************************/
  494 #ifndef KERNEL
  495 OSKextVersion
  496 OSKextParseVersionCFString(CFStringRef versionString)
  497 {
  498         OSKextVersion result = -1;
  499         char         versBuffer[kOSKextVersionMaxLength];
  500 
  501         if (CFStringGetCString(versionString, versBuffer,
  502             sizeof(versBuffer), kCFStringEncodingASCII)) {
  503                 result = OSKextParseVersionString(versBuffer);
  504         }
  505         return result;
  506 }
  507 #endif

Cache object: b7cdfe2a396bfde0383d2c1a2a1cfc8c


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.