1 /* dssi_list_plugins.c
2  *
3  * Written by Sean Bolton, with inspiration from Richard Furse's listplugins
4  * from the LADSPA SDK.
5  *
6  * This program is in the public domain.
7  *
8  * $Id: dssi_list_plugins.c,v 1.1 2010/06/27 19:30:09 smbolton Exp $
9  */
10 
11 #include <stdlib.h>
12 #include <stdio.h>
13 #include <string.h>
14 #include <sys/types.h>
15 #include <dirent.h>
16 #include <errno.h>
17 #include <sys/stat.h>
18 #include <dlfcn.h>
19 
20 #include <ladspa.h>
21 #include "dssi.h"
22 
23 struct duplicate_list {
24     struct duplicate_list *next;
25     const char *item;
26 };
27 
28 struct duplicate_list *dup_list = NULL;
29 
30 int verbose = 0;
31 
32 void
check_for_duplicates(const char * filename)33 check_for_duplicates(const char *filename)
34 {
35     struct duplicate_list *d;
36 
37     for (d = dup_list; d; d = d->next) {
38         if (!strcmp(d->item, filename)) {
39             printf("-- warning: shared library '%s' appears more than once on DSSI_PATH\n", filename);
40             return;
41         }
42     }
43 
44     /* not found, add it to the list */
45     d = (struct duplicate_list *)malloc(sizeof(struct duplicate_list));
46     d->item = strdup(filename);
47     d->next = dup_list;
48     dup_list = d;
49 }
50 
51 void
free_dup_list(void)52 free_dup_list(void)
53 {
54     struct duplicate_list *d;
55 
56     while (dup_list) {
57         d = dup_list;
58         dup_list = d->next;
59         free((char *)d->item);
60         free(d);
61     }
62 }
63 
64 void
list_dssi_plugins(DSSI_Descriptor_Function descriptor_function)65 list_dssi_plugins(DSSI_Descriptor_Function descriptor_function)
66 {
67     int i;
68     const DSSI_Descriptor *descriptor;
69 
70     for (i = 0; (descriptor = descriptor_function(i)); i++)
71         printf("\t%-16s  %s\n", descriptor->LADSPA_Plugin->Label,
72                                 descriptor->LADSPA_Plugin->Name);
73 
74     if (verbose && i == 0)
75         printf("-- odd ... no plugins found within this shared object\n");
76 }
77 
78 void
list_ladspa_plugins(LADSPA_Descriptor_Function descriptor_function)79 list_ladspa_plugins(LADSPA_Descriptor_Function descriptor_function)
80 {
81     int i;
82     const LADSPA_Descriptor *descriptor;
83 
84     for (i = 0; (descriptor = descriptor_function(i)); i++)
85         printf("\t%-16s  (%lu) %s\n", descriptor->Label, descriptor->UniqueID, descriptor->Name);
86 
87     if (verbose && i == 0)
88         printf("-- odd ... no plugins found within this shared object\n");
89 }
90 
91 void
list_directory(char * directory)92 list_directory(char *directory)
93 {
94     int directory_length = strlen(directory);
95     DIR *dir;
96     struct dirent *dirent;
97     char *filename;
98     struct stat statbuf;
99     void *handle;
100     int found = 0;
101 
102     if (directory_length == 0) {
103         if (verbose) printf("-- warning: skipping zero-length element in DSSI_PATH\n");
104         return;
105     }
106     if (directory[directory_length - 1] == '/')
107         directory[directory_length - 1] = 0; /* slash gets added again below */
108 
109     dir = opendir(directory);
110     if (!dir) {
111         if (verbose) printf("-- warning: couldn't open DSSI_PATH directory element '%s'\n", directory);
112         return;
113     }
114 
115     if (verbose) printf("-- scanning directory %s\n", directory);
116 
117     while ((dirent = readdir(dir)) != NULL) {
118 
119         if (!strcmp(dirent->d_name, ".") || !strcmp(dirent->d_name, ".."))
120             continue;
121 
122         filename = malloc(directory_length + strlen(dirent->d_name) + 2);
123         sprintf(filename, "%s/%s", directory, dirent->d_name);
124 
125         if (stat(filename, &statbuf)) {
126             if (verbose)
127                 printf("-- warning: couldn't stat file '%s': %s\n", filename, strerror(errno));
128             free(filename);
129             continue;
130         }
131         if (S_ISDIR(statbuf.st_mode)) { /* silently skip subdirectories */
132             free(filename);
133             continue;
134         }
135 
136         handle = dlopen(filename, RTLD_LAZY);
137         if (handle) {
138             DSSI_Descriptor_Function dssi_descriptor_function;
139             LADSPA_Descriptor_Function ladspa_descriptor_function;
140 
141             if (verbose)
142                 check_for_duplicates(dirent->d_name);
143 
144             dssi_descriptor_function = (DSSI_Descriptor_Function)dlsym(handle, "dssi_descriptor");
145             ladspa_descriptor_function = (LADSPA_Descriptor_Function)dlsym(handle, "ladspa_descriptor");
146 
147             if (dssi_descriptor_function) {
148                 printf("%s\n", filename);
149                 list_dssi_plugins(dssi_descriptor_function);
150                 found++;
151             } else if (ladspa_descriptor_function) {
152                 printf("%s (LADSPA-only)\n", filename);
153                 list_ladspa_plugins(ladspa_descriptor_function);
154             } else {
155                 if (verbose)
156                     printf("-- warning: shared object '%s' is neither a LADSPA nor DSSI plugin\n", filename);
157             }
158             dlclose(handle);
159         } else { /* not a library */
160             int len = strlen(dirent->d_name);
161 
162             if (len > 4 && !strcmp(dirent->d_name + len - 3, ".la")) {  /* libtool *.la file */
163                 /* if (verbose) printf("-- skipping file '%s'\n", filename); */
164             } else
165                 if (verbose)
166                     printf("-- warning: couldn't dlopen file '%s': %s\n", filename, dlerror());
167         }
168         free(filename);
169     }
170 
171     closedir(dir);
172 
173     if (verbose && found == 0)
174         printf("-- odd ... no DSSI plugins were found in this directory\n");
175 }
176 
177 void
usage(const char * program_name)178 usage(const char *program_name)
179 {
180     fprintf(stderr, "usage: %s [-v|--verbose]\n", program_name);
181     fprintf(stderr, "Scan the directories listed in environment variable DSSI_PATH, and list\n");
182     fprintf(stderr, "the DSSI plugins found therein.  Optional arguments:\n");
183     fprintf(stderr, "  -v, --verbose    describe the scan and error conditions more verbosely.\n");
184 
185     exit(1);
186 }
187 
188 int
main(int argc,char * argv[])189 main(int argc, char *argv[])
190 {
191     char *path, *pathtmp, *element;
192 
193     while (argc > 1) {
194         argc--;
195         if (!strcmp(argv[argc], "-v") || !strcmp(argv[argc], "--verbose"))
196             verbose = 1;
197         else
198             usage(argv[0]); /* does not return */
199     }
200 
201     path = getenv("DSSI_PATH");
202     if (!path) {
203         path = "/usr/local/lib/dssi:/usr/lib/dssi";
204         fprintf(stderr, "warning: DSSI_PATH not set, defaulting to '%s'\n", path);
205     }
206 
207     path = strdup(path);
208     pathtmp = path;
209     while ((element = strtok(pathtmp, ":")) != 0) {
210         pathtmp = NULL;
211         list_directory(element);
212     }
213     free(path);
214 
215     free_dup_list();
216 
217     return 0;
218 }
219 
220