comedi_open has file descriptor leak
[comedilib.git] / lib / comedi.c
1 /*
2     lib/comedi.c
3     generic functions
4
5     COMEDILIB - Linux Control and Measurement Device Interface Library
6     Copyright (C) 1997-2001 David A. Schleef <ds@schleef.org>
7
8     This library is free software; you can redistribute it and/or
9     modify it under the terms of the GNU Lesser General Public
10     License as published by the Free Software Foundation, version 2.1
11     of the License.
12
13     This library is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16     Lesser General Public License for more details.
17
18     You should have received a copy of the GNU Lesser General Public
19     License along with this library; if not, write to the Free Software
20     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
21     USA.
22 */
23
24 #include <stdio.h>
25 #include <math.h>
26 #include <stdlib.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <fcntl.h>
30 #include <unistd.h>
31 #include <sys/ioctl.h>
32 #include <errno.h>
33 #include <string.h>
34
35 #include "libinternal.h"
36
37 INTERNAL int __comedi_init=0;
38
39 INTERNAL void initialize(void)
40 {
41         char *s;
42
43         __comedi_init=1;
44
45         if( (s=getenv("COMEDILIB_LOGLEVEL")) ){
46                 __comedi_loglevel=strtol(s,NULL,0);
47                 COMEDILIB_DEBUG(3,"setting loglevel to %d\n",__comedi_loglevel);
48         }
49 }
50
51 EXPORT_ALIAS_DEFAULT(_comedi_open,comedi_open,0.7.18);
52 comedi_t* _comedi_open(const char *fn)
53 {
54         comedi_t *it;
55
56         if(!__comedi_init)
57                 initialize();
58
59         if(!(it=malloc(sizeof(comedi_t))))
60                 goto cleanup;
61         memset(it,0,sizeof(comedi_t));
62
63         if((it->fd=open(fn,O_RDWR))<0){
64                 libc_error();
65                 goto cleanup;
66         }
67
68         if(comedi_ioctl(it->fd, COMEDI_DEVINFO, &it->devinfo) < 0)
69                 goto cleanup;
70
71         it->n_subdevices=it->devinfo.n_subdevs;
72
73         if(get_subdevices(it) < 0)
74                 goto cleanup;
75
76         it->magic=COMEDILIB_MAGIC;
77
78         return it;
79 cleanup:
80         if(it) {
81                 /* As long as get_subdevices is the last action above,
82                    it->subdevices should not need any cleanup, since
83                    get_subdevices should have done the cleanup already */
84                 if (it->fd >= 0)
85                         close(it->fd);
86                 free(it);
87         }
88
89         return NULL;
90 }
91
92 EXPORT_ALIAS_DEFAULT(_comedi_close,comedi_close,0.7.18);
93 int _comedi_close(comedi_t *it)
94 {
95         subdevice *s;
96         int i,j;
97
98         if(!valid_dev(it))
99                 return -1;
100         it->magic=0;
101
102         for(i=0;i<it->n_subdevices;i++){
103                 s=it->subdevices+i;
104                 if(s->type==COMEDI_SUBD_UNUSED)
105                         continue;
106
107                 if(s->subd_flags&SDF_FLAGS){
108                         free(s->flags_list);
109                 }
110                 if(s->subd_flags&SDF_MAXDATA){
111                         free(s->maxdata_list);
112                 }
113                 if(s->subd_flags&SDF_RANGETYPE){
114                         free(s->range_type_list);
115                         for(j=0;j<s->n_chan;j++)
116                                 free(s->rangeinfo_list[j]);
117                         free(s->rangeinfo_list);
118                 }else{
119                         free(s->rangeinfo);
120                 }
121                 if(s->cmd_mask)free(s->cmd_mask);
122                 if(s->cmd_timed)free(s->cmd_timed);
123         }
124         if(it->subdevices){
125                 free(it->subdevices);
126         }
127         close(it->fd);
128         free(it);
129         return 0;
130 }
131
132 EXPORT_ALIAS_DEFAULT(_comedi_cancel,comedi_cancel,0.7.18);
133 int _comedi_cancel(comedi_t *it,unsigned int subdevice)
134 {
135         if(!valid_dev(it)) return -1;
136         return comedi_ioctl(it->fd, COMEDI_CANCEL, (void*)(unsigned long)subdevice);
137 }
138
139 EXPORT_ALIAS_DEFAULT(_comedi_poll,comedi_poll,0.7.18);
140 int _comedi_poll(comedi_t *it,unsigned int subdevice)
141 {
142         if(!valid_dev(it)) return -1;
143         return comedi_ioctl(it->fd, COMEDI_POLL, (void*)(unsigned long)subdevice);
144 }
145
146 EXPORT_ALIAS_DEFAULT(_comedi_fileno,comedi_fileno,0.7.18);
147 int _comedi_fileno(comedi_t *it)
148 {
149         if(!valid_dev(it)) return -1;
150         return it->fd;
151 }
152
153 EXPORT_ALIAS_DEFAULT(_comedi_trigger,comedi_trigger,0.7.18);
154 int _comedi_trigger(comedi_t *it,comedi_trig *t)
155 {
156         if(!valid_dev(it) || !t)
157                 return -1;
158
159         return comedi_ioctl(it->fd, COMEDI_TRIG, t);
160 }
161
162 EXPORT_ALIAS_DEFAULT(_comedi_command,comedi_command,0.7.18);
163 int _comedi_command(comedi_t *it,comedi_cmd *t)
164 {
165         int ret;
166         if(!valid_dev(it)) return -1;
167         ret = comedi_ioctl(it->fd, COMEDI_CMD, t);
168         __comedi_errno = errno;
169         switch(__comedi_errno){
170         case EIO:
171                 __comedi_errno = ECMDNOTSUPP;
172                 break;
173         }
174         return ret;
175 }
176
177 EXPORT_ALIAS_DEFAULT(_comedi_command_test,comedi_command_test,0.7.18);
178 int _comedi_command_test(comedi_t *it,comedi_cmd *t)
179 {
180         int ret;
181         if(!valid_dev(it)) return -1;
182         ret = comedi_ioctl(it->fd, COMEDI_CMDTEST, t);
183         __comedi_errno = errno;
184         switch(__comedi_errno){
185         case EIO:
186                 __comedi_errno = ECMDNOTSUPP;
187                 break;
188         }
189         return ret;
190 }
191
192 EXPORT_ALIAS_DEFAULT(_comedi_do_insnlist,comedi_do_insnlist,0.7.18);
193 int _comedi_do_insnlist(comedi_t *it,comedi_insnlist *il)
194 {
195         int ret;
196         if(!valid_dev(it)) return -1;
197         ret = comedi_ioctl(it->fd, COMEDI_INSNLIST, il);
198         __comedi_errno = errno;
199         return ret;
200 }
201
202 EXPORT_ALIAS_DEFAULT(_comedi_do_insn,comedi_do_insn,0.7.18);
203 int _comedi_do_insn(comedi_t *it,comedi_insn *insn)
204 {
205         if(!valid_dev(it)) return -1;
206         if(it->has_insn_ioctl){
207                 return comedi_ioctl(it->fd, COMEDI_INSN, insn);
208         }else{
209                 comedi_insnlist il;
210                 int ret;
211
212                 il.n_insns = 1;
213                 il.insns = insn;
214
215                 ret = comedi_ioctl(it->fd, COMEDI_INSNLIST, &il);
216
217                 if(ret<0)return ret;
218                 return insn->n;
219         }
220 }
221
222 EXPORT_ALIAS_DEFAULT(_comedi_lock,comedi_lock,0.7.18);
223 int _comedi_lock(comedi_t *it,unsigned int subdevice)
224 {
225         if(!valid_dev(it)) return -1;
226         return comedi_ioctl(it->fd, COMEDI_LOCK, (void*)(unsigned long)subdevice);
227 }
228
229 EXPORT_ALIAS_DEFAULT(_comedi_unlock,comedi_unlock,0.7.18);
230 int _comedi_unlock(comedi_t *it,unsigned int subdevice)
231 {
232         if(!valid_dev(it)) return -1;
233         return comedi_ioctl(it->fd, COMEDI_UNLOCK, (void*)(unsigned long)subdevice);
234 }
235