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