Coverage Report

Created: 2026-10-17 06:38

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/barebox/lib/misc.c
Line
Count
Source
1
/*
2
 * misc.c - various assorted functions
3
 *
4
 * Copyright (c) 2007 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
5
 *
6
 * This program is free software; you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License version 2
8
 * as published by the Free Software Foundation.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 */
16
17
#include <common.h>
18
#include <malloc.h>
19
#include <errno.h>
20
#include <fs.h>
21
#include <string.h>
22
#include <linux/ctype.h>
23
#include <getopt.h>
24
#include <libfile.h>
25
26
/*
27
 * Like simple_strtoull() but handles an optional G, M, K or k
28
 * suffix for Gigabyte, Megabyte or Kilobyte
29
 */
30
unsigned long long strtoull_suffix(const char *str, char **endp, int base)
31
0
{
32
0
  unsigned long long val;
33
0
  char *end;
34
35
0
  val = simple_strtoull(str, &end, base);
36
37
0
  switch (*end) {
38
0
  case 'G':
39
0
    val *= 1024;
40
0
    fallthrough;
41
0
  case 'M':
42
0
    val *= 1024;
43
0
    fallthrough;
44
0
  case 'k':
45
0
  case 'K':
46
0
    val *= 1024;
47
0
    end++;
48
0
    break;
49
0
  default:
50
0
    break;
51
0
  }
52
53
0
  if (strncmp(end, "iB", 2) == 0)
54
0
    end += 2;
55
56
0
  if (endp)
57
0
    *endp = end;
58
59
0
  return val;
60
0
}
61
EXPORT_SYMBOL(strtoull_suffix);
62
63
unsigned long strtoul_suffix(const char *str, char **endp, int base)
64
0
{
65
0
  return strtoull_suffix(str, endp, base);
66
0
}
67
EXPORT_SYMBOL(strtoul_suffix);
68
69
/*
70
 * This function parses strings in the form <startadr>[-endaddr]
71
 * or <startadr>[+size] and fills in start and size accordingly.
72
 * <startadr> and <endadr> can be given in decimal or hex (with 0x prefix)
73
 * and can have an optional G, M, K or k suffix.
74
 *
75
 * examples:
76
 * 0x1000-0x2000 -> start = 0x1000, size = 0x1001
77
 * 0x1000+0x1000 -> start = 0x1000, size = 0x1000
78
 * 0x1000        -> start = 0x1000, size = ~0
79
 * 1M+1k         -> start = 0x100000, size = 0x400
80
 */
81
int parse_area_spec(const char *str, loff_t *start, loff_t *size)
82
0
{
83
0
  char *endp;
84
0
  loff_t end, _start, _size;
85
86
0
  if (!isdigit(*str))
87
0
    return -1;
88
89
0
  _start = strtoull_suffix(str, &endp, 0);
90
91
0
  str = endp;
92
93
0
  if (!*str) {
94
    /* beginning given, but no size, assume maximum size */
95
0
    _size = ~0;
96
0
    goto success;
97
0
  }
98
99
0
  if (*str == '-') {
100
    /* beginning and end given */
101
0
    if (!isdigit(*(str + 1)))
102
0
      return -1;
103
104
0
    end = strtoull_suffix(str + 1, &endp, 0);
105
0
    str = endp;
106
0
    if (end < _start) {
107
0
      printf("end < start\n");
108
0
      return -1;
109
0
    }
110
0
    _size = end - _start + 1;
111
0
    goto success;
112
0
  }
113
114
0
  if (*str == '+') {
115
    /* beginning and size given */
116
0
    if (!isdigit(*(str + 1)))
117
0
      return -1;
118
119
0
    _size = strtoull_suffix(str + 1, &endp, 0);
120
0
    str = endp;
121
0
    goto success;
122
0
  }
123
124
0
  return -1;
125
126
0
success:
127
0
  if (*str && !isspace(*str))
128
0
    return -1;
129
0
  *start = _start;
130
0
  *size = _size;
131
0
  return 0;
132
0
}
133
EXPORT_SYMBOL(parse_area_spec);
134
135
/*
136
 * Common function for parsing options for the 'md', 'mw', 'memcpy', 'memcmp'
137
 * commands.
138
 */
139
int mem_parse_options(int argc, char *argv[], char *optstr, int *mode,
140
          char **sourcefile, char **destfile, int *swab)
141
0
{
142
0
  int opt;
143
144
0
  while((opt = getopt(argc, argv, optstr)) > 0) {
145
0
    switch(opt) {
146
0
    case 'b':
147
0
      *mode = O_RWSIZE_1;
148
0
      break;
149
0
    case 'w':
150
0
      *mode = O_RWSIZE_2;
151
0
      break;
152
0
    case 'l':
153
0
      *mode = O_RWSIZE_4;
154
0
      break;
155
0
    case 'q':
156
0
      *mode = O_RWSIZE_8;
157
0
      break;
158
0
    case 's':
159
0
      *sourcefile = optarg;
160
0
      break;
161
0
    case 'd':
162
0
      *destfile = optarg;
163
0
      break;
164
0
    case 'x':
165
0
      if (!swab)
166
0
        return -EINVAL;
167
0
      *swab = 1;
168
0
      break;
169
0
    default:
170
0
      return -EINVAL;
171
0
    }
172
0
  }
173
174
0
  return 0;
175
0
}
176
177
int memcpy_parse_options(int argc, char *argv[], int *sourcefd,
178
       int *destfd, loff_t *count,
179
       int rwsize, int destmode)
180
0
{
181
0
  loff_t dest, src;
182
0
  int mode = rwsize;
183
0
  char *sourcefile = NULL;
184
0
  char *destfile = NULL;
185
0
  struct  stat statbuf;
186
187
0
  if (mem_parse_options(argc, argv, "bwlqs:d:", &mode, &sourcefile,
188
0
            &destfile, NULL) < 0)
189
0
    return -EINVAL;
190
191
0
  if (optind + 2 > argc)
192
0
    return -EINVAL;
193
194
0
  src = strtoull_suffix(argv[optind], NULL, 0);
195
0
  dest = strtoull_suffix(argv[optind + 1], NULL, 0);
196
197
0
  if (optind + 2 == argc) {
198
0
    if (!sourcefile) {
199
0
      printf("source and count not given\n");
200
0
      return -EINVAL;
201
0
    }
202
0
    if (stat(sourcefile, &statbuf)) {
203
0
      perror("stat");
204
0
      return -1;
205
0
    }
206
0
    *count = statbuf.st_size - src;
207
0
  } else {
208
0
    *count = strtoull_suffix(argv[optind + 2], NULL, 0);
209
0
  }
210
211
0
  sourcefile = sourcefile ?: "/dev/mem";
212
0
  destfile = destfile ?: "/dev/mem";
213
214
0
  *sourcefd = open_and_lseek(sourcefile, mode | O_RDONLY, src);
215
0
  if (*sourcefd < 0) {
216
0
    printf("Could not open source file \"%s\": %m\n", sourcefile);
217
0
    return -1;
218
0
  }
219
220
0
  *destfd = open_and_lseek(destfile, mode | destmode, dest);
221
0
  if (*destfd < 0) {
222
0
    printf("Could not open destination file \"%s\": %m\n", destfile);
223
0
    close(*sourcefd);
224
0
    return -1;
225
0
  }
226
227
0
  return 0;
228
0
}