1c72fcc34Sopenharmony_ci/* 2c72fcc34Sopenharmony_ci * Advanced Linux Sound Architecture Control Program 3c72fcc34Sopenharmony_ci * Copyright (c) by Jaroslav Kysela <perex@perex.cz> 4c72fcc34Sopenharmony_ci * 5c72fcc34Sopenharmony_ci * 6c72fcc34Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 7c72fcc34Sopenharmony_ci * it under the terms of the GNU General Public License as published by 8c72fcc34Sopenharmony_ci * the Free Software Foundation; either version 2 of the License, or 9c72fcc34Sopenharmony_ci * (at your option) any later version. 10c72fcc34Sopenharmony_ci * 11c72fcc34Sopenharmony_ci * This program is distributed in the hope that it will be useful, 12c72fcc34Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 13c72fcc34Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14c72fcc34Sopenharmony_ci * GNU General Public License for more details. 15c72fcc34Sopenharmony_ci * 16c72fcc34Sopenharmony_ci * You should have received a copy of the GNU General Public License 17c72fcc34Sopenharmony_ci * along with this program; if not, write to the Free Software 18c72fcc34Sopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19c72fcc34Sopenharmony_ci * 20c72fcc34Sopenharmony_ci */ 21c72fcc34Sopenharmony_ci 22c72fcc34Sopenharmony_ci#include "aconfig.h" 23c72fcc34Sopenharmony_ci#include "version.h" 24c72fcc34Sopenharmony_ci#include <stdio.h> 25c72fcc34Sopenharmony_ci#include <stdlib.h> 26c72fcc34Sopenharmony_ci#include <unistd.h> 27c72fcc34Sopenharmony_ci#include <fcntl.h> 28c72fcc34Sopenharmony_ci#include <errno.h> 29c72fcc34Sopenharmony_ci#include <string.h> 30c72fcc34Sopenharmony_ci#include <signal.h> 31c72fcc34Sopenharmony_ci#include <sys/time.h> 32c72fcc34Sopenharmony_ci#include <sys/stat.h> 33c72fcc34Sopenharmony_ci#include "alsactl.h" 34c72fcc34Sopenharmony_ci#include "os_compat.h" 35c72fcc34Sopenharmony_ci 36c72fcc34Sopenharmony_ci#define PATH_SIZE 512 37c72fcc34Sopenharmony_ci 38c72fcc34Sopenharmony_cistatic int alarm_flag; 39c72fcc34Sopenharmony_ci 40c72fcc34Sopenharmony_cistatic void signal_handler_alarm(int sig ATTRIBUTE_UNUSED) 41c72fcc34Sopenharmony_ci{ 42c72fcc34Sopenharmony_ci alarm_flag = 1; 43c72fcc34Sopenharmony_ci} 44c72fcc34Sopenharmony_ci 45c72fcc34Sopenharmony_cistatic int state_lock_(const char *lock_file, int lock, int timeout, int _fd) 46c72fcc34Sopenharmony_ci{ 47c72fcc34Sopenharmony_ci int fd = -1, err = 0; 48c72fcc34Sopenharmony_ci struct flock lck; 49c72fcc34Sopenharmony_ci struct stat st; 50c72fcc34Sopenharmony_ci char lcktxt[14]; 51c72fcc34Sopenharmony_ci struct sigaction sig_alarm, sig_alarm_orig; 52c72fcc34Sopenharmony_ci struct itimerval itv; 53c72fcc34Sopenharmony_ci 54c72fcc34Sopenharmony_ci if (do_lock <= 0) 55c72fcc34Sopenharmony_ci return 0; 56c72fcc34Sopenharmony_ci 57c72fcc34Sopenharmony_ci lck.l_type = lock ? F_WRLCK : F_UNLCK; 58c72fcc34Sopenharmony_ci lck.l_whence = SEEK_SET; 59c72fcc34Sopenharmony_ci lck.l_start = 0; 60c72fcc34Sopenharmony_ci lck.l_len = 11; 61c72fcc34Sopenharmony_ci lck.l_pid = 0; 62c72fcc34Sopenharmony_ci if (lock) { 63c72fcc34Sopenharmony_ci snprintf(lcktxt, sizeof(lcktxt), "%10li\n", (long)getpid()); 64c72fcc34Sopenharmony_ci } else { 65c72fcc34Sopenharmony_ci snprintf(lcktxt, sizeof(lcktxt), "%10s\n", ""); 66c72fcc34Sopenharmony_ci fd = _fd; 67c72fcc34Sopenharmony_ci } 68c72fcc34Sopenharmony_ci while (fd < 0 && timeout-- > 0) { 69c72fcc34Sopenharmony_ci fd = open(lock_file, O_RDWR); 70c72fcc34Sopenharmony_ci if (!lock && fd < 0) { 71c72fcc34Sopenharmony_ci err = -EIO; 72c72fcc34Sopenharmony_ci goto out; 73c72fcc34Sopenharmony_ci } 74c72fcc34Sopenharmony_ci if (fd < 0) { 75c72fcc34Sopenharmony_ci fd = open(lock_file, O_RDWR|O_CREAT|O_EXCL, 0644); 76c72fcc34Sopenharmony_ci if (fd < 0) { 77c72fcc34Sopenharmony_ci if (errno == EBUSY || errno == EAGAIN) { 78c72fcc34Sopenharmony_ci sleep(1); 79c72fcc34Sopenharmony_ci continue; 80c72fcc34Sopenharmony_ci } 81c72fcc34Sopenharmony_ci if (errno == EEXIST) { 82c72fcc34Sopenharmony_ci fd = open(lock_file, O_RDWR); 83c72fcc34Sopenharmony_ci if (fd >= 0) 84c72fcc34Sopenharmony_ci break; 85c72fcc34Sopenharmony_ci } 86c72fcc34Sopenharmony_ci err = -errno; 87c72fcc34Sopenharmony_ci goto out; 88c72fcc34Sopenharmony_ci } 89c72fcc34Sopenharmony_ci } 90c72fcc34Sopenharmony_ci } 91c72fcc34Sopenharmony_ci if (fd < 0 && timeout <= 0) { 92c72fcc34Sopenharmony_ci err = -EBUSY; 93c72fcc34Sopenharmony_ci goto out; 94c72fcc34Sopenharmony_ci } 95c72fcc34Sopenharmony_ci if (fstat(fd, &st) < 0) { 96c72fcc34Sopenharmony_ci err = -errno; 97c72fcc34Sopenharmony_ci goto out; 98c72fcc34Sopenharmony_ci } 99c72fcc34Sopenharmony_ci if (st.st_size != 11 || !lock) { 100c72fcc34Sopenharmony_ci if (write(fd, lcktxt, 11) != 11) { 101c72fcc34Sopenharmony_ci err = -EIO; 102c72fcc34Sopenharmony_ci goto out; 103c72fcc34Sopenharmony_ci } 104c72fcc34Sopenharmony_ci if (lock && lseek(fd, 0, SEEK_SET)) { 105c72fcc34Sopenharmony_ci err = -errno; 106c72fcc34Sopenharmony_ci goto out; 107c72fcc34Sopenharmony_ci } 108c72fcc34Sopenharmony_ci } 109c72fcc34Sopenharmony_ci alarm_flag = 0; 110c72fcc34Sopenharmony_ci memset(&sig_alarm, 0, sizeof(sig_alarm)); 111c72fcc34Sopenharmony_ci sigemptyset(&sig_alarm.sa_mask); 112c72fcc34Sopenharmony_ci sig_alarm.sa_handler = signal_handler_alarm; 113c72fcc34Sopenharmony_ci if (sigaction(SIGALRM, &sig_alarm, &sig_alarm_orig) < 0) { 114c72fcc34Sopenharmony_ci err = -ENXIO; 115c72fcc34Sopenharmony_ci goto out; 116c72fcc34Sopenharmony_ci } 117c72fcc34Sopenharmony_ci memset(&itv, 0, sizeof(itv)); 118c72fcc34Sopenharmony_ci itv.it_value.tv_sec = timeout; 119c72fcc34Sopenharmony_ci if (setitimer(ITIMER_REAL, &itv, NULL) < 0) { 120c72fcc34Sopenharmony_ci err = -ENXIO; 121c72fcc34Sopenharmony_ci sigaction(SIGALRM, &sig_alarm_orig, NULL); 122c72fcc34Sopenharmony_ci goto out; 123c72fcc34Sopenharmony_ci } 124c72fcc34Sopenharmony_ci while (alarm_flag == 0) { 125c72fcc34Sopenharmony_ci if (fcntl(fd, F_SETLKW, &lck) == 0) 126c72fcc34Sopenharmony_ci break; 127c72fcc34Sopenharmony_ci if (errno == EAGAIN || errno == ERESTART) 128c72fcc34Sopenharmony_ci continue; 129c72fcc34Sopenharmony_ci } 130c72fcc34Sopenharmony_ci memset(&itv, 0, sizeof(itv)); 131c72fcc34Sopenharmony_ci setitimer(ITIMER_REAL, &itv, NULL); 132c72fcc34Sopenharmony_ci sigaction(SIGALRM, &sig_alarm_orig, NULL); 133c72fcc34Sopenharmony_ci if (alarm_flag) { 134c72fcc34Sopenharmony_ci err = -EBUSY; 135c72fcc34Sopenharmony_ci goto out; 136c72fcc34Sopenharmony_ci } 137c72fcc34Sopenharmony_ci if (lock) { 138c72fcc34Sopenharmony_ci if (write(fd, lcktxt, 11) != 11) { 139c72fcc34Sopenharmony_ci err = -EIO; 140c72fcc34Sopenharmony_ci goto out; 141c72fcc34Sopenharmony_ci } 142c72fcc34Sopenharmony_ci return fd; 143c72fcc34Sopenharmony_ci } 144c72fcc34Sopenharmony_ci err = 0; 145c72fcc34Sopenharmony_ci 146c72fcc34Sopenharmony_ciout: 147c72fcc34Sopenharmony_ci if (fd >= 0) 148c72fcc34Sopenharmony_ci close(fd); 149c72fcc34Sopenharmony_ci return err; 150c72fcc34Sopenharmony_ci} 151c72fcc34Sopenharmony_ci 152c72fcc34Sopenharmony_cistatic void state_lock_file(char *buf, size_t buflen) 153c72fcc34Sopenharmony_ci{ 154c72fcc34Sopenharmony_ci if (lockfile[0] == '/') 155c72fcc34Sopenharmony_ci snprintf(buf, buflen, "%s", lockfile); 156c72fcc34Sopenharmony_ci else 157c72fcc34Sopenharmony_ci snprintf(buf, buflen, "%s/%s", lockpath, lockfile); 158c72fcc34Sopenharmony_ci} 159c72fcc34Sopenharmony_ci 160c72fcc34Sopenharmony_ciint state_lock(const char *file, int timeout) 161c72fcc34Sopenharmony_ci{ 162c72fcc34Sopenharmony_ci char fn[PATH_SIZE]; 163c72fcc34Sopenharmony_ci int err; 164c72fcc34Sopenharmony_ci 165c72fcc34Sopenharmony_ci state_lock_file(fn, sizeof(fn)); 166c72fcc34Sopenharmony_ci err = state_lock_(fn, 1, timeout, -1); 167c72fcc34Sopenharmony_ci if (err < 0) 168c72fcc34Sopenharmony_ci error("file %s lock error: %s", file, strerror(-err)); 169c72fcc34Sopenharmony_ci return err; 170c72fcc34Sopenharmony_ci} 171c72fcc34Sopenharmony_ci 172c72fcc34Sopenharmony_ciint state_unlock(int _fd, const char *file) 173c72fcc34Sopenharmony_ci{ 174c72fcc34Sopenharmony_ci char fn[PATH_SIZE]; 175c72fcc34Sopenharmony_ci int err; 176c72fcc34Sopenharmony_ci 177c72fcc34Sopenharmony_ci state_lock_file(fn, sizeof(fn)); 178c72fcc34Sopenharmony_ci err = state_lock_(fn, 0, 10, _fd); 179c72fcc34Sopenharmony_ci if (err < 0) 180c72fcc34Sopenharmony_ci error("file %s unlock error: %s", file, strerror(-err)); 181c72fcc34Sopenharmony_ci return err; 182c72fcc34Sopenharmony_ci} 183c72fcc34Sopenharmony_ci 184c72fcc34Sopenharmony_cistatic void card_lock_file(char *buf, size_t buflen, int card_number) 185c72fcc34Sopenharmony_ci{ 186c72fcc34Sopenharmony_ci snprintf(buf, buflen, "%s/card%i.lock", lockpath, card_number); 187c72fcc34Sopenharmony_ci} 188c72fcc34Sopenharmony_ci 189c72fcc34Sopenharmony_ciint card_lock(int card_number, int timeout) 190c72fcc34Sopenharmony_ci{ 191c72fcc34Sopenharmony_ci char fn[PATH_SIZE]; 192c72fcc34Sopenharmony_ci int err; 193c72fcc34Sopenharmony_ci 194c72fcc34Sopenharmony_ci card_lock_file(fn, sizeof(fn), card_number); 195c72fcc34Sopenharmony_ci err = state_lock_(fn, 1, timeout, -1); 196c72fcc34Sopenharmony_ci if (err < 0) 197c72fcc34Sopenharmony_ci error("card %d lock error: %s", card_number, strerror(-err)); 198c72fcc34Sopenharmony_ci return err; 199c72fcc34Sopenharmony_ci} 200c72fcc34Sopenharmony_ci 201c72fcc34Sopenharmony_ciint card_unlock(int _fd, int card_number) 202c72fcc34Sopenharmony_ci{ 203c72fcc34Sopenharmony_ci char fn[PATH_SIZE]; 204c72fcc34Sopenharmony_ci int err; 205c72fcc34Sopenharmony_ci 206c72fcc34Sopenharmony_ci card_lock_file(fn, sizeof(fn), card_number); 207c72fcc34Sopenharmony_ci err = state_lock_(fn, 0, 10, _fd); 208c72fcc34Sopenharmony_ci if (err < 0) 209c72fcc34Sopenharmony_ci error("card %d unlock error: %s", card_number, strerror(-err)); 210c72fcc34Sopenharmony_ci return err; 211c72fcc34Sopenharmony_ci} 212