问题
Android10;高通平台
使用下面date命令修改时间日期,时分秒生效,年月日不生效
=> date -D YYYY-MM-DD hh:mm:ss
路径
\android\external\toybox\toys\posix\date.c
\android\external\toybox\lib\args.c
找原因
首先在命令行键入
=> adb shell date -D 2020-10-01 22:59:00
去代码看一下参数传的有没有什么问题
\android\external\toybox\main.c
// argc:参数的数量 argv: 参数
int main(int argc, char *argv[])
{
if (!*argv) return 127;
if (CFG_TOYBOX) {
// Call the multiplexer, adjusting this argv[] to be its' argv[1].
// (It will adjust it back before calling toy_exec().)
toys.argv = argv-1;
toybox_main();
}
...
}
argc = 4,
argv[0] = date, argv[1] = -D, argv[2] = 2020-10-01, argv[3] = 22:59:00
很明显这里并没有什么问题,我们接着往下看调用toybox_main()
// Multiplexer command, first argument is command to run, rest are args to that.
// If first argument starts with - output list of command install paths.
void toybox_main(void)
{
static char *toy_paths[]={"usr/","bin/","sbin/",0};
int i, len = 0;
if (toys.argv[1]) {
toy_exec(toys.argv+1);
if (0<readlink(toys.argv[1], libbuf, sizeof(libbuf)))
toy_exec_which(toy_find(basename(libbuf)), toys.argv);
}
...
}
参数传给toys.argv,我们看一下toys.argv里面是怎么存放数据的:
其中toys.argv[0]为空,toys.argv[1] = date, toys.argv[2] = -D, toys.argv[3] = 2020-10-08, toys.argv[4] = 22:59:00
还是没有问题,我们接着往下看
// Lookup internal toybox command to run via argv[0]
void toy_exec(char *argv[])
{
toy_exec_which(toy_find(basename(*argv)), argv);
}
// Run an internal toybox command.
void toy_exec_which(struct toy_list *which, char *argv[])
{
...
// Run command
toy_init(which, argv);
if (toys.which) toys.which->toy_main();
xexit();
}
void toy_init(struct toy_list *which, char *argv[])
{
void *oldwhich = toys.which;
...
// Continue to portion of init needed by standalone commands
toy_singleinit(which, argv);
}
static void toy_singleinit(struct toy_list *which, char *argv[])
{
toys.which = which;
toys.argv = argv;
...
if (NEED_OPTIONS && which->options) get_optflags();
else {
toys.optargs = argv+1;
for (toys.optc = 0; toys.optargs[toys.optc]; toys.optc++);
}
toys.old_umask = umask(0);
if (!(which->flags & TOYFLAG_UMASK)) umask(toys.old_umask);
toys.signalfd--;
toys.toycount = ARRAY_LEN(toy_list);
}
这里走的分支是get_optflags()
get_optflags()是对参数的解析,通过log可以发现get_optflags的for循环只循环了gof.argc=1(-D),gof.argc=3(22:59:00),漏掉了gof.argc=2就是年月日
先看gof.argc=1的循环:
gof.arg是字符型指针,指向toys.argv[1] = -D 的”-”,++后就指向了”D”, 所以传给gotflag()的参数是”D”
// Fill out toys.optflags, toys.optargs, and this[] from toys.argv
void get_optflags(void)
{
struct getoptflagstate gof;
struct opts *catch;
unsigned long long saveflags;
char *letters[]={"s",""};
// Iterate through command line arguments, skipping argv[0]
for (gof.argc=1; toys.argv[gof.argc]; gof.argc++) {
gof.arg = toys.argv[gof.argc];
catch = NULL;
// Parse this argument
if (gof.stopearly>1) goto notflag;
gof.nodash_now = 0;
// Various things with dashes
if (*gof.arg == '-') {
// Handle -
if (!gof.arg[1]) goto notflag;
gof.arg++;
if (*gof.arg=='-') {
struct longopts *lo;
gof.arg++;
// Handle --
if (!*gof.arg) {
gof.stopearly += 2;
continue;
}
// do we match a known --longopt?
for (lo = gof.longopts; lo; lo = lo->next) {
if (!strncmp(gof.arg, lo->str, lo->len)) {
if (!gof.arg[lo->len]) gof.arg = 0;
else if (gof.arg[lo->len] == '=' && lo->opt->type)
gof.arg += lo->len;
else continue;
// It's a match.
catch = lo->opt;
break;
}
}
// Should we handle this --longopt as a non-option argument?
if (!lo && gof.noerror) {
gof.arg -= 2;
goto notflag;
}
// Long option parsed, handle option.
gotflag(&gof, catch);
continue;
}
// Handle things that don't start with a dash.
} else {
if (gof.nodash && (gof.nodash>1 || gof.argc == 1)) gof.nodash_now = 1;
else goto notflag;
}
// At this point, we have the args part of -args. Loop through
// each entry (could be -abc meaning -a -b -c)
saveflags = toys.optflags;
while (*gof.arg) {
// Identify next option char.
for (catch = gof.opts; catch; catch = catch->next)
if (*gof.arg == catch->c)
if (!((catch->flags&4) && gof.arg[1])) break;
// Handle option char (advancing past what was used)
if (gotflag(&gof, catch) ) {
toys.optflags = saveflags;
gof.arg = toys.argv[gof.argc];
goto notflag;
}
}
continue;
// Not a flag, save value in toys.optargs[]
notflag:
if (gof.stopearly) gof.stopearly++;
toys.optargs[toys.optc++] = toys.argv[gof.argc];
}
...
}
看下为什么会把年月日跳过,gotflag()中选项(-option)解析, gotflag(&gof, catch);
传入的gof->arg 指向 ”D”, gof->arg有参数++指向” ”
// Use getoptflagstate to parse one command line option from argv
static int gotflag(struct getoptflagstate *gof, struct opts *opt)
{
int type;
// Set flags
toys.optflags |= opt->dex[1];
gof->excludes |= opt->dex[2];
if (opt->flags&2) gof->stopearly=2;
...
// Does this option take an argument?
if (!gof->arg) {
if (opt->flags & 8) return 0;
gof->arg = "";
} else gof->arg++; // 指向" "
type = opt->type; // type = ":"
...
return 0;
}
char*arg = ” ”
gof->nodash_now = 0, !arg[0] = 1, opt->flags = 0
进行判断,++argc,argc由1变为2,也是导致年月日被跳过的原因
这时arg指向“2020-10-08”, opt->arg指向“2020-10-08”
解决方法
由于args.c是解析命令行参数的共用文件,没把握最好不要修改,很容易影响到其他命令的解析。我们可以让被跳过的参数2为任意字符,如("+"可为任意字符)
=> date -D + YYYY-MM-DDhh:mm:ss
另外也可以使用
=> date MMDDhhmmYYYY.ss set
来设置时间