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-2008 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 <System/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        (2)
   42 #define VERS_REVISION_DIGITS     (2)
   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    (100000000)
   50 #define VERS_MINOR_MULT      (1000000)
   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 __vers_isdigit(char c) {
   68     return (c == '' ||
   69         c == '1' || c == '2' || c == '3' ||
   70         c == '4' || c == '5' || c == '6' ||
   71         c == '7' || c == '8' || c == '9');
   72 }
   73 
   74 /*********************************************************************
   75 *********************************************************************/
   76 static int __vers_isspace(char c) {
   77     return (c == ' ' ||
   78         c == '\t' ||
   79         c == '\r' ||
   80         c == '\n');
   81 }
   82 
   83 /*********************************************************************
   84 *********************************************************************/
   85 static int __vers_digit_for_char(char c) {
   86     switch (c) {
   87       case '': return 0; break;
   88       case '1': return 1; break;
   89       case '2': return 2; break;
   90       case '3': return 3; break;
   91       case '4': return 4; break;
   92       case '5': return 5; break;
   93       case '6': return 6; break;
   94       case '7': return 7; break;
   95       case '8': return 8; break;
   96       case '9': return 9; break;
   97       default:  return -1; break;
   98     }
   99 
  100     return -1;
  101 }
  102 
  103 /*********************************************************************
  104 *********************************************************************/
  105 static int __VERS_isreleasestate(char c) {
  106     return (c == 'd' || c == 'a' || c == 'b' || c == 'f');
  107 }
  108 
  109 
  110 /*********************************************************************
  111 *********************************************************************/
  112 static OSKextVersionStage __OSKextVersionStageForString(const char ** string_p) {
  113     const char * string;
  114 
  115     if (!string_p || !*string_p) {
  116         return kOSKextVersionStageInvalid;
  117     }
  118 
  119     string = *string_p;
  120 
  121     if (__vers_isspace(string[0]) || string[0] == '\0') {
  122         return kOSKextVersionStageRelease;
  123     } else {
  124         switch (string[0]) {
  125           case 'd':
  126               if (__vers_isdigit(string[1])) {
  127                   *string_p = &string[1];
  128                   return kOSKextVersionStageDevelopment;
  129               }
  130               break;
  131           case 'a':
  132               if (__vers_isdigit(string[1])) {
  133                   *string_p = &string[1];
  134                   return kOSKextVersionStageAlpha;
  135               }
  136               break;
  137           case 'b':
  138               if (__vers_isdigit(string[1])) {
  139                   *string_p = &string[1];
  140                   return kOSKextVersionStageBeta;
  141               }
  142               break;
  143           case 'f':
  144               if (__vers_isdigit(string[1])) {
  145                   *string_p = &string[1];
  146                   return kOSKextVersionStageCandidate;
  147               } else if (string[1] == 'c' && __vers_isdigit(string[2])) {
  148                   *string_p = &string[2];
  149                   return kOSKextVersionStageCandidate;
  150               } else {
  151                   return kOSKextVersionStageInvalid;
  152               }
  153               break;
  154           default:
  155               return kOSKextVersionStageInvalid;
  156               break;
  157         }
  158     }
  159 
  160     return kOSKextVersionStageInvalid;
  161 }
  162 
  163 /*********************************************************************
  164 *********************************************************************/
  165 static const char * __OSKextVersionStringForStage(OSKextVersionStage stage)
  166 {
  167     switch (stage) {
  168       case kOSKextVersionStageInvalid:     return NULL; break;
  169       case kOSKextVersionStageDevelopment: return "d"; break;
  170       case kOSKextVersionStageAlpha:       return "a"; break;
  171       case kOSKextVersionStageBeta:        return "b"; break;
  172       case kOSKextVersionStageCandidate:   return "f"; break;
  173       case kOSKextVersionStageRelease:     return ""; break;
  174     }
  175 
  176     return NULL;
  177 }
  178 
  179 /*********************************************************************
  180 *********************************************************************/
  181 OSKextVersion OSKextParseVersionString(const char * versionString)
  182 {
  183     OSKextVersion   result             = -1;
  184     int             vers_digit         = -1;
  185     int             num_digits_scanned = 0;
  186     OSKextVersion   vers_major         = 0;
  187     OSKextVersion   vers_minor         = 0;
  188     OSKextVersion   vers_revision      = 0;
  189     OSKextVersion   vers_stage         = 0;
  190     OSKextVersion   vers_stage_level   = 0;
  191     const char    * current_char_p;
  192 
  193     if (!versionString || *versionString == '\0') {
  194         return -1;
  195     }
  196 
  197     current_char_p = (const char *)&versionString[0];
  198 
  199    /*****
  200     * Check for an initial digit of the major release number.
  201     */
  202     vers_major = __vers_digit_for_char(*current_char_p);
  203     if (vers_major < 0) {
  204         return -1;
  205     }
  206 
  207     current_char_p++;
  208     num_digits_scanned = 1;
  209 
  210    /* Complete scan for major version number. Legal characters are
  211     * any digit, period, any buildstage letter.
  212     */
  213     while (num_digits_scanned < VERS_MAJOR_DIGITS) {
  214         if (__vers_isspace(*current_char_p) || *current_char_p == '\0') {
  215             vers_stage = kOSKextVersionStageRelease;
  216             goto finish;
  217         } else if (__vers_isdigit(*current_char_p)) {
  218             vers_digit = __vers_digit_for_char(*current_char_p);
  219             if (vers_digit < 0) {
  220                 return -1;
  221             }
  222             vers_major = (vers_major) * 10 + vers_digit;
  223             current_char_p++;
  224             num_digits_scanned++;
  225         } else if (__VERS_isreleasestate(*current_char_p)) {
  226             goto release_state;
  227         } else if (*current_char_p == '.') {
  228             current_char_p++;
  229             goto minor_version;
  230         } else {
  231             return -1;
  232         }
  233     }
  234 
  235    /* Check for too many digits.
  236     */
  237     if (num_digits_scanned == VERS_MAJOR_DIGITS) {
  238          if (*current_char_p == '.') {
  239             current_char_p++;
  240         } else if (__vers_isdigit(*current_char_p)) {
  241             return -1;
  242         }
  243     }
  244 
  245 minor_version:
  246 
  247     num_digits_scanned = 0;
  248 
  249    /* Scan for minor version number. Legal characters are
  250     * any digit, period, any buildstage letter.
  251     */
  252     while (num_digits_scanned < VERS_MINOR_DIGITS) {
  253         if (__vers_isspace(*current_char_p) || *current_char_p == '\0') {
  254             vers_stage = kOSKextVersionStageRelease;
  255             goto finish;
  256         } else if (__vers_isdigit(*current_char_p)) {
  257             vers_digit = __vers_digit_for_char(*current_char_p);
  258             if (vers_digit < 0) {
  259                 return -1;
  260             }
  261             vers_minor = (vers_minor) * 10 + vers_digit;
  262             current_char_p++;
  263             num_digits_scanned++;
  264         } else if (__VERS_isreleasestate(*current_char_p)) {
  265             goto release_state;
  266         } else if (*current_char_p == '.') {
  267             current_char_p++;
  268             goto revision;
  269         } else {
  270             return -1;
  271         }
  272     }
  273 
  274    /* Check for too many digits.
  275     */
  276     if (num_digits_scanned == VERS_MINOR_DIGITS) {
  277          if (*current_char_p == '.') {
  278             current_char_p++;
  279         } else if (__vers_isdigit(*current_char_p)) {
  280             return -1;
  281         }
  282     }
  283 
  284 revision:
  285 
  286     num_digits_scanned = 0;
  287 
  288    /* Scan for revision version number. Legal characters are
  289     * any digit, any buildstage letter (NOT PERIOD).
  290     */
  291     while (num_digits_scanned < VERS_REVISION_DIGITS) {
  292         if (__vers_isspace(*current_char_p) || *current_char_p == '\0') {
  293             vers_stage = kOSKextVersionStageRelease;
  294             goto finish;
  295         } else if (__vers_isdigit(*current_char_p)) {
  296             vers_digit = __vers_digit_for_char(*current_char_p);
  297             if (vers_digit < 0) {
  298                 return -1;
  299             }
  300             vers_revision = (vers_revision) * 10 + vers_digit;
  301             current_char_p++;
  302             num_digits_scanned++;
  303         } else if (__VERS_isreleasestate(*current_char_p)) {
  304             goto release_state;
  305         } else {
  306             return -1;
  307         }
  308     }
  309 
  310    /* Check for too many digits.
  311     */
  312     if (num_digits_scanned == VERS_REVISION_DIGITS) {
  313          if (*current_char_p == '.') {
  314             current_char_p++;
  315         } else if (__vers_isdigit(*current_char_p)) {
  316             return -1;
  317         }
  318     }
  319 
  320 release_state:
  321 
  322    /*****
  323     * Check for the release state.
  324     */
  325     if (__vers_isspace(*current_char_p) || *current_char_p == '\0') {
  326         vers_stage = kOSKextVersionStageRelease;
  327         goto finish;
  328     } else {
  329         vers_stage = __OSKextVersionStageForString(&current_char_p);
  330         if (vers_stage == kOSKextVersionStageInvalid) {
  331             return -1;
  332         }
  333     }
  334 
  335 
  336 // stage level
  337 
  338     num_digits_scanned = 0;
  339 
  340    /* Scan for stage level number. Legal characters are
  341     * any digit only.
  342     */
  343     while (num_digits_scanned < VERS_STAGE_LEVEL_DIGITS) {
  344         if (__vers_isspace(*current_char_p) || *current_char_p == '\0') {
  345             if (num_digits_scanned) {
  346                 goto finish;
  347             } else {
  348                 return -1;
  349             }
  350         } else if (__vers_isdigit(*current_char_p)) {
  351             vers_digit = __vers_digit_for_char(*current_char_p);
  352             if (vers_digit < 0) {
  353                 return -1;
  354             }
  355             vers_stage_level = (vers_stage_level) * 10 + vers_digit;
  356             current_char_p++;
  357             num_digits_scanned++;
  358         } else {
  359             return -1;
  360         }
  361     }
  362 
  363    /* Check for too many digits.
  364     */
  365     if ((num_digits_scanned == VERS_STAGE_LEVEL_DIGITS) &&
  366         ! (__vers_isspace(*current_char_p) || (*current_char_p == '\0'))) {
  367 
  368         return -1;
  369     }
  370 
  371     if (vers_stage_level > VERS_STAGE_LEVEL_MAX) {
  372         return -1;
  373     }
  374 
  375 finish:
  376 
  377     if (vers_stage == kOSKextVersionStageCandidate && vers_stage_level == 0) {
  378         return -1;
  379     }
  380 
  381     result = (vers_major * VERS_MAJOR_MULT) +
  382              (vers_minor * VERS_MINOR_MULT) +
  383              (vers_revision * VERS_REVISION_MULT) +
  384              (vers_stage * VERS_STAGE_MULT) +
  385              vers_stage_level; 
  386 
  387     return result;
  388 }
  389 
  390 /*********************************************************************
  391 * This function must be safe to call in panic context.
  392 *********************************************************************/
  393 Boolean OSKextVersionGetString(
  394     OSKextVersion   aVersion,
  395     char          * buffer,
  396     uint32_t        bufferLength)
  397 {
  398     int             cpos = 0;
  399     OSKextVersion   vers_major = 0;
  400     OSKextVersion   vers_minor = 0;
  401     OSKextVersion   vers_revision = 0;
  402     OSKextVersion   vers_stage = 0;
  403     OSKextVersion   vers_stage_level = 0;
  404     const char    * stage_string = NULL;  // don't free
  405 
  406    /* No buffer or length less than longest possible vers string,
  407     * return 0.
  408     */
  409     if (!buffer || bufferLength < kOSKextVersionMaxLength) {
  410         return FALSE;
  411     }
  412 
  413     bzero(buffer, bufferLength * sizeof(char));
  414 
  415     if (aVersion < 0) {
  416         strlcpy(buffer, "(invalid)", bufferLength);
  417         return TRUE;
  418     }
  419     if (aVersion == 0) {
  420         strlcpy(buffer, "(missing)", bufferLength);
  421         return TRUE;
  422     }
  423 
  424     vers_major = aVersion / VERS_MAJOR_MULT;
  425     if (vers_major > VERS_MAJOR_MAX) {
  426         strlcpy(buffer, "(invalid)", bufferLength);
  427         return TRUE;
  428     }
  429 
  430     vers_minor = aVersion - (vers_major * VERS_MAJOR_MULT);
  431     vers_minor /= VERS_MINOR_MULT;
  432 
  433     vers_revision = aVersion -
  434         ( (vers_major * VERS_MAJOR_MULT) + (vers_minor * VERS_MINOR_MULT) );
  435     vers_revision /= VERS_REVISION_MULT;
  436 
  437     vers_stage = aVersion -
  438         ( (vers_major * VERS_MAJOR_MULT) + (vers_minor * VERS_MINOR_MULT) +
  439           (vers_revision * VERS_REVISION_MULT));
  440     vers_stage /= VERS_STAGE_MULT;
  441 
  442     vers_stage_level = aVersion -
  443         ( (vers_major * VERS_MAJOR_MULT) + (vers_minor * VERS_MINOR_MULT) +
  444           (vers_revision * VERS_REVISION_MULT) + (vers_stage * VERS_STAGE_MULT));
  445     if (vers_stage_level > VERS_STAGE_LEVEL_MAX) {
  446         strlcpy(buffer, "(invalid)", bufferLength);
  447         return TRUE;
  448     }
  449 
  450     cpos = snprintf(buffer, bufferLength, "%u", (uint32_t)vers_major);
  451 
  452    /* Always include the minor version; it just looks weird without.
  453     */
  454     buffer[cpos] = '.';
  455     cpos++;
  456     cpos += snprintf(buffer+cpos, bufferLength - cpos, "%u", (uint32_t)vers_minor);
  457 
  458    /* The revision is displayed only if nonzero.
  459     */
  460     if (vers_revision) {
  461         buffer[cpos] = '.';
  462         cpos++;
  463         cpos += snprintf(buffer+cpos, bufferLength - cpos, "%u",
  464                         (uint32_t)vers_revision);
  465     }
  466 
  467     stage_string = __OSKextVersionStringForStage(vers_stage);
  468     if (!stage_string) {
  469         strlcpy(buffer, "(invalid)", bufferLength);
  470         return TRUE;
  471     }
  472     if (stage_string[0]) {
  473         strlcat(buffer, stage_string, bufferLength);
  474         cpos += strlen(stage_string);
  475     }
  476 
  477     if (vers_stage < kOSKextVersionStageRelease) {
  478         snprintf(buffer+cpos, bufferLength - cpos, "%u", (uint32_t)vers_stage_level);
  479     }
  480 
  481     return TRUE;
  482 }
  483 
  484 /*********************************************************************
  485 *********************************************************************/
  486 #ifndef KERNEL
  487 OSKextVersion OSKextParseVersionCFString(CFStringRef versionString)
  488 {
  489     OSKextVersion result = -1;
  490     char         versBuffer[kOSKextVersionMaxLength];
  491     
  492     if (CFStringGetCString(versionString, versBuffer,
  493         sizeof(versBuffer), kCFStringEncodingASCII)) {
  494 
  495         result = OSKextParseVersionString(versBuffer);
  496     }
  497     return result;
  498 }
  499 #endif

Cache object: 36bceb40af4734996572aff03b0b4f49


[ 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.