2 * RouterBOOT configuration utility
4 * Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org>
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 as published
8 * by the Free Software Foundation.
20 #include <linux/limits.h>
25 #define RBCFG_TMP_FILE "/tmp/.rbcfg"
26 #define RBCFG_MTD_NAME "soft_config"
28 #define RB_ERR_NOTFOUND 1
29 #define RB_ERR_INVALID 2
30 #define RB_ERR_NOMEM 3
33 #define ARRAY_SIZE(_a) (sizeof((_a)) / sizeof((_a)[0]))
51 #define RBCFG_ENV_TYPE_U32 0
57 const struct rbcfg_value
*values
;
61 #define CMD_FLAG_USES_CFG 0x01
63 struct rbcfg_command
{
67 int (*exec
)(int argc
, const char *argv
[]);
70 static void usage(void);
74 static struct rbcfg_ctx
*rbcfg_ctx
;
75 static char *rbcfg_name
;
77 #define CFG_U32(_name, _desc, _val) { \
83 static const struct rbcfg_value rbcfg_boot_delay
[] = {
84 CFG_U32("1", "1 second", RB_BOOT_DELAY_1SEC
),
85 CFG_U32("2", "2 seconds", RB_BOOT_DELAY_2SEC
),
86 CFG_U32("3", "3 seconds", RB_BOOT_DELAY_3SEC
),
87 CFG_U32("4", "4 seconds", RB_BOOT_DELAY_4SEC
),
88 CFG_U32("5", "5 seconds", RB_BOOT_DELAY_5SEC
),
89 CFG_U32("6", "6 seconds", RB_BOOT_DELAY_6SEC
),
90 CFG_U32("7", "7 seconds", RB_BOOT_DELAY_7SEC
),
91 CFG_U32("8", "8 seconds", RB_BOOT_DELAY_8SEC
),
92 CFG_U32("9", "9 seconds", RB_BOOT_DELAY_9SEC
),
95 static const struct rbcfg_value rbcfg_boot_device
[] = {
96 CFG_U32("eth", "boot over Ethernet",
97 RB_BOOT_DEVICE_ETHER
),
98 CFG_U32("nandeth", "boot from NAND, if fail then Ethernet",
99 RB_BOOT_DEVICE_NANDETH
),
100 CFG_U32("ethnand", "boot Ethernet once, then NAND",
101 RB_BOOT_DEVICE_ETHONCE
),
102 CFG_U32("nand", "boot from NAND only",
103 RB_BOOT_DEVICE_NANDONLY
),
104 CFG_U32("flash", "boot in flash configuration mode",
105 RB_BOOT_DEVICE_FLASHCFG
),
106 CFG_U32("flashnand", "boot in flash configuration mode once, then NAND",
107 RB_BOOT_DEVICE_FLSHONCE
),
110 static const struct rbcfg_value rbcfg_boot_key
[] = {
111 CFG_U32("any", "any key", RB_BOOT_KEY_ANY
),
112 CFG_U32("del", "<Delete> key only", RB_BOOT_KEY_DEL
),
115 static const struct rbcfg_value rbcfg_boot_protocol
[] = {
116 CFG_U32("bootp", "BOOTP protocol", RB_BOOT_PROTOCOL_BOOTP
),
117 CFG_U32("dhcp", "DHCP protocol", RB_BOOT_PROTOCOL_DHCP
),
120 static const struct rbcfg_value rbcfg_uart_speed
[] = {
121 CFG_U32("115200", "", RB_UART_SPEED_115200
),
122 CFG_U32("57600", "", RB_UART_SPEED_57600
),
123 CFG_U32("38400", "", RB_UART_SPEED_38400
),
124 CFG_U32("19200", "", RB_UART_SPEED_19200
),
125 CFG_U32("9600", "", RB_UART_SPEED_9600
),
126 CFG_U32("4800", "", RB_UART_SPEED_4800
),
127 CFG_U32("2400", "", RB_UART_SPEED_2400
),
128 CFG_U32("1200", "", RB_UART_SPEED_1200
),
129 CFG_U32("off", "disable console output", RB_UART_SPEED_OFF
),
132 static const struct rbcfg_value rbcfg_cpu_mode
[] = {
133 CFG_U32("powersave", "power save", RB_CPU_MODE_POWERSAVE
),
134 CFG_U32("regular", "regular (better for -0c environment)",
135 RB_CPU_MODE_REGULAR
),
138 static const struct rbcfg_value rbcfg_booter
[] = {
139 CFG_U32("regular", "load regular booter", RB_BOOTER_REGULAR
),
140 CFG_U32("backup", "force backup-booter loading", RB_BOOTER_BACKUP
),
143 static const struct rbcfg_env rbcfg_envs
[] = {
145 .name
= "boot_delay",
146 .id
= RB_ID_BOOT_DELAY
,
147 .type
= RBCFG_ENV_TYPE_U32
,
148 .values
= rbcfg_boot_delay
,
149 .num_values
= ARRAY_SIZE(rbcfg_boot_delay
),
151 .name
= "boot_device",
152 .id
= RB_ID_BOOT_DEVICE
,
153 .type
= RBCFG_ENV_TYPE_U32
,
154 .values
= rbcfg_boot_device
,
155 .num_values
= ARRAY_SIZE(rbcfg_boot_device
),
158 .id
= RB_ID_BOOT_KEY
,
159 .type
= RBCFG_ENV_TYPE_U32
,
160 .values
= rbcfg_boot_key
,
161 .num_values
= ARRAY_SIZE(rbcfg_boot_key
),
163 .name
= "boot_protocol",
164 .id
= RB_ID_BOOT_PROTOCOL
,
165 .type
= RBCFG_ENV_TYPE_U32
,
166 .values
= rbcfg_boot_protocol
,
167 .num_values
= ARRAY_SIZE(rbcfg_boot_protocol
),
171 .type
= RBCFG_ENV_TYPE_U32
,
172 .values
= rbcfg_booter
,
173 .num_values
= ARRAY_SIZE(rbcfg_booter
),
176 .id
= RB_ID_CPU_MODE
,
177 .type
= RBCFG_ENV_TYPE_U32
,
178 .values
= rbcfg_cpu_mode
,
179 .num_values
= ARRAY_SIZE(rbcfg_cpu_mode
),
181 .name
= "uart_speed",
182 .id
= RB_ID_UART_SPEED
,
183 .type
= RBCFG_ENV_TYPE_U32
,
184 .values
= rbcfg_uart_speed
,
185 .num_values
= ARRAY_SIZE(rbcfg_uart_speed
),
189 static inline uint16_t
190 get_u16(const void *buf
)
192 const uint8_t *p
= buf
;
194 return ((uint16_t) p
[1] + ((uint16_t) p
[0] << 8));
197 static inline uint32_t
198 get_u32(const void *buf
)
200 const uint8_t *p
= buf
;
202 return ((uint32_t) p
[3] + ((uint32_t) p
[2] << 8) +
203 ((uint32_t) p
[1] << 16) + ((uint32_t) p
[0] << 24));
207 put_u32(void *buf
, uint32_t val
)
212 p
[2] = (val
>> 8) & 0xff;
213 p
[1] = (val
>> 16) & 0xff;
214 p
[0] = (val
>> 24) & 0xff;
218 rbcfg_find_tag(struct rbcfg_ctx
*ctx
, uint16_t tag_id
, uint16_t *tag_len
,
223 char *buf
= ctx
->buf
;
224 unsigned int buflen
= ctx
->buflen
;
225 int ret
= RB_ERR_NOTFOUND
;
227 /* skip magic and CRC value */
243 if (id
== RB_ID_TERMINATOR
)
261 fprintf(stderr
, "no tag found with id=%u\n", tag_id
);
267 rbcfg_get_u32(struct rbcfg_ctx
*ctx
, uint16_t id
, uint32_t *val
)
273 err
= rbcfg_find_tag(ctx
, id
, &tag_len
, &tag_data
);
277 *val
= get_u32(tag_data
);
282 rbcfg_set_u32(struct rbcfg_ctx
*ctx
, uint16_t id
, uint32_t val
)
288 err
= rbcfg_find_tag(ctx
, id
, &tag_len
, &tag_data
);
292 put_u32(tag_data
, val
);
296 char *rbcfg_find_mtd(const char *name
, int *erase_size
)
305 f
= fopen("/proc/mtd", "r");
311 p
= fgets(dev
, sizeof(dev
), f
);
315 if (!strstr(dev
, name
))
318 err
= sscanf(dev
, "mtd%d: %08x", &mtd_num
, erase_size
);
322 sprintf(dev
, "/dev/mtdblock%d", mtd_num
);
327 if ((s
.st_mode
& S_IFBLK
) == 0)
330 ret
= malloc(strlen(dev
) + 1);
334 strncpy(ret
, dev
, strlen(dev
) + 1);
343 rbcfg_check_tmp(struct rbcfg_ctx
*ctx
)
348 err
= stat(ctx
->tmp_file
, &s
);
352 if ((s
.st_mode
& S_IFREG
) == 0)
355 if (s
.st_size
!= ctx
->buflen
)
362 rbcfg_load(struct rbcfg_ctx
*ctx
)
365 uint32_t crc_orig
, crc
;
371 tmp
= rbcfg_check_tmp(ctx
);
372 name
= (tmp
) ? ctx
->tmp_file
: ctx
->mtd_device
;
374 fd
= open(name
, O_RDONLY
);
376 fprintf(stderr
, "unable to open %s\n", name
);
381 err
= read(fd
, ctx
->buf
, ctx
->buflen
);
382 if (err
!= ctx
->buflen
) {
383 fprintf(stderr
, "unable to read from %s\n", name
);
388 magic
= get_u32(ctx
->buf
);
389 if (magic
!= RB_MAGIC_SOFT
) {
390 fprintf(stderr
, "invalid configuration\n");
391 err
= RB_ERR_INVALID
;
395 crc_orig
= get_u32(ctx
->buf
+ 4);
396 put_u32(ctx
->buf
+ 4, 0);
397 crc
= cyg_ether_crc32((unsigned char *) ctx
->buf
, ctx
->buflen
);
398 if (crc
!= crc_orig
) {
399 fprintf(stderr
, "configuration has CRC error\n");
400 err
= RB_ERR_INVALID
;
416 struct rbcfg_ctx
*ctx
;
420 mtd_device
= rbcfg_find_mtd(RBCFG_MTD_NAME
, &buflen
);
422 fprintf(stderr
, "unable to find configuration\n");
423 return RB_ERR_NOTFOUND
;
426 ctx
= malloc(sizeof(struct rbcfg_ctx
) + buflen
);
432 ctx
->mtd_device
= mtd_device
;
433 ctx
->tmp_file
= RBCFG_TMP_FILE
;
434 ctx
->buflen
= buflen
;
435 ctx
->buf
= (char *) &ctx
[1];
437 err
= rbcfg_load(ctx
);
452 rbcfg_update(int tmp
)
454 struct rbcfg_ctx
*ctx
= rbcfg_ctx
;
460 put_u32(ctx
->buf
, RB_MAGIC_SOFT
);
461 put_u32(ctx
->buf
+ 4, 0);
462 crc
= cyg_ether_crc32((unsigned char *) ctx
->buf
, ctx
->buflen
);
463 put_u32(ctx
->buf
+ 4, crc
);
465 name
= (tmp
) ? ctx
->tmp_file
: ctx
->mtd_device
;
466 fd
= open(name
, O_WRONLY
| O_CREAT
);
468 fprintf(stderr
, "unable to open %s for writing\n", name
);
473 err
= write(fd
, ctx
->buf
, ctx
->buflen
);
474 if (err
!= ctx
->buflen
) {
491 struct rbcfg_ctx
*ctx
;
494 free(ctx
->mtd_device
);
498 static const struct rbcfg_value
*
499 rbcfg_env_find(const struct rbcfg_env
*env
, const char *name
)
503 for (i
= 0; i
< env
->num_values
; i
++) {
504 const struct rbcfg_value
*v
= &env
->values
[i
];
506 if (strcmp(v
->name
, name
) == 0)
513 static const struct rbcfg_value
*
514 rbcfg_env_find_u32(const struct rbcfg_env
*env
, uint32_t val
)
518 for (i
= 0; i
< env
->num_values
; i
++) {
519 const struct rbcfg_value
*v
= &env
->values
[i
];
521 if (v
->val
.u32
== val
)
529 rbcfg_env_get_u32(const struct rbcfg_env
*env
)
531 const struct rbcfg_value
*v
;
535 err
= rbcfg_get_u32(rbcfg_ctx
, env
->id
, &val
);
539 v
= rbcfg_env_find_u32(env
, val
);
541 fprintf(stderr
, "unknown value %08x found for %s\n",
550 rbcfg_env_set_u32(const struct rbcfg_env
*env
, const char *data
)
552 const struct rbcfg_value
*v
;
555 v
= rbcfg_env_find(env
, data
);
557 fprintf(stderr
, "invalid value '%s'\n", data
);
558 return RB_ERR_INVALID
;
561 err
= rbcfg_set_u32(rbcfg_ctx
, env
->id
, v
->val
.u32
);
566 rbcfg_env_get(const struct rbcfg_env
*env
)
568 const char *ret
= NULL
;
571 case RBCFG_ENV_TYPE_U32
:
572 ret
= rbcfg_env_get_u32(env
);
580 rbcfg_env_set(const struct rbcfg_env
*env
, const char *data
)
585 case RBCFG_ENV_TYPE_U32
:
586 ret
= rbcfg_env_set_u32(env
, data
);
594 rbcfg_cmd_apply(int argc
, const char *argv
[])
596 return rbcfg_update(0);
600 rbcfg_cmd_help(int argc
, const char *argv
[])
607 rbcfg_cmd_get(int argc
, const char *argv
[])
609 int err
= RB_ERR_NOTFOUND
;
614 return RB_ERR_INVALID
;
617 for (i
= 0; i
< ARRAY_SIZE(rbcfg_envs
); i
++) {
618 const struct rbcfg_env
*env
= &rbcfg_envs
[i
];
621 if (strcmp(env
->name
, argv
[0]))
624 value
= rbcfg_env_get(env
);
626 fprintf(stdout
, "%s\n", value
);
636 rbcfg_cmd_set(int argc
, const char *argv
[])
638 int err
= RB_ERR_INVALID
;
642 /* not enough parameters */
644 return RB_ERR_INVALID
;
647 for (i
= 0; i
< ARRAY_SIZE(rbcfg_envs
); i
++) {
648 const struct rbcfg_env
*env
= &rbcfg_envs
[i
];
650 if (strcmp(env
->name
, argv
[0]))
653 err
= rbcfg_env_set(env
, argv
[1]);
655 err
= rbcfg_update(1);
663 rbcfg_cmd_show(int argc
, const char *argv
[])
669 return RB_ERR_INVALID
;
672 for (i
= 0; i
< ARRAY_SIZE(rbcfg_envs
); i
++) {
673 const struct rbcfg_env
*env
= &rbcfg_envs
[i
];
676 value
= rbcfg_env_get(env
);
678 fprintf(stdout
, "%s=%s\n", env
->name
, value
);
684 static const struct rbcfg_command rbcfg_commands
[] = {
688 "\t- write configuration to the mtd device",
689 .flags
= CMD_FLAG_USES_CFG
,
690 .exec
= rbcfg_cmd_apply
,
694 "\t- show this screen",
695 .exec
= rbcfg_cmd_help
,
698 .usage
= "get <name>\n"
699 "\t- get value of the configuration option <name>",
700 .flags
= CMD_FLAG_USES_CFG
,
701 .exec
= rbcfg_cmd_get
,
704 .usage
= "set <name> <value>\n"
705 "\t- set value of the configuration option <name> to <value>",
706 .flags
= CMD_FLAG_USES_CFG
,
707 .exec
= rbcfg_cmd_set
,
711 "\t- show value of all configuration options",
712 .flags
= CMD_FLAG_USES_CFG
,
713 .exec
= rbcfg_cmd_show
,
724 fprintf(stderr
, "Usage: %s <command>\n", rbcfg_name
);
726 fprintf(stderr
, "\nCommands:\n");
727 for (i
= 0; i
< ARRAY_SIZE(rbcfg_commands
); i
++) {
728 const struct rbcfg_command
*cmd
;
729 cmd
= &rbcfg_commands
[i
];
731 len
= snprintf(buf
, sizeof(buf
), "%s", cmd
->usage
);
733 fprintf(stderr
, "%s\n", buf
);
736 fprintf(stderr
, "\nConfiguration options:\n");
737 for (i
= 0; i
< ARRAY_SIZE(rbcfg_envs
); i
++) {
738 const struct rbcfg_env
*env
;
741 env
= &rbcfg_envs
[i
];
742 fprintf(stderr
, "\n%s:\n", env
->name
);
743 for (j
= 0; j
< env
->num_values
; j
++) {
744 const struct rbcfg_value
*v
= &env
->values
[j
];
745 fprintf(stderr
, "\t%-12s %s\n", v
->name
, v
->desc
);
748 fprintf(stderr
, "\n");
751 int main(int argc
, const char *argv
[])
753 const struct rbcfg_command
*cmd
= NULL
;
757 rbcfg_name
= (char *) argv
[0];
764 for (i
= 0; i
< ARRAY_SIZE(rbcfg_commands
); i
++) {
765 if (strcmp(rbcfg_commands
[i
].command
, argv
[1]) == 0) {
766 cmd
= &rbcfg_commands
[i
];
772 fprintf(stderr
, "unknown command '%s'\n", argv
[1]);
780 if (cmd
->flags
& CMD_FLAG_USES_CFG
) {
786 ret
= cmd
->exec(argc
, argv
);
788 if (cmd
->flags
& CMD_FLAG_USES_CFG
)