"Fossies" - the Fresh Open Source Software Archive

Member "dosfstools-4.2/src/common.c" (31 Jan 2021, 8678 Bytes) of package /linux/misc/dosfstools-4.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "common.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 4.1_vs_4.2.

    1 /* common.c - Common functions
    2 
    3    Copyright (C) 1993 Werner Almesberger <werner.almesberger@lrc.di.epfl.ch>
    4    Copyright (C) 1998 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
    5    Copyright (C) 2008-2014 Daniel Baumann <mail@daniel-baumann.ch>
    6    Copyright (C) 2018 Pali Rohár <pali.rohar@gmail.com>
    7 
    8    This program is free software: you can redistribute it and/or modify
    9    it under the terms of the GNU General Public License as published by
   10    the Free Software Foundation, either version 3 of the License, or
   11    (at your option) any later version.
   12 
   13    This program is distributed in the hope that it will be useful,
   14    but WITHOUT ANY WARRANTY; without even the implied warranty of
   15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
   16    GNU General Public License for more details.
   17 
   18    You should have received a copy of the GNU General Public License
   19    along with this program. If not, see <http://www.gnu.org/licenses/>.
   20 
   21    The complete text of the GNU General Public License
   22    can be found in /usr/share/common-licenses/GPL-3 file.
   23 */
   24 
   25 /* FAT32, VFAT, Atari format support, and various fixes additions May 1998
   26  * by Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> */
   27 
   28 #include <stdlib.h>
   29 #include <stdio.h>
   30 #include <string.h>
   31 #include <stdarg.h>
   32 #include <errno.h>
   33 #include <wctype.h>
   34 #include <termios.h>
   35 #include <sys/time.h>
   36 #include <unistd.h>
   37 
   38 #include "common.h"
   39 #include "charconv.h"
   40 
   41 
   42 int interactive;
   43 int write_immed;
   44 int atari_format;
   45 const char *program_name;
   46 
   47 
   48 typedef struct _link {
   49     void *data;
   50     struct _link *next;
   51 } LINK;
   52 
   53 void die(const char *msg, ...)
   54 {
   55     va_list args;
   56 
   57     if (program_name)
   58     fprintf(stderr, "%s: ", program_name);
   59 
   60     va_start(args, msg);
   61     vfprintf(stderr, msg, args);
   62     va_end(args);
   63     fprintf(stderr, "\n");
   64     exit(1);
   65 }
   66 
   67 void pdie(const char *msg, ...)
   68 {
   69     va_list args;
   70 
   71     if (program_name)
   72     fprintf(stderr, "%s: ", program_name);
   73 
   74     va_start(args, msg);
   75     vfprintf(stderr, msg, args);
   76     va_end(args);
   77     fprintf(stderr, ":%s\n", strerror(errno));
   78     exit(1);
   79 }
   80 
   81 void *alloc(int size)
   82 {
   83     void *this;
   84 
   85     if ((this = malloc(size)))
   86     return this;
   87     pdie("malloc");
   88     return NULL;        /* for GCC */
   89 }
   90 
   91 void *qalloc(void **root, int size)
   92 {
   93     LINK *link;
   94 
   95     link = alloc(sizeof(LINK));
   96     link->next = *root;
   97     *root = link;
   98     return link->data = alloc(size);
   99 }
  100 
  101 void qfree(void **root)
  102 {
  103     LINK *this;
  104 
  105     while (*root) {
  106     this = (LINK *) * root;
  107     *root = this->next;
  108     free(this->data);
  109     free(this);
  110     }
  111 }
  112 
  113 int min(int a, int b)
  114 {
  115     return a < b ? a : b;
  116 }
  117 
  118 
  119 #ifndef HAVE_VASPRINTF
  120 static int vasprintf(char **strp, const char *fmt, va_list va)
  121 {
  122     int length;
  123     va_list vacopy;
  124 
  125     va_copy(vacopy, va);
  126 
  127     length = vsnprintf(NULL, 0, fmt, vacopy);
  128     if (length < 0)
  129     return length;
  130 
  131     *strp = malloc(length + 1);
  132     if (!*strp) {
  133     errno = ENOMEM;
  134     return -1;
  135     }
  136 
  137     return vsnprintf(*strp, length + 1, fmt, va);
  138 }
  139 #endif
  140 
  141 int xasprintf(char **strp, const char *fmt, ...)
  142 {
  143     va_list va;
  144     int retval;
  145 
  146     va_start(va, fmt);
  147     retval = vasprintf(strp, fmt, va);
  148     va_end(va);
  149 
  150     if (retval < 0)
  151     pdie("asprintf");
  152 
  153     return retval;
  154 }
  155 
  156 
  157 int get_choice(int noninteractive_result, const char *noninteractive_msg,
  158            int choices, ...)
  159 {
  160     int choice_values[9];
  161     const char *choice_strings[9];
  162     int choice;
  163     int quit_choice;
  164     int print_choices, print_full_choices;
  165     va_list va;
  166     int i;
  167     static int inhibit_quit_choice;
  168 
  169     if (!interactive) {
  170     printf("%s\n", noninteractive_msg);
  171     return noninteractive_result;
  172     }
  173 
  174     if (choices < 2 || choices > 9)
  175     die("internal error: invalid number %u of choices in get_choice()",
  176         choices);
  177 
  178     va_start(va, choices);
  179     for (i = 0; i < choices; i++) {
  180     choice_values[i] = va_arg(va, int);
  181     choice_strings[i] = va_arg(va, const char *);
  182     }
  183     va_end(va);
  184 
  185     print_choices = 1;
  186     print_full_choices = 0;
  187     while (1) {
  188     if (print_choices) {
  189         print_choices = 0;
  190         for (i = 0; i < choices; i++)
  191         printf("%d) %s\n", i + 1, choice_strings[i]);
  192 
  193         if (print_full_choices) {
  194         printf("?) List all choices\n");
  195         printf("q) Quit fsck\n");
  196         }
  197     }
  198 
  199     printf("[%.*s?%s]? ", choices, "123456789", inhibit_quit_choice ? "" : "q");
  200     fflush(stdout);
  201 
  202     do {
  203         choice = getchar();
  204     } while (choice == '\n');  /* filter out enter presses */
  205 
  206     if (choice == EOF)
  207         exit(1);
  208 
  209     printf("%c\n", choice);
  210 
  211     if (choice > '0' && choice <= '0' + choices)
  212         break;
  213 
  214     if (choice == '?') {
  215         print_choices = 1;
  216         print_full_choices = 1;
  217     }
  218 
  219     if (!inhibit_quit_choice && (choice == 'q' || choice == 'Q')) {
  220         if (!write_immed)
  221         printf("No changes have been written to the filesystem yet. If you choose\n"
  222                "to quit, it will be left in the same state it was in before you\n"
  223                "started this program.\n");
  224         else
  225         printf("fsck is running in immediate write mode. All changes so far have\n"
  226                "already been written and can not be undone now. If you choose to\n"
  227                "quit now, these changes will stay in place.\n");
  228 
  229         inhibit_quit_choice = 1;
  230         quit_choice = get_choice(1, "This is never non-interactive.",
  231                      2,
  232                      1, "Quit now",
  233                      2, "Continue");
  234         inhibit_quit_choice = 0;
  235 
  236         if (quit_choice == 1)
  237         exit(0);
  238     }
  239     }
  240 
  241     return choice_values[choice - '1'];
  242 }
  243 
  244 
  245 char *get_line(const char *prompt, char *dest, size_t length)
  246 {
  247     struct termios tio, tio_orig;
  248     int tio_fail;
  249     char *retval;
  250 
  251     tio_fail = tcgetattr(0, &tio_orig);
  252     if (!tio_fail) {
  253     tio = tio_orig;
  254     tio.c_lflag |= ICANON | ECHO;
  255     tcsetattr(0, TCSAFLUSH, &tio);
  256     }
  257 
  258     printf("%s: ", prompt);
  259     fflush(stdout);
  260 
  261     retval = fgets(dest, length, stdin);
  262 
  263     if (!tio_fail)
  264     tcsetattr(0, TCSAFLUSH, &tio_orig);
  265     return retval;
  266 }
  267 
  268 
  269 /*
  270  * ++roman: On m68k, check if this is an Atari; if yes, turn on Atari variant
  271  * of MS-DOS filesystem by default.
  272  */
  273 void check_atari(void)
  274 {
  275 #if defined(__mc68000__) && defined(__linux__) && defined(CONF_CHECK_ATARI)
  276     FILE *f;
  277     char line[128], *p;
  278 
  279     if (!(f = fopen("/proc/hardware", "r"))) {
  280     perror("/proc/hardware");
  281     return;
  282     }
  283 
  284     while (fgets(line, sizeof(line), f)) {
  285     if (strncmp(line, "Model:", 6) == 0) {
  286         p = line + 6;
  287         p += strspn(p, " \t");
  288         if (strncmp(p, "Atari ", 6) == 0)
  289         atari_format = 1;
  290         break;
  291     }
  292     }
  293     fclose(f);
  294 #endif
  295 }
  296 
  297 
  298 uint32_t generate_volume_id(void)
  299 {
  300     struct timeval now;
  301 
  302     if (gettimeofday(&now, NULL) != 0 || now.tv_sec == (time_t)-1 || now.tv_sec < 0) {
  303         srand(getpid());
  304         /* rand() returns int from [0,RAND_MAX], therefore only 31 bits */
  305         return (((uint32_t)(rand() & 0xFFFF)) << 16) | ((uint32_t)(rand() & 0xFFFF));
  306     }
  307 
  308     /* volume ID = current time, fudged for more uniqueness */
  309     return ((uint32_t)now.tv_sec << 20) | (uint32_t)now.tv_usec;
  310 }
  311 
  312 /*
  313  * Validate volume label
  314  *
  315  * @param[in]   doslabel   Label stored according to current DOS codepage
  316  *
  317  * @return   bitmask of errors
  318  *           0x01 - lowercase character
  319  *           0x02 - character below 0x20
  320  *           0x04 - character in disallowed set
  321  *           0x08 - empty or space-only label
  322  *           0x10 - space at beginning
  323  */
  324 int validate_volume_label(char *doslabel)
  325 {
  326     int i;
  327     int ret = 0;
  328     wchar_t wlabel[12];
  329 
  330     if (dos_string_to_wchar_string(wlabel, doslabel, sizeof(wlabel))) {
  331         for (i = 0; wlabel[i]; i++) {
  332             /* FAT specification: Lower case characters are not allowed in DIR_Name
  333                                   (what these characters are is country specific)
  334                Original label is stored in DOS OEM code page, so islower() function
  335                cannot be used. Therefore convert original label to locale independent
  336                wchar_t* and then use iswlower() function for it.
  337             */
  338             if (iswlower(wlabel[i])) {
  339                 ret |= 0x01;
  340                 break;
  341             }
  342         }
  343     }
  344 
  345     /* According to FAT specification those bytes (after conversion to DOS OEM
  346        code page) are not allowed.
  347      */
  348     for (i = 0; i < 11; i++) {
  349         if (doslabel[i] < 0x20)
  350             ret |= 0x02;
  351         if (doslabel[i] == 0x22 ||
  352             (doslabel[i] >= 0x2A && doslabel[i] <= 0x2C) ||
  353             doslabel[i] == 0x2E ||
  354             doslabel[i] == 0x2F ||
  355             (doslabel[i] >= 0x3A && doslabel[i] <= 0x3F) ||
  356             (doslabel[i] >= 0x5B && doslabel[i] <= 0x5D) ||
  357             doslabel[i] == 0x7C)
  358             ret |= 0x04;
  359     }
  360 
  361     if (memcmp(doslabel, "           ", 11) == 0)
  362         ret |= 0x08;
  363 
  364     if (doslabel[0] == ' ')
  365         ret |= 0x10;
  366 
  367     return ret;
  368 }