alsactl: safe state store and memory allocation cleanups

- store new configuration to file + ".new" extension, rename later
- free the configuration tree on exit from load_state()/save_state()
- call snd_config_update_free_global() at the end of command blocks

Signed-off-by: Jaroslav Kysela <perex@perex.cz>
This commit is contained in:
Jaroslav Kysela 2013-04-03 11:13:41 +02:00
parent 6de3c709b3
commit e3e85a851c
2 changed files with 55 additions and 20 deletions

View file

@ -176,6 +176,7 @@ int main(int argc, char *argv[])
if (!strcmp(argv[optind], "init")) { if (!strcmp(argv[optind], "init")) {
res = init(initfile, cardname); res = init(initfile, cardname);
snd_config_update_free_global();
} else if (!strcmp(argv[optind], "store")) { } else if (!strcmp(argv[optind], "store")) {
res = save_state(cfgfile, cardname); res = save_state(cfgfile, cardname);
} else if (!strcmp(argv[optind], "restore")) { } else if (!strcmp(argv[optind], "restore")) {

View file

@ -1546,6 +1546,7 @@ int save_state(const char *file, const char *cardname)
snd_input_t *in; snd_input_t *in;
snd_output_t *out; snd_output_t *out;
int stdio; int stdio;
char *nfile = NULL;
err = snd_config_top(&config); err = snd_config_top(&config);
if (err < 0) { if (err < 0) {
@ -1553,13 +1554,22 @@ int save_state(const char *file, const char *cardname)
return err; return err;
} }
stdio = !strcmp(file, "-"); stdio = !strcmp(file, "-");
if (!stdio) {
nfile = malloc(strlen(file) + 5);
if (nfile == NULL) {
error("No enough memory...");
goto out;
}
strcpy(nfile, file);
strcat(nfile, ".new");
}
if (!stdio && (err = snd_input_stdio_open(&in, file, "r")) >= 0) { if (!stdio && (err = snd_input_stdio_open(&in, file, "r")) >= 0) {
err = snd_config_load(config, in); err = snd_config_load(config, in);
snd_input_close(in); snd_input_close(in);
#if 0 #if 0
if (err < 0) { if (err < 0) {
error("snd_config_load error: %s", snd_strerror(err)); error("snd_config_load error: %s", snd_strerror(err));
return err; goto out;
} }
#endif #endif
} }
@ -1575,17 +1585,19 @@ int save_state(const char *file, const char *cardname)
if (card < 0) { if (card < 0) {
if (first) { if (first) {
if (ignore_nocards) { if (ignore_nocards) {
return 0; err = 0;
goto out;
} else { } else {
error("No soundcards found..."); error("No soundcards found...");
return -ENODEV; err = -ENODEV;
goto out;
} }
} }
break; break;
} }
first = 0; first = 0;
if ((err = get_controls(card, config))) if ((err = get_controls(card, config)))
return err; goto out;
} }
} else { } else {
int cardno; int cardno;
@ -1593,26 +1605,39 @@ int save_state(const char *file, const char *cardname)
cardno = snd_card_get_index(cardname); cardno = snd_card_get_index(cardname);
if (cardno < 0) { if (cardno < 0) {
error("Cannot find soundcard '%s'...", cardname); error("Cannot find soundcard '%s'...", cardname);
return cardno; err = cardno;
goto out;
} }
if ((err = get_controls(cardno, config))) { if ((err = get_controls(cardno, config))) {
return err; goto out;
} }
} }
if (stdio) if (stdio) {
err = snd_output_stdio_attach(&out, stdout, 0); err = snd_output_stdio_attach(&out, stdout, 0);
else } else {
err = snd_output_stdio_open(&out, file, "w"); err = snd_output_stdio_open(&out, nfile, "w");
}
if (err < 0) { if (err < 0) {
error("Cannot open %s for writing: %s", file, snd_strerror(err)); error("Cannot open %s for writing: %s", file, snd_strerror(err));
return -errno; err = -errno;
goto out;
} }
err = snd_config_save(config, out); err = snd_config_save(config, out);
snd_output_close(out); snd_output_close(out);
if (err < 0) if (err < 0) {
error("snd_config_save: %s", snd_strerror(err)); error("snd_config_save: %s", snd_strerror(err));
return 0; } else {
//unlink(file);
err = rename(nfile, file);
if (err < 0)
error("rename failed: %s (%s)", strerror(-err), file);
}
out:
free(nfile);
snd_config_delete(config);
snd_config_update_free_global();
return err;
} }
int load_state(const char *file, const char *initfile, const char *cardname, int load_state(const char *file, const char *initfile, const char *cardname,
@ -1638,7 +1663,7 @@ int load_state(const char *file, const char *initfile, const char *cardname,
snd_input_close(in); snd_input_close(in);
if (err < 0) { if (err < 0) {
error("snd_config_load error: %s", snd_strerror(err)); error("snd_config_load error: %s", snd_strerror(err));
return err; goto out;
} }
} else { } else {
int card, first = 1; int card, first = 1;
@ -1650,7 +1675,8 @@ int load_state(const char *file, const char *initfile, const char *cardname,
card = snd_card_get_index(cardname); card = snd_card_get_index(cardname);
if (card < 0) { if (card < 0) {
error("Cannot find soundcard '%s'...", cardname); error("Cannot find soundcard '%s'...", cardname);
return -ENODEV; err = -ENODEV;
goto out;
} }
goto single; goto single;
} else { } else {
@ -1676,7 +1702,8 @@ single:
} }
if (first) if (first)
finalerr = 0; /* no cards, no error code */ finalerr = 0; /* no cards, no error code */
return finalerr; err = finalerr;
goto out;
} }
if (!cardname) { if (!cardname) {
@ -1691,10 +1718,12 @@ single:
if (card < 0) { if (card < 0) {
if (first) { if (first) {
if (ignore_nocards) { if (ignore_nocards) {
return 0; err = 0;
goto out;
} else { } else {
error("No soundcards found..."); error("No soundcards found...");
return -ENODEV; err = -ENODEV;
goto out;
} }
} }
break; break;
@ -1721,7 +1750,8 @@ single:
cardno = snd_card_get_index(cardname); cardno = snd_card_get_index(cardname);
if (cardno < 0) { if (cardno < 0) {
error("Cannot find soundcard '%s'...", cardname); error("Cannot find soundcard '%s'...", cardname);
return -ENODEV; err = -ENODEV;
goto out;
} }
/* do a check if controls matches state file */ /* do a check if controls matches state file */
if (do_init && set_controls(cardno, config, 0)) { if (do_init && set_controls(cardno, config, 0)) {
@ -1734,8 +1764,12 @@ single:
if ((err = set_controls(cardno, config, 1))) { if ((err = set_controls(cardno, config, 1))) {
initfailed(cardno, "restore", err); initfailed(cardno, "restore", err);
if (!force_restore) if (!force_restore)
goto out;
}
}
err = finalerr;
out:
snd_config_delete(config);
snd_config_update_free_global();
return err; return err;
} }
}
return finalerr;
}