aaf99fb21f1143fce54a7d8dedb1a1df0db65eb3
[multipath-tools/.git] / libmultipath / propsel.c
1 /*
2  * Copyright (c) 2004, 2005 Christophe Varoqui
3  * Copyright (c) 2005 Benjamin Marzinski, Redhat
4  * Copyright (c) 2005 Kiyoshi Ueda, NEC
5  */
6 #include <stdio.h>
7
8 #include "checkers.h"
9 #include "memory.h"
10 #include "vector.h"
11 #include "structs.h"
12 #include "config.h"
13 #include "debug.h"
14 #include "pgpolicies.h"
15 #include "alias.h"
16 #include "defaults.h"
17 #include "devmapper.h"
18 #include "prio.h"
19 #include "discovery.h"
20 #include "dict.h"
21 #include "prioritizers/alua_rtpg.h"
22 #include <inttypes.h>
23
24 pgpolicyfn *pgpolicies[] = {
25         NULL,
26         one_path_per_group,
27         one_group,
28         group_by_serial,
29         group_by_prio,
30         group_by_node_name
31 };
32
33 #define do_set(var, src, dest, msg)                                     \
34 do {                                                                    \
35         if (src && src->var) {                                          \
36                 dest = src->var;                                        \
37                 origin = msg;                                           \
38                 goto out;                                               \
39         }                                                               \
40 } while(0)
41 #define do_default(dest, value)                                         \
42 do {                                                                    \
43         dest = value;                                                   \
44         origin = "(internal default)";                                  \
45 } while(0)
46
47 #define mp_set_mpe(var)                                                 \
48 do_set(var, mp->mpe, mp->var, "(LUN setting)")
49 #define mp_set_hwe(var)                                                 \
50 do_set(var, mp->hwe, mp->var, "(controller setting)")
51 #define mp_set_ovr(var)                                                 \
52 do_set(var, conf->overrides, mp->var, "(overrides setting)")
53 #define mp_set_conf(var)                                                \
54 do_set(var, conf, mp->var, "(config file default)")
55 #define mp_set_default(var, value)                                      \
56 do_default(mp->var, value)
57
58 #define pp_set_mpe(var)                                                 \
59 do_set(var, mpe, pp->var, "(LUN setting)")
60 #define pp_set_hwe(var)                                                 \
61 do_set(var, pp->hwe, pp->var, "(controller setting)")
62 #define pp_set_conf(var)                                                \
63 do_set(var, conf, pp->var, "(config file default)")
64 #define pp_set_ovr(var)                                                 \
65 do_set(var, conf->overrides, pp->var, "(overrides setting)")
66 #define pp_set_default(var, value)                                      \
67 do_default(pp->var, value)
68
69 #define do_attr_set(var, src, shift, msg)                               \
70 do {                                                                    \
71         if (src && (src->attribute_flags & (1 << shift))) {             \
72                 mp->attribute_flags |= (1 << shift);                    \
73                 mp->var = src->var;                                     \
74                 origin = msg;                                           \
75                 goto out;                                               \
76         }                                                               \
77 } while(0)
78
79 #define set_attr_mpe(var, shift)                                        \
80 do_attr_set(var, mp->mpe, shift, "(LUN setting)")
81 #define set_attr_conf(var, shift)                                       \
82 do_attr_set(var, conf, shift, "(config file default)")
83
84 extern int
85 select_mode (struct config *conf, struct multipath *mp)
86 {
87         char *origin;
88
89         set_attr_mpe(mode, ATTR_MODE);
90         set_attr_conf(mode, ATTR_MODE);
91         mp->attribute_flags &= ~(1 << ATTR_MODE);
92         return 0;
93 out:
94         condlog(3, "%s: mode = 0%o %s", mp->alias, mp->mode, origin);
95         return 0;
96 }
97
98 extern int
99 select_uid (struct config *conf, struct multipath *mp)
100 {
101         char *origin;
102
103         set_attr_mpe(uid, ATTR_UID);
104         set_attr_conf(uid, ATTR_UID);
105         mp->attribute_flags &= ~(1 << ATTR_UID);
106         return 0;
107 out:
108         condlog(3, "%s: uid = 0%o %s", mp->alias, mp->uid, origin);
109         return 0;
110 }
111
112 extern int
113 select_gid (struct config *conf, struct multipath *mp)
114 {
115         char *origin;
116
117         set_attr_mpe(gid, ATTR_GID);
118         set_attr_conf(gid, ATTR_GID);
119         mp->attribute_flags &= ~(1 << ATTR_GID);
120         return 0;
121 out:
122         condlog(3, "%s: gid = 0%o %s", mp->alias, mp->gid, origin);
123         return 0;
124 }
125
126 /*
127  * selectors :
128  * traverse the configuration layers from most specific to most generic
129  * stop at first explicit setting found
130  */
131 extern int
132 select_rr_weight (struct config *conf, struct multipath * mp)
133 {
134         char *origin, buff[13];
135
136         mp_set_mpe(rr_weight);
137         mp_set_ovr(rr_weight);
138         mp_set_hwe(rr_weight);
139         mp_set_conf(rr_weight);
140         mp_set_default(rr_weight, DEFAULT_RR_WEIGHT);
141 out:
142         print_rr_weight(buff, 13, &mp->rr_weight);
143         condlog(3, "%s: rr_weight = %s %s", mp->alias, buff, origin);
144         return 0;
145 }
146
147 extern int
148 select_pgfailback (struct config *conf, struct multipath * mp)
149 {
150         char *origin, buff[13];
151
152         mp_set_mpe(pgfailback);
153         mp_set_ovr(pgfailback);
154         mp_set_hwe(pgfailback);
155         mp_set_conf(pgfailback);
156         mp_set_default(pgfailback, DEFAULT_FAILBACK);
157 out:
158         print_pgfailback(buff, 13, &mp->pgfailback);
159         condlog(3, "%s: failback = %s %s", mp->alias, buff, origin);
160         return 0;
161 }
162
163 extern int
164 select_pgpolicy (struct config *conf, struct multipath * mp)
165 {
166         char *origin, buff[POLICY_NAME_SIZE];
167
168         if (conf->pgpolicy_flag > 0) {
169                 mp->pgpolicy = conf->pgpolicy_flag;
170                 origin = "(cmd line flag)";
171                 goto out;
172         }
173         mp_set_mpe(pgpolicy);
174         mp_set_ovr(pgpolicy);
175         mp_set_hwe(pgpolicy);
176         mp_set_conf(pgpolicy);
177         mp_set_default(pgpolicy, DEFAULT_PGPOLICY);
178 out:
179         mp->pgpolicyfn = pgpolicies[mp->pgpolicy];
180         get_pgpolicy_name(buff, POLICY_NAME_SIZE, mp->pgpolicy);
181         condlog(3, "%s: path_grouping_policy = %s %s", mp->alias, buff, origin);
182         return 0;
183 }
184
185 extern int
186 select_selector (struct config *conf, struct multipath * mp)
187 {
188         char *origin;
189
190         mp_set_mpe(selector);
191         mp_set_ovr(selector);
192         mp_set_hwe(selector);
193         mp_set_conf(selector);
194         mp_set_default(selector, DEFAULT_SELECTOR);
195 out:
196         mp->selector = STRDUP(mp->selector);
197         condlog(3, "%s: path_selector = \"%s\" %s", mp->alias, mp->selector,
198                 origin);
199         return 0;
200 }
201
202 static void
203 select_alias_prefix (struct config *conf, struct multipath * mp)
204 {
205         char *origin;
206
207         mp_set_ovr(alias_prefix);
208         mp_set_hwe(alias_prefix);
209         mp_set_conf(alias_prefix);
210         mp_set_default(alias_prefix, DEFAULT_ALIAS_PREFIX);
211 out:
212         condlog(3, "%s: alias_prefix = %s %s", mp->wwid, mp->alias_prefix,
213                 origin);
214 }
215
216 static int
217 want_user_friendly_names(struct config *conf, struct multipath * mp)
218 {
219
220         char *origin;
221         int user_friendly_names;
222
223         do_set(user_friendly_names, mp->mpe, user_friendly_names,
224                "(LUN setting)");
225         do_set(user_friendly_names, conf->overrides, user_friendly_names,
226                "(overrides setting)");
227         do_set(user_friendly_names, mp->hwe, user_friendly_names,
228                "(controller setting)");
229         do_set(user_friendly_names, conf, user_friendly_names,
230                "(config file setting)");
231         do_default(user_friendly_names, DEFAULT_USER_FRIENDLY_NAMES);
232 out:
233         condlog(3, "%s: user_friendly_names = %s %s", mp->wwid,
234                 (user_friendly_names == USER_FRIENDLY_NAMES_ON)? "yes" : "no",
235                 origin);
236         return (user_friendly_names == USER_FRIENDLY_NAMES_ON);
237 }
238
239 extern int
240 select_alias (struct config *conf, struct multipath * mp)
241 {
242         char *origin = NULL;
243
244         if (mp->mpe && mp->mpe->alias) {
245                 mp->alias = STRDUP(mp->mpe->alias);
246                 origin = "(LUN setting)";
247                 goto out;
248         }
249
250         mp->alias = NULL;
251         if (!want_user_friendly_names(conf, mp))
252                 goto out;
253
254         select_alias_prefix(conf, mp);
255
256         if (strlen(mp->alias_old) > 0) {
257                 mp->alias = use_existing_alias(mp->wwid, conf->bindings_file,
258                                 mp->alias_old, mp->alias_prefix,
259                                 conf->bindings_read_only);
260                 memset (mp->alias_old, 0, WWID_SIZE);
261                 origin = "(using existing alias)";
262         }
263
264         if (mp->alias == NULL) {
265                 mp->alias = get_user_friendly_alias(mp->wwid,
266                                 conf->bindings_file, mp->alias_prefix, conf->bindings_read_only);
267                 origin = "(user_friendly_name)";
268         }
269 out:
270         if (mp->alias == NULL) {
271                 mp->alias = STRDUP(mp->wwid);
272                 origin = "(default to wwid)";
273         }
274         if (mp->alias)
275                 condlog(3, "%s: alias = %s %s", mp->wwid, mp->alias, origin);
276         return mp->alias ? 0 : 1;
277 }
278
279 extern int
280 select_features (struct config *conf, struct multipath * mp)
281 {
282         char *origin;
283
284         mp_set_mpe(features);
285         mp_set_ovr(features);
286         mp_set_hwe(features);
287         mp_set_conf(features);
288         mp_set_default(features, DEFAULT_FEATURES);
289 out:
290         mp->features = STRDUP(mp->features);
291         condlog(3, "%s: features = \"%s\" %s", mp->alias, mp->features, origin);
292
293         if (strstr(mp->features, "queue_if_no_path")) {
294                 if (mp->no_path_retry == NO_PATH_RETRY_UNDEF)
295                         mp->no_path_retry = NO_PATH_RETRY_QUEUE;
296                 else if (mp->no_path_retry == NO_PATH_RETRY_FAIL) {
297                         condlog(1, "%s: config error, overriding 'no_path_retry' value",
298                                 mp->alias);
299                         mp->no_path_retry = NO_PATH_RETRY_QUEUE;
300                 }
301         }
302         return 0;
303 }
304
305 extern int
306 select_hwhandler (struct config *conf, struct multipath * mp)
307 {
308         char *origin;
309
310         mp_set_hwe(hwhandler);
311         mp_set_conf(hwhandler);
312         mp_set_default(hwhandler, DEFAULT_HWHANDLER);
313 out:
314         mp->hwhandler = STRDUP(mp->hwhandler);
315         condlog(3, "%s: hardware_handler = \"%s\" %s", mp->alias, mp->hwhandler,
316                 origin);
317         return 0;
318 }
319
320 extern int
321 select_checker(struct config *conf, struct path *pp)
322 {
323         char *origin, *checker_name;
324         struct checker * c = &pp->checker;
325
326         do_set(checker_name, conf->overrides, checker_name, "(overrides setting)");
327         do_set(checker_name, pp->hwe, checker_name, "(controller setting)");
328         do_set(checker_name, conf, checker_name, "(config file setting)");
329         do_default(checker_name, DEFAULT_CHECKER);
330 out:
331         checker_get(conf->multipath_dir, c, checker_name);
332         condlog(3, "%s: path_checker = %s %s", pp->dev, c->name, origin);
333         if (conf->checker_timeout) {
334                 c->timeout = conf->checker_timeout;
335                 condlog(3, "%s: checker timeout = %u s (config file default)",
336                                 pp->dev, c->timeout);
337         }
338         else if (sysfs_get_timeout(pp, &c->timeout) > 0)
339                 condlog(3, "%s: checker timeout = %u ms (sysfs setting)",
340                                 pp->dev, c->timeout);
341         else {
342                 c->timeout = DEF_TIMEOUT;
343                 condlog(3, "%s: checker timeout = %u ms (internal default)",
344                                 pp->dev, c->timeout);
345         }
346         return 0;
347 }
348
349 extern int
350 select_getuid (struct config *conf, struct path * pp)
351 {
352         char *origin;
353
354         pp_set_ovr(getuid);
355         pp_set_ovr(uid_attribute);
356         pp_set_hwe(getuid);
357         pp_set_hwe(uid_attribute);
358         pp_set_conf(getuid);
359         pp_set_conf(uid_attribute);
360         pp_set_default(uid_attribute, DEFAULT_UID_ATTRIBUTE);
361 out:
362         if (pp->uid_attribute)
363                 condlog(3, "%s: uid_attribute = %s %s", pp->dev,
364                         pp->uid_attribute, origin);
365         else if (pp->getuid)
366                 condlog(3, "%s: getuid = \"%s\" %s", pp->dev, pp->getuid,
367                         origin);
368         return 0;
369 }
370
371 void
372 detect_prio(struct config *conf, struct path * pp)
373 {
374         int ret;
375         struct prio *p = &pp->prio;
376         int tpgs = 0;
377         unsigned int timeout = conf->checker_timeout;
378         char buff[512];
379         char *default_prio = PRIO_ALUA;
380
381         if ((tpgs = get_target_port_group_support(pp->fd, timeout)) <= 0)
382                 return;
383         pp->tpgs = tpgs;
384         ret = get_target_port_group(pp, timeout);
385         if (ret < 0)
386                 return;
387         if (get_asymmetric_access_state(pp->fd, ret, timeout) < 0)
388                 return;
389         if (sysfs_get_asymmetric_access_state(pp, buff, 512) >= 0)
390                 default_prio = PRIO_SYSFS;
391         prio_get(conf->multipath_dir, p, default_prio, DEFAULT_PRIO_ARGS);
392 }
393
394 #define set_prio(dir, src, msg)                                 \
395 do {                                                                    \
396         if (src && src->prio_name) {                                    \
397                 prio_get(dir, p, src->prio_name, src->prio_args);       \
398                 origin = msg;                                           \
399                 goto out;                                               \
400         }                                                               \
401 } while(0)
402
403 extern int
404 select_prio (struct config *conf, struct path * pp)
405 {
406         char *origin;
407         struct mpentry * mpe;
408         struct prio * p = &pp->prio;
409
410         if (pp->detect_prio == DETECT_PRIO_ON) {
411                 detect_prio(conf, pp);
412                 if (prio_selected(p)) {
413                         origin = "(detected setting)";
414                         goto out;
415                 }
416         }
417         mpe = find_mpe(conf->mptable, pp->wwid);
418         set_prio(conf->multipath_dir, mpe, "(LUN setting)");
419         set_prio(conf->multipath_dir, conf->overrides, "(overrides setting)");
420         set_prio(conf->multipath_dir, pp->hwe, "controller setting)");
421         set_prio(conf->multipath_dir, conf, "(config file default)");
422         prio_get(conf->multipath_dir, p, DEFAULT_PRIO, DEFAULT_PRIO_ARGS);
423         origin = "(internal default)";
424 out:
425         /*
426          * fetch tpgs mode for alua, if its not already obtained
427          */
428         if (!strncmp(prio_name(p), PRIO_ALUA, PRIO_NAME_LEN)) {
429                 int tpgs = 0;
430                 unsigned int timeout = conf->checker_timeout;
431
432                 if(!pp->tpgs &&
433                    (tpgs = get_target_port_group_support(pp->fd, timeout)) >= 0)
434                         pp->tpgs = tpgs;
435         }
436         condlog(3, "%s: prio = %s %s", pp->dev, prio_name(p), origin);
437         condlog(3, "%s: prio args = \"%s\" %s", pp->dev, prio_args(p), origin);
438         return 0;
439 }
440
441 extern int
442 select_no_path_retry(struct config *conf, struct multipath *mp)
443 {
444         char *origin = NULL;
445         char buff[12];
446
447         if (mp->flush_on_last_del == FLUSH_IN_PROGRESS) {
448                 condlog(0, "flush_on_last_del in progress");
449                 mp->no_path_retry = NO_PATH_RETRY_FAIL;
450                 return 0;
451         }
452         mp_set_mpe(no_path_retry);
453         mp_set_ovr(no_path_retry);
454         mp_set_hwe(no_path_retry);
455         mp_set_conf(no_path_retry);
456 out:
457         print_no_path_retry(buff, 12, &mp->no_path_retry);
458         if (origin)
459                 condlog(3, "%s: no_path_retry = %s %s", mp->alias, buff,
460                         origin);
461         else if (mp->no_path_retry != NO_PATH_RETRY_UNDEF)
462                 condlog(3, "%s: no_path_retry = %s (inherited setting)",
463                         mp->alias, buff);
464         else
465                 condlog(3, "%s: no_path_retry = undef (internal default)",
466                         mp->alias);
467         return 0;
468 }
469
470 int
471 select_minio_rq (struct config *conf, struct multipath * mp)
472 {
473         char *origin;
474
475         do_set(minio_rq, mp->mpe, mp->minio, "(LUN setting)");
476         do_set(minio_rq, conf->overrides, mp->minio, "(overrides setting)");
477         do_set(minio_rq, mp->hwe, mp->minio, "(controller setting)");
478         do_set(minio_rq, conf, mp->minio, "(config file setting)");
479         do_default(mp->minio, DEFAULT_MINIO_RQ);
480 out:
481         condlog(3, "%s: minio = %i %s", mp->alias, mp->minio, origin);
482         return 0;
483 }
484
485 int
486 select_minio_bio (struct config *conf, struct multipath * mp)
487 {
488         char *origin;
489
490         mp_set_mpe(minio);
491         mp_set_ovr(minio);
492         mp_set_hwe(minio);
493         mp_set_conf(minio);
494         mp_set_default(minio, DEFAULT_MINIO);
495 out:
496         condlog(3, "%s: minio = %i %s", mp->alias, mp->minio, origin);
497         return 0;
498 }
499
500 extern int
501 select_minio (struct config *conf, struct multipath * mp)
502 {
503         unsigned int minv_dmrq[3] = {1, 1, 0};
504
505         if (VERSION_GE(conf->version, minv_dmrq))
506                 return select_minio_rq(conf, mp);
507         else
508                 return select_minio_bio(conf, mp);
509 }
510
511 extern int
512 select_fast_io_fail(struct config *conf, struct multipath *mp)
513 {
514         char *origin, buff[12];
515
516         mp_set_ovr(fast_io_fail);
517         mp_set_hwe(fast_io_fail);
518         mp_set_conf(fast_io_fail);
519         mp_set_default(fast_io_fail, DEFAULT_FAST_IO_FAIL);
520 out:
521         print_fast_io_fail(buff, 12, &mp->fast_io_fail);
522         condlog(3, "%s: fast_io_fail_tmo = %s %s", mp->alias, buff, origin);
523         return 0;
524 }
525
526 extern int
527 select_dev_loss(struct config *conf, struct multipath *mp)
528 {
529         char *origin, buff[12];
530
531         mp_set_ovr(dev_loss);
532         mp_set_hwe(dev_loss);
533         mp_set_conf(dev_loss);
534         mp->dev_loss = 0;
535         return 0;
536 out:
537         print_dev_loss(buff, 12, &mp->dev_loss);
538         condlog(3, "%s: dev_loss_tmo = %s %s", mp->alias, buff, origin);
539         return 0;
540 }
541
542 extern int
543 select_flush_on_last_del(struct config *conf, struct multipath *mp)
544 {
545         char *origin;
546
547         if (mp->flush_on_last_del == FLUSH_IN_PROGRESS)
548                 return 0;
549         mp_set_mpe(flush_on_last_del);
550         mp_set_ovr(flush_on_last_del);
551         mp_set_hwe(flush_on_last_del);
552         mp_set_conf(flush_on_last_del);
553         mp_set_default(flush_on_last_del, DEFAULT_FLUSH);
554 out:
555         condlog(3, "%s: flush_on_last_del = %s %s", mp->alias,
556                 (mp->flush_on_last_del == FLUSH_ENABLED)? "yes" : "no", origin);
557         return 0;
558 }
559
560 extern int
561 select_reservation_key (struct config *conf, struct multipath * mp)
562 {
563         char *origin, buff[12];
564
565         mp_set_mpe(reservation_key);
566         mp_set_conf(reservation_key);
567         mp->reservation_key = NULL;
568         return 0;
569 out:
570         print_reservation_key(buff, 12, &mp->reservation_key);
571         condlog(3, "%s: reservation_key = %s %s", mp->alias, buff, origin);
572         return 0;
573 }
574
575 extern int
576 select_retain_hwhandler (struct config *conf, struct multipath * mp)
577 {
578         char *origin;
579         unsigned int minv_dm_retain[3] = {1, 5, 0};
580
581         if (!VERSION_GE(conf->version, minv_dm_retain)) {
582                 mp->retain_hwhandler = RETAIN_HWHANDLER_OFF;
583                 origin = "(requires kernel version >= 1.5.0)";
584                 goto out;
585         }
586         mp_set_ovr(retain_hwhandler);
587         mp_set_hwe(retain_hwhandler);
588         mp_set_conf(retain_hwhandler);
589         mp_set_default(retain_hwhandler, DEFAULT_RETAIN_HWHANDLER);
590 out:
591         condlog(3, "%s: retain_attached_hw_handler = %s %s", mp->alias,
592                 (mp->retain_hwhandler == RETAIN_HWHANDLER_ON)? "yes" : "no",
593                 origin);
594         return 0;
595 }
596
597 extern int
598 select_detect_prio (struct config *conf, struct path * pp)
599 {
600         char *origin;
601
602         pp_set_ovr(detect_prio);
603         pp_set_hwe(detect_prio);
604         pp_set_conf(detect_prio);
605         pp_set_default(detect_prio, DEFAULT_DETECT_PRIO);
606 out:
607         condlog(3, "%s: detect_prio = %s %s", pp->dev,
608                 (pp->detect_prio == DETECT_PRIO_ON)? "yes" : "no", origin);
609         return 0;
610 }
611
612 extern int
613 select_deferred_remove (struct config *conf, struct multipath *mp)
614 {
615         char *origin;
616
617 #ifndef LIBDM_API_DEFERRED
618         mp->deferred_remove = DEFERRED_REMOVE_OFF;
619         origin = "(not compiled with support)";
620         goto out;
621 #endif
622         if (mp->deferred_remove == DEFERRED_REMOVE_IN_PROGRESS) {
623                 condlog(3, "%s: deferred remove in progress", mp->alias);
624                 return 0;
625         }
626         mp_set_mpe(deferred_remove);
627         mp_set_ovr(deferred_remove);
628         mp_set_hwe(deferred_remove);
629         mp_set_conf(deferred_remove);
630         mp_set_default(deferred_remove, DEFAULT_DEFERRED_REMOVE);
631 out:
632         condlog(3, "%s: deferred_remove = %s %s", mp->alias,
633                 (mp->deferred_remove == DEFERRED_REMOVE_ON)? "yes" : "no",
634                 origin);
635         return 0;
636 }
637
638 extern int
639 select_delay_watch_checks(struct config *conf, struct multipath *mp)
640 {
641         char *origin, buff[12];
642
643         mp_set_mpe(delay_watch_checks);
644         mp_set_ovr(delay_watch_checks);
645         mp_set_hwe(delay_watch_checks);
646         mp_set_conf(delay_watch_checks);
647         mp_set_default(delay_watch_checks, DEFAULT_DELAY_CHECKS);
648 out:
649         print_delay_checks(buff, 12, &mp->delay_watch_checks);
650         condlog(3, "%s: delay_watch_checks = %s %s", mp->alias, buff, origin);
651         return 0;
652 }
653
654 extern int
655 select_delay_wait_checks(struct config *conf, struct multipath *mp)
656 {
657         char *origin, buff[12];
658
659         mp_set_mpe(delay_wait_checks);
660         mp_set_ovr(delay_wait_checks);
661         mp_set_hwe(delay_wait_checks);
662         mp_set_conf(delay_wait_checks);
663         mp_set_default(delay_wait_checks, DEFAULT_DELAY_CHECKS);
664 out:
665         print_delay_checks(buff, 12, &mp->delay_wait_checks);
666         condlog(3, "%s: delay_wait_checks = %s %s", mp->alias, buff, origin);
667         return 0;
668 }