4 * @brief Functions, used by both Linux and Lynx during installation.
6 * @author Copyright (C) 2009 CERN. Yury GEORGIEVSKIY <ygeorgie@cern.ch>
8 * @date Created on 14/02/2009
11 #define _GNU_SOURCE /* asprintf rocks */
15 #include <sys/types.h>
18 #include <sys/utsname.h> /* for uname */
22 #include <general_both.h>
25 #define RED_CLR "\033[0;31m"
26 #define WHITE_CLR "\033[1;37m"
27 #define END_CLR "\033[m"
29 static char *default_xml_config_file(void);
31 void display_version(char *name
)
33 static char *version
= "0.1";
34 printf("Versioin %s\n", version
);
40 * @param name -- you'll never know
42 void display_usage(char *name
)
44 printf("Usage: %s <*.xml> [-] [-v | -h] [ -fall | -fexclude ] \\\n"
45 " [-s]<name> -o\"option string\" -n<noden> ... \\\n"
46 " [-s]<name> -o\"option string\" -n<noden> ...\n\n"
47 "Installing the driver based on it's xml description.\n"
49 " <*.xml> %soptional%s\n"
50 " Where to take driver description from.\n"
51 " Default is %s/etc/drivers.xml%s\n\n"
53 " Read the XML file from standard input\n\n"
54 " -v -- display version\n\n"
55 " -h -- show help\n\n"
56 " <name> %soptional%s\n"
57 " Specify driver to be installed in a Normal"
59 " -s<name> %soptional%s\n"
60 " Special installation mode request. All driver\n"
61 " parameters will be passed to the driver during\n"
62 " dr_install(), but not during cdv_install() call.\n"
63 " Valid %s[ONLY]%s for Linux device drivers.\n\n"
64 " -o\"str\" %soptional%s\n"
65 " Option string to pass to the driver during\n"
66 " init_module() system call\n"
67 " Valid %s[ONLY]%s for Linux device drivers.\n\n"
68 " -n<noden> %soptional%s\n"
69 " Extra symbolic link node name to create.\n"
70 " Normally, DEF_CLIENT_CTXT_AM (16 as of 07.2009)\n"
71 " nodes are created with names\n"
72 " <mod_name>1 .. <mod_name>16\n\n"
73 " In this case -- DEF_CLIENT_CTXT_AM symlinks with\n"
74 " names <noden>1 .. <noden>16 will also be created\n"
75 " and will point to corresponding module nodes\n"
76 " <mod_name>1 .. <mod_name>16.\n\n"
77 " If there are already <noden>1 .. <noden>16 - then\n"
78 " <noden>17 .. <noden>32 will be created.\n"
79 " They will point to corresponding module nodes\n"
80 " <mod_name>1 .. <mod_name>16.\n\n"
82 " -fall %soptional%s\n"
83 " Tells to install all the drivers found in the xml\n"
85 " Multiple -s <name> params can present in the command\n"
86 " line to specify the drivers, that should be istalled\n"
87 " using special installation mode.\n\n"
88 " -fexclude %soptional%s\n"
89 " Will install all the drivers, exept one provided\n"
90 " in the command line.\n\n"
91 " -foptions %soptional [for driverGen only]%s\n"
92 " Options from .xml file should be taken instead of\n"
93 " one, provided in the command line.\n\n"
96 " Will install everything from `uname -n`.xml\n"
98 " [2] instprog my.xml\n"
99 " Install everything from my.xml config file\n\n"
100 " [3] instprog -fall CTRP -nctr -o\"option for CTR\" \\\n"
101 " -sMIL1553 VD80 -o\"vd80 option\"\n"
102 " Install everything from `uname -n`.xml\n"
103 " MIL1553 goes through special installation.\n"
104 " Pass the option for CTRP driver.\n"
105 " Create symlink nodes for CTRP driver.\n"
106 " Pass the option for VD80.\n\n"
107 " [4] instprog my.xml -sMIL1553 VD80 -sCTRP\n"
108 " Install only MIL1553 and VD80 from my.xml\n"
109 " MIL1553 -- special one.\n"
110 " VD80 -- uses normal installation schema.\n"
111 " CTRP -- special installation request.\n\n"
112 " [5] instprog -fexclude MIL1553 VD80 CTRV\n"
113 " Install everything, exept MIL1553, VD80 and CTRV\n"
114 " drivers from `uname -n`.xml config file.\n"
115 " Pass the option for VD80 driver.\n\n",
116 basename(name
), WHITE_CLR
, END_CLR
, WHITE_CLR
, END_CLR
,
117 WHITE_CLR
, END_CLR
, WHITE_CLR
, END_CLR
, WHITE_CLR
, END_CLR
,
118 WHITE_CLR
, END_CLR
, WHITE_CLR
, END_CLR
, WHITE_CLR
, END_CLR
,
119 WHITE_CLR
, END_CLR
, WHITE_CLR
, END_CLR
, WHITE_CLR
, END_CLR
,
124 * @brief Command line arg parser
126 * @param argc -- arg amount
127 * @param argv -- arg value
128 * @param flg -- I_ALL -- install all drivers found in the .xml
129 * I_CHOSEN -- install only drivers, that are provided in the
131 * I_EXCLUDED -- install all drivers, exept one provided in the
132 * command line (--exclude option)
133 * @param cf -- .xml config file name goes here. Should be freed by the
135 * @param head -- list head to hold all driver descriptions
136 * (of type struct drvrd)
138 * Returned massive holds driver names that user provded in the command line.
140 * list, struct drvrd.dopt and struct drvrd.dname should be freed afterwards!
142 * @return driver description list capacity (head param)
143 * @return -ECANCELED -- if just help message or version were displayed
144 * @return -ENOMEM -- can't allocate memory for driver description table
146 int parse_prog_args(int argc
, char* argv
[], int *flg
, char **cf
,
147 struct list_head
*head
)
152 INIT_LIST_HEAD(head
);
154 *flg
= 0; /* nothing set yet */
155 /* Scan params of the command line */
156 while ( (opt
= getopt(argc
, argv
, "-s:f:o:n:hv")) != EOF
) {
158 case 's': /* special installation mode (Linux only)
159 All driver parameters are passed to the
160 driver during dr_install(), but not during
161 cdv_install() call, which will not be
163 ddp
= calloc(1, sizeof(*ddp
));
166 asprintf(&ddp
->dname
, "%s", optarg
);
168 list_add_tail(&ddp
->list
, head
);
169 if (!*flg
) /* not set yet */
172 case 'f': /* force flags */
173 if (*flg
) /* already set */
175 if (!strcmp(optarg
, "exclude"))
177 if (!strcmp(optarg
, "all"))
181 case 'o': /* Driver option string (Linux only) */
183 asprintf(&ddp
->dopt
, "%s", optarg
);
185 case 'n': /* symbolik link node name */
187 asprintf(&ddp
->slnn
, "%s", optarg
);
189 case 'v': /* current version */
190 display_version(argv
[0]);
191 return -ECANCELED
; /* Operation canceled */
193 display_usage(argv
[0]);
194 return -ECANCELED
; /* Operation canceled */
198 * Although not documented, in Lynx when we pass '-'
199 * alone as an argument, getopt(3) returns '-' as the
200 * option character instead of returning it as a
201 * non-option argument, which is the sane thing.
206 #else /* __linux__ */
207 case 1: /* Non-option argument.
208 Can be either xml config file name or driver name */
210 if (strstr(optarg
, ".xml")) {
212 asprintf(cf
, "%s", optarg
);
214 } else if (!strcmp(optarg
, "-")) {
218 ddp
= calloc(1, sizeof(*ddp
));
221 asprintf(&ddp
->dname
, "%s", optarg
);
222 list_add_tail(&ddp
->list
, head
);
223 if (!*flg
) /* not set yet */
227 printf("Unsupported command line argument!\n");
232 if (!*flg
) *flg
= I_ALL
; /* no drivers in the command line */
233 if (!*cf
) /* no .xml file provided in the command line. Set default */
234 *cf
= default_xml_config_file();
236 return list_capacity(head
);
243 * @brief Creates device node symlinks
245 * @param dnames -- dev nodes to create symlinks for
246 * @param slname -- symlink name
247 * @param dna -- number of links to create
249 * Symlinks with names <slname>1 .. <slname>dna will be created.
251 * If there are already <slname>1 .. <slname>dna -- then
252 * <slname>dna+1 .. <slname>2*dna will be created. They will point to
253 * corresponding module nodes <mod_name>1 .. <mod_name>dna.
255 * @return how many symlinks created
257 static void create_node_symlinks(char **dnames
, char *slname
, int dna
)
260 struct direct
*direntry
;
264 char *nn
= NULL
; /* node name */
266 getcwd(cwd
, sizeof(cwd
)); /* save cwd */
267 dir
= opendir("/dev");
269 while ( (direntry
= readdir(dir
)) ) {
270 /* check, if symlink names are already there
272 if (strstr(direntry
->d_name
, slname
)) {
273 lstat(direntry
->d_name
, &fstat
);
274 if (S_ISLNK(fstat
.st_mode
))
281 for (i
= 0; i
< dna
; cntr
++, i
++) {
282 asprintf(&nn
, "/dev/%s.%d", slname
, cntr
);
283 symlink(dnames
[i
], nn
);
290 * @brierf Create driver nodes for the user. One node - one user context
292 * @param dmaj -- driver major number
293 * @param dname -- driver name
294 * @param slname -- symbolic link node name. Can be NULL
295 * @param dna -- driver nodes amount to create
297 * Will create driver nodes <mod_name>1 .. <mod_name>dna.
298 * First number will be 1, last one will be the @ref dna parameter.
300 * If @ref slname is not NULL -- then @ref dna number of symlinks with names
301 * <slname>1 .. <slname>dna will be created.
303 * If there are already <slname>1 .. <slname>dna -- then
304 * <slname>dna+1 .. <slname>2*dna will be created. They will point to
305 * corresponding module nodes <mod_name>1 .. <mod_name>dna.
307 * @return how many nodes created
309 int create_driver_nodes(int dmaj
, char *dname
, char *slname
, int dna
)
313 char *nn
= NULL
; /* node name */
317 for (cntr
= 1; cntr
<= dna
; cntr
++) { /* buildup device nodes */
318 asprintf(&nn
, "/dev/%s.%d", dname
, cntr
);
319 unlink(nn
); /* if already exist delete it */
320 devn
= makedev(dmaj
, cntr
);
321 if (mknod(nn
, S_IFCHR
| 0666, devn
) < 0) {
322 printf("mknod() failed! Can't create '%s' device node",
327 mas
[cntr
-1] = nn
; /* save node names */
330 if (slname
) /* we should create symlinks */
331 create_node_symlinks(mas
, slname
, dna
);
333 for (cntr
= 0; cntr
< dna
; cntr
++) free(mas
[cntr
]);
338 * @brief Create driver info file in /tmp.
340 * @param name -- Driver Name
341 * @param addr -- Address to save in the info file
343 * @b NOTE Returned pointer should be freed afterwards by the caller.
345 * @return NULL - error
346 * @return info filename - all OK
348 inline char *create_info_file(char *name
, void *addr
)
356 asprintf(&ifn
, "/tmp/%s_XXXXXX", name
);
358 write(fd
, &addr
, sizeof(void*)); /* safe info table address */
365 * @brief Creates option string (provided by the user) to pass it to
366 * init_module() system call
368 * @param argc -- command line arg amount
369 * @param argv -- command line arguments
370 * @param uarg -- index of the first user-defined parameter
372 * Taken from mod-init-tools.
373 * Returned pointer should be freed afterwards by the caller!
375 * @return created option string (can be an empty one "") - if OK
376 * @return NULL - if failed
378 __attribute__ ((unused
)) char *create_usr_option_string(int argc
,
379 char *argv
[], int uarg
)
381 char *options
= strdup("");
385 fprintf(stderr
, "%s() can't allocate memory: %s\n",
386 __func__
, strerror(errno
));
391 return options
; /* no user arguments in the command
392 line - return an empty string */
394 for (i
= uarg
; i
< argc
; i
++) {
395 options
= realloc(options
,
396 strlen(options
) + 1 + strlen(argv
[i
]) + 1);
398 fprintf(stderr
, "%s() can't allocate memory: %s\n",
399 __func__
, strerror(errno
));
402 strcat(options
, argv
[i
]);
403 strcat(options
, " ");
410 * @brief Generates default .xml config file
414 * Naming convention for default config file is "/etc/drivers.xml"
415 * This comes from the Makefile for building DSCs from the database,
417 * /acc/src/dsc/co/Make.dsc
419 * @b NOTE Name should be freed by the caller afterwards.
421 * @return XML config file name
423 char *default_xml_config_file(void)
427 asprintf(&xmlnm
, "/etc/drivers.xml");
432 * @brief free all driver description resources
434 * @param head -- driver description list head
436 void free_drvrd(struct list_head
*head
)
439 struct list_head
*lst
, *safe
;
441 list_for_each_safe(lst
, safe
, head
) {
442 el
= list_entry(lst
, struct drvrd
, list
);
443 if (el
->dopt
) free(el
->dopt
);
444 if (el
->slnn
) free(el
->slnn
);
445 if (el
->dname
) free(el
->dname
);
452 * @brief Get command line driver description, if any
454 * @param head -- driver description list head
455 * @param dnm -- driver name from .xml file
457 * @return command line driver description, or NULL.
459 struct drvrd
*cmd_line_dd(struct list_head
*head
, char *dnm
)
463 list_for_each_entry(dd
, head
, list
)
464 if (!(strcmp(dd
->dname
, dnm
)))
470 * @brief Search for the .ko in cwd, and if it is a symlink -- follows it.
472 * @param path -- result goes here
473 * @param dn -- driver name. Exactly as in the DB.
475 * [1] If driver is delivered -- then we should have a .ko object files in cwd.
478 * [2] If drvier is compiled locally and is @b not delivered -- then we can have
479 * N .ko objects, which are symlinks. They contain 'uname -r' in their
480 * names. Ex: vd80.2.6.29.4-rt15.ko.
481 * It points to the real .ko object of the format as in [1]
483 * Function will detect the type, and if it's a symlink, will follow it.
485 * path should be freed afterwards by the caller.
487 * @return 0 -- all OK, can proceed with installation
488 * @return -1 -- *.ko filename ambiguity, means that there are names with
489 * 'uname -r' part in them, and there are one without it.
490 * @return -2 -- can't read a symbolic link
491 * @return -3 -- .ko doesn't exist
493 int drvr_pathname(char **path
, char *dn
)
495 DIR *dir
= opendir("./");
496 struct direct
*direntry
;
497 char *kosl
; /* .ko symlink filename */
498 char *kof
; /* .ko filename */
501 char slbuf
[256] = { 0 };
502 int lko
= 0, rko
= 0; /* .ko counters
504 rko - remote .ko file (symlink) */
507 /* note, that here we ensure lowercase drivername */
508 asprintf(&kosl
, "%s.%s.ko", str2lower(dn
), buf
.release
);
509 asprintf(&kof
, "%s.ko", str2lower(dn
));
511 /* *.ko && *.`uname -r`.ko can't co-exist together in one dir */
512 while ( (direntry
= readdir(dir
)) ) {
513 if (!strcmp(direntry
->d_name
, kof
))
515 if (!strcmp(direntry
->d_name
, kosl
))
521 printf("%sCan't file neither %s nor %s\n"
522 " .ko doesn't exist\n",
528 /* we should have at least one of them */
530 printf("%sAmbiguous *.ko filenames detected.\n"
531 " [%s] and [%s] can't co-exist.\n",
533 rc
= -1; /* both *.ko and *.`uname -r`.ko detected */
538 asprintf(path
, "./%s", kof
);
543 /* we have a symlink */
544 if (readlink(kosl
, slbuf
, sizeof(slbuf
)-1) == -1) {
545 printf("%sCan't resolve %s symlink\n", ERR_MSG
, kosl
);
549 asprintf(path
, "%s", slbuf
);
552 if (kosl
) free(kosl
);