?login_element?

Subversion Repositories NedoOS

Rev

Rev 1229 | Blame | Compare with Previous | Last modification | View Log | Download

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