alsa-utils/alsactl/lock.c
Jaroslav Kysela cc5c3357cf alsactl: add the daemon mode
For the plug-and-play hardware, like USB devices, it may be helpful
to manage the sound state periodically, before the devices are removed.

This change implements new commands 'daemon' and 'rdaemon' to save
the sound state in defined intervals when the sound controls are changed.

The udev rules can notify the daemon using the 'kill' or 'nrestore'
commands to rescan available cards in the system.

Signed-off-by: Jaroslav Kysela <perex@perex.cz>
2013-04-05 13:47:18 +02:00

124 lines
2.6 KiB
C

/*
* Advanced Linux Sound Architecture Control Program
* Copyright (c) by Jaroslav Kysela <perex@perex.cz>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "aconfig.h"
#include "version.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <sys/stat.h>
#include "alsactl.h"
static int state_lock_(const char *file, int lock, int timeout)
{
int fd = -1, err = 0;
struct flock lck;
struct stat st;
char lcktxt[11];
char *nfile;
if (!do_lock)
return 0;
nfile = malloc(strlen(file) + 6);
if (nfile == NULL) {
error("No enough memory...");
return -ENOMEM;
}
strcpy(nfile, file);
strcat(nfile, ".lock");
lck.l_type = lock ? F_WRLCK : F_UNLCK;
lck.l_whence = SEEK_SET;
lck.l_start = 0;
lck.l_len = 11;
lck.l_pid = 0;
if (lock) {
sprintf(lcktxt, "%10li\n", (long)getpid());
} else {
sprintf(lcktxt, "%10s\n", "");
}
while (fd < 0 && timeout-- > 0) {
fd = open(nfile, O_RDWR);
if (fd < 0) {
fd = open(nfile, O_RDWR|O_CREAT|O_EXCL, 0644);
if (fd < 0) {
if (errno == EBUSY || errno == EAGAIN) {
sleep(1);
timeout--;
} else {
err = -errno;
goto out;
}
}
}
}
if (fd < 0 && timeout <= 0) {
err = -EBUSY;
goto out;
}
if (fstat(fd, &st) < 0) {
err = -errno;
goto out;
}
if (st.st_size != 11) {
if (write(fd, lcktxt, 11) != 11) {
err = -EIO;
goto out;
}
if (lseek(fd, 0, SEEK_SET)) {
err = -errno;
goto out;
}
}
while (timeout > 0) {
if (fcntl(fd, F_SETLK, &lck) < 0) {
sleep(1);
timeout--;
} else {
break;
}
}
if (timeout <= 0) {
err = -EBUSY;
goto out;
}
if (write(fd, lcktxt, 11) != 11) {
err = -EIO;
goto out;
}
out:
free(nfile);
return err;
}
int state_lock(const char *file, int lock, int timeout)
{
int err;
err = state_lock_(file, lock, timeout);
if (err < 0)
error("file %s %slock error: %s", file,
lock ? "" : "un", strerror(-err));
return err;
}