LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 2751|回复: 11

请问谁晓得mount命令的编写方法。或者是该GNU项目的名称?

[复制链接]
发表于 2007-12-1 17:16:56 | 显示全部楼层 |阅读模式
请问谁晓得mount命令的编写方法。或者是该GNU项目的名称?
如题。
发表于 2007-12-1 18:13:34 | 显示全部楼层
应该是OS系统调用。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2007-12-1 19:14:00 | 显示全部楼层
谢谢,知道了。
我把这些放上来了(真是不好意思。居然过去没看见,我还以为这个东西很复杂呢)

$ man -k mount
drivemount_applet (1) - Drive Mount Applet for the GNOME panel.
fdlist (1)           - Floppy disk mount utility
fdmount (1)          - Floppy disk mount utility
fdmountd (1)         - Floppy disk mount utility
fdumount (1)         - Floppy disk mount utility
fdutilsconfig (8)    - configure the suid bit of fdmount
free (1)             - Display amount of free and used memory in the system
fusermount (1)       - mount FUSE filesystems
gnome-eject (1)      - Mount drives and volumes using HAL and read settings from the GNOME desktop configuration system gconf.
gnome-mount (1)      - Mount drives and volumes using HAL and read settings from the GNOME desktop configuration system gconf.
gnome-umount (1)     - Mount drives and volumes using HAL and read settings from the GNOME desktop configuration system gconf.
gnome-volume-manager (1) - GNOME daemon to auto-mount and manage media devices
mklost+found (8)     - create a lost+found directory on a mounted Linux second extended file system
mount (2)            - mount and unmount filesystems
mount (8)            - mount a file system
mount.ntfs (8)       - Third Generation Read/Write NTFS Driver
mount.ntfs-3g (8)    - Third Generation Read/Write NTFS Driver
mountpoint (1)       - see if a directory is a mountpoint
setup (2)            - setup devices and file systems, mount root file system
sleep (1)            - delay for a specified amount of time
umount (2)           - mount and unmount filesystems
umount (8)           - unmount file systems
umount2 (2)          - mount and unmount filesystems
$ man 2 mount
回复 支持 反对

使用道具 举报

 楼主| 发表于 2007-12-1 20:10:34 | 显示全部楼层
转载一篇mount函数说明:

Linux系统调用-- mount/umount函数详解

【 mount/umount系统调用】  
   
功能描述:
mount挂上文件系统,umount执行相反的操作。

用法:
#include <sys/mount.h>

int mount(const char *source, const char *target,
  const char *filesystemtype, unsigned long mountflags, const void *data);

int umount(const char *target);

int umount2(const char *target, int flags);


参数:  
source:将要挂上的文件系统,通常是一个设备名。
target:文件系统所要挂在的目标目录。
filesystemtype:文件系统的类型,可以是"ext2","msdos","proc","nfs","iso9660" 。。。
mountflags:指定文件系统的读写访问标志,可能值有以下

MS_BIND:执行bind挂载,使文件或者子目录树在文件系统内的另一个点上可视。
MS_DIRSYNC:同步目录的更新。
MS_MANDLOCK:允许在文件上执行强制锁。
MS_MOVE:移动子目录树。
MS_NOATIME:不要更新文件上的访问时间。
MS_NODEV:不允许访问设备文件。
MS_NODIRATIME:不允许更新目录上的访问时间。
MS_NOEXEC:不允许在挂上的文件系统上执行程序。
MS_NOSUID:执行程序时,不遵照set-user-ID 和 set-group-ID位。
MS_RDONLY:指定文件系统为只读。
MS_REMOUNT:重新加载文件系统。这允许你改变现存文件系统的mountflag和数据,而无需使用先卸载,再挂上文件系统的方式。
MS_SYNCHRONOUS:同步文件的更新。
MNT_FORCE:强制卸载,即使文件系统处于忙状态。
MNT_EXPIRE:将挂载点标志为过时。

data:文件系统特有的参数。
   
返回说明:  
成功执行时,返回0。失败返回-1,errno被设为以下的某个值  
EACCES:权能不足,可能原因是,路径的一部分不可搜索,或者挂载只读的文件系统时,没有指定 MS_RDONLY 标志。
EAGAIN:成功地将不处于忙状态的文件系统标志为过时。
EBUSY:一. 源文件系统已被挂上。或者不可以以只读的方式重新挂载,因为它还拥有以写方式打开的文件。二. 目标处于忙状态。
EFAULT: 内存空间访问出错。
EINVAL:操作无效,可能是源文件系统超级块无效。
ELOOP :路径解析的过程中存在太多的符号连接。
EMFILE:无需块设备要求的情况下,无用设备表已满。
ENAMETOOLONG:路径名超出可允许的长度。
ENODEV:内核不支持某中文件系统。
ENOENT:路径名部分内容表示的目录不存在。
ENOMEM: 核心内存不足。
ENOTBLK:source不是块设备。
ENOTDIR:路径名的部分内容不是目录。
EPERM : 调用者权能不足。
ENXIO:块主设备号超出所允许的范围。
回复 支持 反对

使用道具 举报

发表于 2007-12-2 09:43:33 | 显示全部楼层
留名,对那些参数不是很了解
回复 支持 反对

使用道具 举报

 楼主| 发表于 2007-12-2 17:24:15 | 显示全部楼层
再加点资料:
请问有什么系统调用可以获取系统中已挂载的文件系统列表?
http://www.linuxsir.cn/bbs/thread274193.html
回复 支持 反对

使用道具 举报

发表于 2007-12-3 08:57:54 | 显示全部楼层
Post by huyongzs;1790526
再加点资料:
请问有什么系统调用可以获取系统中已挂载的文件系统列表?
http://www.linuxsir.cn/bbs/thread274193.html


直接读 /proc/mounts, 比如在 shell 中

  1. cat /proc/mounts
复制代码
回复 支持 反对

使用道具 举报

发表于 2007-12-4 09:28:00 | 显示全部楼层
这种问题的最好答案,我个人觉得就是busybox
回复 支持 反对

使用道具 举报

 楼主| 发表于 2007-12-7 21:15:35 | 显示全部楼层
Post by remote fish;1790712
直接读 /proc/mounts, 比如在 shell 中

  1. cat /proc/mounts
复制代码


谢谢,我读的是/etc下的一个文件。好象是/etc/mtab
回复 支持 反对

使用道具 举报

发表于 2007-12-7 23:49:12 | 显示全部楼层
Post by Arthur.Echo;1791241
这种问题的最好答案,我个人觉得就是busybox


我也觉得。一开始我以为mount只是简单的系统调用,没想到从源里面拿到的mount源代码那么长...ubuntu中是在util-linux软件包。

这个是一小部分源代码:mount.c
  1. /*
  2. * A mount(8) for Linux 0.99.
  3. * mount.c,v 1.1.1.1 1993/11/18 08:40:51 jrs Exp
  4. *
  5. * Modifications by many people. Distributed under GPL.
  6. */

  7. #include <unistd.h>
  8. #include <ctype.h>
  9. #include <errno.h>
  10. #include <string.h>
  11. #include <getopt.h>
  12. #include <stdio.h>

  13. #include <pwd.h>
  14. #include <grp.h>

  15. #include <sys/types.h>
  16. #include <sys/ioctl.h>
  17. #include <sys/stat.h>
  18. #include <sys/wait.h>
  19. #include <sys/mount.h>

  20. #include "mount_blkid.h"
  21. #include "mount_constants.h"
  22. #include "sundries.h"
  23. #include "xmalloc.h"
  24. #include "mntent.h"
  25. #include "fstab.h"
  26. #include "lomount.h"
  27. #include "loop.h"
  28. #include "linux_fs.h"                /* for BLKGETSIZE */
  29. #include "mount_guess_rootdev.h"
  30. #include "mount_guess_fstype.h"
  31. #include "mount_by_label.h"
  32. #include "getusername.h"
  33. #include "paths.h"
  34. #include "env.h"
  35. #include "nls.h"

  36. #define DO_PS_FIDDLING

  37. #ifdef DO_PS_FIDDLING
  38. #include "setproctitle.h"
  39. #endif

  40. /* True for fake mount (-f).  */
  41. static int fake = 0;

  42. /* True if we are allowed to call /sbin/mount.${FSTYPE} */
  43. static int external_allowed = 1;

  44. /* Don't write a entry in /etc/mtab (-n).  */
  45. static int nomtab = 0;

  46. /* True for explicit readonly (-r).  */
  47. static int readonly = 0;

  48. /* Nonzero for chatty (-v).  */
  49. int verbose = 0;

  50. /* Nonzero for sloppy (-s).  */
  51. int sloppy = 0;

  52. /* True for explicit read/write (-w).  */
  53. static int readwrite = 0;

  54. /* True for all mount (-a).  */
  55. int mount_all = 0;

  56. /* True for fork() during all mount (-F).  */
  57. static int optfork = 0;

  58. /* Add volumelabel in a listing of mounted devices (-l). */
  59. static int list_with_volumelabel = 0;

  60. /* Nonzero for mount {--bind|--replace|--before|--after|--over|--move} */
  61. static int mounttype = 0;

  62. /* True if ruid != euid.  */
  63. static int suid = 0;

  64. /* Contains the fd to read the passphrase from, if any. */
  65. static int pfd = -1;

  66. /* Map from -o and fstab option strings to the flag argument to mount(2).  */
  67. struct opt_map {
  68.   const char *opt;                /* option name */
  69.   int  skip;                        /* skip in mtab option string */
  70.   int  inv;                        /* true if flag value should be inverted */
  71.   int  mask;                        /* flag mask value */
  72. };

  73. /* Custom mount options for our own purposes.  */
  74. /* Maybe these should now be freed for kernel use again */
  75. #define MS_NOAUTO        0x80000000
  76. #define MS_USERS        0x40000000
  77. #define MS_USER                0x20000000
  78. #define MS_OWNER        0x10000000
  79. #define MS_GROUP        0x08000000
  80. #define MS_COMMENT        0x00020000
  81. #define MS_LOOP                0x00010000

  82. /* Options that we keep the mount system call from seeing.  */
  83. #define MS_NOSYS        (MS_NOAUTO|MS_USERS|MS_USER|MS_COMMENT|MS_LOOP)

  84. /* Options that we keep from appearing in the options field in the mtab.  */
  85. #define MS_NOMTAB        (MS_REMOUNT|MS_NOAUTO|MS_USERS|MS_USER)

  86. /* Options that we make ordinary users have by default.  */
  87. #define MS_SECURE        (MS_NOEXEC|MS_NOSUID|MS_NODEV)

  88. /* Options that we make owner-mounted devices have by default */
  89. #define MS_OWNERSECURE        (MS_NOSUID|MS_NODEV)

  90. static const struct opt_map opt_map[] = {
  91.   { "defaults",        0, 0, 0                },        /* default options */
  92.   { "ro",        1, 0, MS_RDONLY        },        /* read-only */
  93.   { "rw",        1, 1, MS_RDONLY        },        /* read-write */
  94.   { "exec",        0, 1, MS_NOEXEC        },        /* permit execution of binaries */
  95.   { "noexec",        0, 0, MS_NOEXEC        },        /* don't execute binaries */
  96.   { "suid",        0, 1, MS_NOSUID        },        /* honor suid executables */
  97.   { "nosuid",        0, 0, MS_NOSUID        },        /* don't honor suid executables */
  98.   { "dev",        0, 1, MS_NODEV        },        /* interpret device files  */
  99.   { "nodev",        0, 0, MS_NODEV        },        /* don't interpret devices */
  100.   { "sync",        0, 0, MS_SYNCHRONOUS},        /* synchronous I/O */
  101.   { "async",        0, 1, MS_SYNCHRONOUS},        /* asynchronous I/O */
  102.   { "dirsync",        0, 0, MS_DIRSYNC},        /* synchronous directory modifications */
  103.   { "remount",  0, 0, MS_REMOUNT},      /* Alter flags of mounted FS */
  104.   { "bind",        0, 0, MS_BIND   },        /* Remount part of tree elsewhere */
  105.   { "rbind",        0, 0, MS_BIND|MS_REC }, /* Idem, plus mounted subtrees */
  106.   { "auto",        0, 1, MS_NOAUTO        },        /* Can be mounted using -a */
  107.   { "noauto",        0, 0, MS_NOAUTO        },        /* Can  only be mounted explicitly */
  108.   { "users",        0, 0, MS_USERS        },        /* Allow ordinary user to mount */
  109.   { "nousers",        0, 1, MS_USERS        },        /* Forbid ordinary user to mount */
  110.   { "user",        0, 0, MS_USER        },        /* Allow ordinary user to mount */
  111.   { "nouser",        0, 1, MS_USER        },        /* Forbid ordinary user to mount */
  112.   { "owner",        0, 0, MS_OWNER  },        /* Let the owner of the device mount */
  113.   { "noowner",        0, 1, MS_OWNER  },        /* Device owner has no special privs */
  114.   { "group",        0, 0, MS_GROUP  },        /* Let the group of the device mount */
  115.   { "nogroup",        0, 1, MS_GROUP  },        /* Device group has no special privs */
  116.   { "_netdev",        0, 0, MS_COMMENT},        /* Device requires network */
  117.   { "comment",        0, 0, MS_COMMENT},        /* fstab comment only (kudzu,_netdev)*/

  118.   /* add new options here */
  119. #ifdef MS_NOSUB
  120.   { "sub",        0, 1, MS_NOSUB        },        /* allow submounts */
  121.   { "nosub",        0, 0, MS_NOSUB        },        /* don't allow submounts */
  122. #endif
  123. #ifdef MS_SILENT
  124.   { "quiet",        0, 0, MS_SILENT    },        /* be quiet  */
  125.   { "loud",        0, 1, MS_SILENT    },        /* print out messages. */
  126. #endif
  127. #ifdef MS_MANDLOCK
  128.   { "mand",        0, 0, MS_MANDLOCK },        /* Allow mandatory locks on this FS */
  129.   { "nomand",        0, 1, MS_MANDLOCK },        /* Forbid mandatory locks on this FS */
  130. #endif
  131.   { "loop",        1, 0, MS_LOOP        },        /* use a loop device */
  132. #ifdef MS_NOATIME
  133.   { "atime",        0, 1, MS_NOATIME },        /* Update access time */
  134.   { "noatime",        0, 0, MS_NOATIME },        /* Do not update access time */
  135. #endif
  136. #ifdef MS_NODIRATIME
  137.   { "diratime",        0, 1, MS_NODIRATIME },        /* Update dir access times */
  138.   { "nodiratime", 0, 0, MS_NODIRATIME },/* Do not update dir access times */
  139. #endif
  140.   { NULL,        0, 0, 0                }
  141. };

  142. static const char *opt_loopdev, *opt_vfstype, *opt_offset, *opt_encryption,
  143.         *opt_speed, *opt_comment;

  144. static struct string_opt_map {
  145.   char *tag;
  146.   int skip;
  147.   const char **valptr;
  148. } string_opt_map[] = {
  149.   { "loop=",        0, &opt_loopdev },
  150.   { "vfs=",        1, &opt_vfstype },
  151.   { "offset=",        0, &opt_offset },
  152.   { "encryption=", 0, &opt_encryption },
  153.   { "speed=", 0, &opt_speed },
  154.   { "comment=", 1, &opt_comment },
  155.   { NULL, 0, NULL }
  156. };

  157. static void
  158. clear_string_opts(void) {
  159.         struct string_opt_map *m;

  160.         for (m = &string_opt_map[0]; m->tag; m++)
  161.                 *(m->valptr) = NULL;
  162. }

  163. static int
  164. parse_string_opt(char *s) {
  165.         struct string_opt_map *m;
  166.         int lth;

  167.         for (m = &string_opt_map[0]; m->tag; m++) {
  168.                 lth = strlen(m->tag);
  169.                 if (!strncmp(s, m->tag, lth)) {
  170.                         *(m->valptr) = xstrdup(s + lth);
  171.                         return 1;
  172.                 }
  173.         }
  174.         return 0;
  175. }

  176. int mount_quiet=0;

  177. /* Report on a single mount.  */
  178. static void
  179. print_one (const struct my_mntent *me) {
  180.         if (mount_quiet)
  181.                 return;
  182.         printf ("%s on %s", me->mnt_fsname, me->mnt_dir);
  183.         if (me->mnt_type != NULL && *(me->mnt_type) != '\0')
  184.                 printf (" type %s", me->mnt_type);
  185.         if (me->mnt_opts != NULL)
  186.                 printf (" (%s)", me->mnt_opts);
  187.         if (list_with_volumelabel) {
  188.                 const char *label;
  189.                 label = mount_get_volume_label_by_spec(me->mnt_fsname);
  190.                 if (label) {
  191.                         printf (" [%s]", label);
  192.                         /* free(label); */
  193.                 }
  194.         }
  195.         printf ("\n");
  196. }

  197. /* Report on everything in mtab (of the specified types if any).  */
  198. static int
  199. print_all (char *types) {
  200.      struct mntentchn *mc, *mc0;

  201.      mc0 = mtab_head();
  202.      for (mc = mc0->nxt; mc && mc != mc0; mc = mc->nxt) {
  203.           if (matching_type (mc->m.mnt_type, types))
  204.                print_one (&(mc->m));
  205.      }
  206.      exit (0);
  207. }

  208. static void
  209. my_free(const void *s) {
  210.         if (s)
  211.                 free((void *) s);
  212. }

  213. /*
  214. * Look for OPT in opt_map table and return mask value.
  215. * If OPT isn't found, tack it onto extra_opts (which is non-NULL).
  216. * For the options uid= and gid= replace user or group name by its value.
  217. */
  218. static inline void
  219. parse_opt(const char *opt, int *mask, char *extra_opts, int len) {
  220.         const struct opt_map *om;

  221.         for (om = opt_map; om->opt != NULL; om++)
  222.                 if (streq (opt, om->opt)) {
  223.                         if (om->inv)
  224.                                 *mask &= ~om->mask;
  225.                         else
  226.                                 *mask |= om->mask;
  227.                         if ((om->mask == MS_USER || om->mask == MS_USERS)
  228.                             && !om->inv)
  229.                                 *mask |= MS_SECURE;
  230.                         if ((om->mask == MS_OWNER || om->mask == MS_GROUP)
  231.                             && !om->inv)
  232.                                 *mask |= MS_OWNERSECURE;
  233. #ifdef MS_SILENT
  234.                         if (om->mask == MS_SILENT && om->inv)  {
  235.                                 mount_quiet = 1;
  236.                                 verbose = 0;
  237.                         }
  238. #endif
  239.                         return;
  240.                 }

  241.         len -= strlen(extra_opts);

  242.         if (*extra_opts && --len > 0)
  243.                 strcat(extra_opts, ",");

  244.         /* convert nonnumeric ids to numeric */
  245.         if (!strncmp(opt, "uid=", 4) && !isdigit(opt[4])) {
  246.                 struct passwd *pw = getpwnam(opt+4);
  247.                 char uidbuf[20];

  248.                 if (pw) {
  249.                         sprintf(uidbuf, "uid=%d", pw->pw_uid);
  250.                         if ((len -= strlen(uidbuf)) > 0)
  251.                                 strcat(extra_opts, uidbuf);
  252.                         return;
  253.                 }
  254.         }
  255.         if (!strncmp(opt, "gid=", 4) && !isdigit(opt[4])) {
  256.                 struct group *gr = getgrnam(opt+4);
  257.                 char gidbuf[20];

  258.                 if (gr) {
  259.                         sprintf(gidbuf, "gid=%d", gr->gr_gid);
  260.                         if ((len -= strlen(gidbuf)) > 0)
  261.                                 strcat(extra_opts, gidbuf);
  262.                         return;
  263.                 }
  264.         }

  265.         if ((len -= strlen(opt)) > 0)
  266.                 strcat(extra_opts, opt);
  267. }
  268.   
  269. /* Take -o options list and compute 4th and 5th args to mount(2).  flags
  270.    gets the standard options (indicated by bits) and extra_opts all the rest */
  271. static void
  272. parse_opts (const char *options, int *flags, char **extra_opts) {
  273.         *flags = 0;
  274.         *extra_opts = NULL;

  275.         clear_string_opts();

  276.         if (options != NULL) {
  277.                 char *opts = xstrdup(options);
  278.                 char *opt;
  279.                 int len = strlen(opts) + 20;

  280.                 *extra_opts = xmalloc(len);
  281.                 **extra_opts = '\0';

  282.                 for (opt = strtok(opts, ","); opt; opt = strtok(NULL, ","))
  283.                         if (!parse_string_opt(opt))
  284.                                 parse_opt(opt, flags, *extra_opts, len);

  285.                 free(opts);
  286.         }

  287.         if (readonly)
  288.                 *flags |= MS_RDONLY;
  289.         if (readwrite)
  290.                 *flags &= ~MS_RDONLY;
  291.         *flags |= mounttype;
  292. }

  293. /* Try to build a canonical options string.  */
  294. static char *
  295. fix_opts_string (int flags, const char *extra_opts, const char *user) {
  296.         const struct opt_map *om;
  297.         const struct string_opt_map *m;
  298.         char *new_opts;

  299.         new_opts = xstrdup((flags & MS_RDONLY) ? "ro" : "rw");
  300.         for (om = opt_map; om->opt != NULL; om++) {
  301.                 if (om->skip)
  302.                         continue;
  303.                 if (om->inv || !om->mask || (flags & om->mask) != om->mask)
  304.                         continue;
  305.                 new_opts = xstrconcat3(new_opts, ",", om->opt);
  306.                 flags &= ~om->mask;
  307.         }
  308.         for (m = &string_opt_map[0]; m->tag; m++) {
  309.                 if (!m->skip && *(m->valptr))
  310.                         new_opts = xstrconcat4(new_opts, ",",
  311.                                                m->tag, *(m->valptr));
  312.         }
  313.         if (extra_opts && *extra_opts) {
  314.                 new_opts = xstrconcat3(new_opts, ",", extra_opts);
  315.         }
  316.         if (user) {
  317.                 new_opts = xstrconcat3(new_opts, ",user=", user);
  318.         }
  319.         return new_opts;
  320. }

  321. static int
  322. already (const char *spec, const char *node) {
  323.         struct mntentchn *mc;
  324.         int ret = 1;

  325.         if ((mc = getmntfile(node)) != NULL)
  326.                 error (_("mount: according to mtab, "
  327.                          "%s is already mounted on %s"),
  328.                        mc->m.mnt_fsname, node);
  329.         else if (spec && strcmp (spec, "none") &&
  330.                  (mc = getmntfile(spec)) != NULL)
  331.                 error (_("mount: according to mtab, %s is mounted on %s"),
  332.                        spec, mc->m.mnt_dir);
  333.         else
  334.                 ret = 0;
  335.         return ret;
  336. }

  337. /* Create mtab with a root entry.  */
  338. static void
  339. create_mtab (void) {
  340.         struct mntentchn *fstab;
  341.         struct my_mntent mnt;
  342.         int flags;
  343.         mntFILE *mfp;

  344.         lock_mtab();

  345.         mfp = my_setmntent (MOUNTED, "a+");
  346.         if (mfp == NULL || mfp->mntent_fp == NULL) {
  347.                 int errsv = errno;
  348.                 die (EX_FILEIO, _("mount: can't open %s for writing: %s"),
  349.                      MOUNTED, strerror (errsv));
  350.         }

  351.         /* Find the root entry by looking it up in fstab */
  352.         if ((fstab = getfsfile ("/")) || (fstab = getfsfile ("root"))) {
  353.                 char *extra_opts;
  354.                 parse_opts (fstab->m.mnt_opts, &flags, &extra_opts);
  355.                 mnt.mnt_dir = "/";
  356.                 mnt.mnt_fsname = canonicalize (fstab->m.mnt_fsname);
  357.                 mnt.mnt_type = fstab->m.mnt_type;
  358.                 mnt.mnt_opts = fix_opts_string (flags, extra_opts, NULL);
  359.                 mnt.mnt_freq = mnt.mnt_passno = 0;
  360.                 my_free(extra_opts);

  361.                 if (my_addmntent (mfp, &mnt) == 1) {
  362.                         int errsv = errno;
  363.                         die (EX_FILEIO, _("mount: error writing %s: %s"),
  364.                              MOUNTED, strerror (errsv));
  365.                 }
  366.         }
  367.         if (fchmod (fileno (mfp->mntent_fp), 0644) < 0)
  368.                 if (errno != EROFS) {
  369.                         int errsv = errno;
  370.                         die (EX_FILEIO,
  371.                              _("mount: error changing mode of %s: %s"),
  372.                              MOUNTED, strerror (errsv));
  373.                 }
  374.         my_endmntent (mfp);

  375.         unlock_mtab();
  376. }

  377. /* count successful mount system calls */
  378. static int mountcount = 0;

  379. /*
  380. * do_mount_syscall()
  381. *        Mount a single file system. Keep track of successes.
  382. * returns: 0: OK, -1: error in errno
  383. */
  384. static int
  385. do_mount_syscall (struct mountargs *args) {
  386.         int flags = args->flags;
  387.         int ret;

  388.         if ((flags & MS_MGC_MSK) == 0)
  389.                 flags |= MS_MGC_VAL;

  390.         ret = mount (args->spec, args->node, args->type, flags, args->data);
  391.         if (ret == 0)
  392.                 mountcount++;
  393.         return ret;
  394. }

  395. /*
  396. * guess_fstype_and_mount()
  397. *        Mount a single file system. Guess the type when unknown.
  398. * returns: 0: OK, -1: error in errno, 1: other error
  399. *        don't exit on non-fatal errors.
  400. *        on return types is filled with the type used.
  401. */
  402. static int
  403. guess_fstype_and_mount(const char *spec, const char *node, const char **types,
  404.                        int flags, char *mount_opts) {
  405.    struct mountargs args = { spec, node, NULL, flags & ~MS_NOSYS, mount_opts };
  406.    
  407.    if (*types && strcasecmp (*types, "auto") == 0)
  408.       *types = NULL;

  409.    if (!*types && (flags & (MS_BIND | MS_MOVE)))
  410.       *types = "none";                /* random, but not "bind" */

  411.    if (!*types && !(flags & MS_REMOUNT)) {
  412.       *types = guess_fstype(spec);
  413.       if (*types && !strcmp(*types, "swap")) {
  414.           error(_("%s looks like swapspace - not mounted"), spec);
  415.           *types = NULL;
  416.           return 1;
  417.       }
  418.    }

  419.    /* Accept a comma-separated list of types, and try them one by one */
  420.    /* A list like "nonfs,.." indicates types not to use */
  421.    if (*types && strncmp(*types, "no", 2) && index(*types,',')) {
  422.       char *t = strdup(*types);
  423.       char *p;

  424.       while((p = index(t,',')) != NULL) {
  425.          *p = 0;
  426.          args.type = *types = t;
  427.          if(do_mount_syscall (&args) == 0)
  428.             return 0;
  429.          t = p+1;
  430.       }
  431.       /* do last type below */
  432.       *types = t;
  433.    }

  434.    if (*types || (flags & MS_REMOUNT)) {
  435.       args.type = *types;
  436.       return do_mount_syscall (&args);
  437.    }

  438.    return procfsloop(do_mount_syscall, &args, types);
  439. }

  440. /*
  441. * suid_check()
  442. *        Die if the user is not allowed to do this.
  443. */
  444. static void
  445. suid_check(const char *spec, const char *node, int *flags, char **user) {
  446.   if (suid) {
  447.       /*
  448.        * MS_OWNER: Allow owners to mount when fstab contains
  449.        * the owner option.  Note that this should never be used
  450.        * in a high security environment, but may be useful to give
  451.        * people at the console the possibility of mounting a floppy.
  452.        * MS_GROUP: Allow members of device group to mount. (Martin Dickopp)
  453.        */
  454.       if (*flags & (MS_OWNER | MS_GROUP)) {
  455.           struct stat sb;

  456.           if (!strncmp(spec, "/dev/", 5) && stat(spec, &sb) == 0) {

  457.               if (*flags & MS_OWNER) {
  458.                   if (getuid() == sb.st_uid)
  459.                       *flags |= MS_USER;
  460.               }

  461.               if (*flags & MS_GROUP) {
  462.                   if (getgid() == sb.st_gid)
  463.                       *flags |= MS_USER;
  464.                   else {
  465.                       int n = getgroups(0, NULL);

  466.                       if (n > 0) {
  467.                               gid_t *groups = xmalloc(n * sizeof(*groups));
  468.                               if (getgroups(n, groups) == n) {
  469.                                       int i;
  470.                                       for (i = 0; i < n; i++) {
  471.                                               if (groups[i] == sb.st_gid) {
  472.                                                       *flags |= MS_USER;
  473.                                                       break;
  474.                                               }
  475.                                       }
  476.                               }
  477.                               free(groups);
  478.                       }
  479.                   }
  480.               }
  481.           }
  482.       }

  483.       /* James Kehl <mkehl@gil.com.au> came with a similar patch:
  484.          allow an arbitrary user to mount when he is the owner of
  485.          the mount-point and has write-access to the device.
  486.          This is even less secure. Let me skip it for the time being;
  487.          there should be an explicit fstab line allowing such things. */

  488.       if (!(*flags & (MS_USER | MS_USERS))) {
  489.           if (already (spec, node))
  490.             die (EX_USAGE, _("mount failed"));
  491.           else
  492.             die (EX_USAGE, _("mount: only root can mount %s on %s"), spec, node);
  493.       }
  494.       if (*flags & MS_USER)
  495.           *user = getusername();
  496.   }

  497.   *flags &= ~(MS_OWNER | MS_GROUP);
  498. }

  499. static int
  500. loop_check(const char **spec, const char **type, int *flags,
  501.            int *loop, const char **loopdev, const char **loopfile) {
  502.   int looptype;
  503.   unsigned long long offset;

  504.   /*
  505.    * In the case of a loop mount, either type is of the form lo@/dev/loop5
  506.    * or the option "-o loop=/dev/loop5" or just "-o loop" is given, or
  507.    * mount just has to figure things out for itself from the fact that
  508.    * spec is not a block device. We do not test for a block device
  509.    * immediately: maybe later other types of mountable objects will occur.
  510.    */

  511.   *loopdev = opt_loopdev;

  512.   looptype = (*type && strncmp("lo@", *type, 3) == 0);
  513.   if (looptype) {
  514.     if (*loopdev)
  515.       error(_("mount: loop device specified twice"));
  516.     *loopdev = *type + 3;
  517.     *type = opt_vfstype;
  518.   } else if (opt_vfstype) {
  519.     if (*type)
  520.       error(_("mount: type specified twice"));
  521.     else
  522.       *type = opt_vfstype;
  523.   }

  524.   *loop = ((*flags & MS_LOOP) || *loopdev || opt_offset || opt_encryption);
  525.   *loopfile = *spec;

  526.   if (*loop) {
  527.     *flags |= MS_LOOP;
  528.     if (fake) {
  529.       if (verbose)
  530.         printf(_("mount: skipping the setup of a loop device\n"));
  531.     } else {
  532.       int loopro = (*flags & MS_RDONLY);

  533.       if (!*loopdev || !**loopdev)
  534.         *loopdev = find_unused_loop_device();
  535.       if (!*loopdev)
  536.         return EX_SYSERR;        /* no more loop devices */
  537.       if (verbose)
  538.         printf(_("mount: going to use the loop device %s\n"), *loopdev);
  539.       offset = opt_offset ? strtoull(opt_offset, NULL, 0) : 0;
  540.       if (set_loop(*loopdev, *loopfile, offset,
  541.                    opt_encryption, pfd, &loopro)) {
  542.         if (verbose)
  543.           printf(_("mount: failed setting up loop device\n"));
  544.         return EX_FAIL;
  545.       }
  546.       if (verbose > 1)
  547.         printf(_("mount: setup loop device successfully\n"));
  548.       *spec = *loopdev;
  549.       if (loopro)
  550.         *flags |= MS_RDONLY;
  551.     }
  552.   }

  553.   return 0;
  554. }

  555. static void
  556. update_mtab_entry(const char *spec, const char *node, const char *type,
  557.                   const char *opts, int flags, int freq, int pass) {
  558.         struct my_mntent mnt;

  559.         mnt.mnt_fsname = canonicalize (spec);
  560.         mnt.mnt_dir = canonicalize (node);
  561.         mnt.mnt_type = type;
  562.         mnt.mnt_opts = opts;
  563.         mnt.mnt_freq = freq;
  564.         mnt.mnt_passno = pass;
  565.       
  566.         /* We get chatty now rather than after the update to mtab since the
  567.            mount succeeded, even if the write to /etc/mtab should fail.  */
  568.         if (verbose)
  569.                 print_one (&mnt);

  570.         if (!nomtab && mtab_is_writable()) {
  571.                 if (flags & MS_REMOUNT)
  572.                         update_mtab (mnt.mnt_dir, &mnt);
  573.                 else {
  574.                         mntFILE *mfp;

  575.                         lock_mtab();
  576.                         mfp = my_setmntent(MOUNTED, "a+");
  577.                         if (mfp == NULL || mfp->mntent_fp == NULL) {
  578.                                 int errsv = errno;
  579.                                 error(_("mount: can't open %s: %s"), MOUNTED,
  580.                                       strerror (errsv));
  581.                         } else {
  582.                                 if ((my_addmntent (mfp, &mnt)) == 1) {
  583.                                         int errsv = errno;
  584.                                         error(_("mount: error writing %s: %s"),
  585.                                               MOUNTED, strerror (errsv));
  586.                                 }
  587.                         }
  588.                         my_endmntent(mfp);
  589.                         unlock_mtab();
  590.                 }
  591.         }
  592.         my_free(mnt.mnt_fsname);
  593.         my_free(mnt.mnt_dir);
  594. }

  595. static void
  596. set_pfd(char *s) {
  597.         if (!isdigit(*s))
  598.                 die(EX_USAGE,
  599.                     _("mount: argument to -p or --pass-fd must be a number"));
  600.         pfd = atoi(optarg);
  601. }

  602. static void
  603. cdrom_setspeed(const char *spec) {
  604. #define CDROM_SELECT_SPEED      0x5322  /* Set the CD-ROM speed */
  605.         if (opt_speed) {
  606.                 int cdrom;
  607.                 int speed = atoi(opt_speed);

  608.                 if ((cdrom = open(spec, O_RDONLY | O_NONBLOCK)) < 0)
  609.                         die(EX_FAIL,
  610.                             _("mount: cannot open %s for setting speed"),
  611.                             spec);
  612.                 if (ioctl(cdrom, CDROM_SELECT_SPEED, speed) < 0)
  613.                         die(EX_FAIL, _("mount: cannot set speed: %s"),
  614.                             strerror(errno));
  615.                 close(cdrom);
  616.         }
  617. }

  618. /*
  619. * check_special_mountprog()
  620. *        If there is a special mount program for this type, exec it.
  621. * returns: 0: no exec was done, 1: exec was done, status has result
  622. */

  623. static int
  624. check_special_mountprog(const char *spec, const char *node, const char *type,
  625.                         int flags, char *extra_opts, int *status) {
  626.   char mountprog[120];
  627.   struct stat statbuf;
  628.   int res;

  629.   if (!external_allowed)
  630.       return 0;

  631.   if (type && strlen(type) < 100) {
  632.        sprintf(mountprog, "/sbin/mount.%s", type);
  633.        if (stat(mountprog, &statbuf) == 0) {
  634.             res = fork();
  635.             if (res == 0) {
  636.                  const char *oo, *mountargs[10];
  637.                  int i = 0;

  638.                  setuid(getuid());
  639.                  setgid(getgid());
  640.                  oo = fix_opts_string (flags, extra_opts, NULL);
  641.                  mountargs[i++] = mountprog;
  642.                  mountargs[i++] = spec;
  643.                  mountargs[i++] = node;
  644.                  if (nomtab)
  645.                       mountargs[i++] = "-n";
  646.                  if (verbose)
  647.                       mountargs[i++] = "-v";
  648.                  if (oo && *oo) {
  649.                       mountargs[i++] = "-o";
  650.                       mountargs[i++] = oo;
  651.                  }
  652.                  mountargs[i] = NULL;
  653.                  execv(mountprog, (char **) mountargs);
  654.                  exit(1);        /* exec failed */
  655.             } else if (res != -1) {
  656.                  int st;
  657.                  wait(&st);
  658.                  *status = (WIFEXITED(st) ? WEXITSTATUS(st) : EX_SYSERR);
  659.                  return 1;
  660.             } else {
  661.                      int errsv = errno;
  662.                  error(_("mount: cannot fork: %s"), strerror(errsv));
  663.             }
  664.        }
  665.   }
  666.   return 0;
  667. }

  668. /*
  669. * try_mount_one()
  670. *        Try to mount one file system. When "bg" is 1, this is a retry
  671. *        in the background. One additional exit code EX_BG is used here.
  672. *        It is used to instruct the caller to retry the mount in the
  673. *        background.
  674. * returns: 0: OK, EX_SYSERR, EX_FAIL, return code from nfsmount,
  675. *      return status from wait
  676. */
  677. static int
  678. try_mount_one (const char *spec0, const char *node0, const char *types0,
  679.                const char *opts0, int freq, int pass, int bg, int ro) {
  680.   int res = 0, status;
  681.   int mnt5_res = 0;                /* only for gcc */
  682.   int mnt_err;
  683.   int flags;
  684.   char *extra_opts;                /* written in mtab */
  685.   char *mount_opts;                /* actually used on system call */
  686.   const char *opts, *spec, *node, *types;
  687.   char *user = 0;
  688.   int loop = 0;
  689.   const char *loopdev = 0, *loopfile = 0;
  690.   struct stat statbuf;
  691.   int nfs_mount_version = 0;        /* any version */

  692.   /* copies for freeing on exit */
  693.   const char *opts1, *spec1, *node1, *types1, *extra_opts1;

  694.   spec = spec1 = xstrdup(spec0);
  695.   node = node1 = xstrdup(node0);
  696.   types = types1 = xstrdup(types0);
  697.   opts = opts1 = xstrdup(opts0);

  698.   parse_opts (opts, &flags, &extra_opts);
  699.   extra_opts1 = extra_opts;

  700.   /* quietly succeed for fstab entries that don't get mounted automatically */
  701.   if (mount_all && (flags & MS_NOAUTO))
  702.       goto out;

  703.   suid_check(spec, node, &flags, &user);

  704.   mount_opts = extra_opts;

  705.   if (opt_speed)
  706.       cdrom_setspeed(spec);

  707.   if (!(flags & MS_REMOUNT)) {
  708.       /*
  709.        * Don't set up a (new) loop device if we only remount - this left
  710.        * stale assignments of files to loop devices. Nasty when used for
  711.        * encryption.
  712.        */
  713.       res = loop_check(&spec, &types, &flags, &loop, &loopdev, &loopfile);
  714.       if (res)
  715.           goto out;
  716.   }

  717.   /*
  718.    * Call mount.TYPE for types that require a separate mount program.
  719.    * For the moment these types are ncpfs and smbfs. Maybe also vxfs.
  720.    * All such special things must occur isolated in the types string.
  721.    */
  722.   if (check_special_mountprog(spec, node, types, flags, extra_opts, &status)) {
  723.       res = status;
  724.       goto out;
  725.   }

  726.   /*
  727.    * Also nfs requires a separate program, but it is built in.
  728.    */
  729.   if (!fake && types && streq (types, "nfs")) {
  730. #ifdef HAVE_NFS
  731. retry_nfs:
  732.     mnt_err = nfsmount (spec, node, &flags, &extra_opts, &mount_opts,
  733.                         &nfs_mount_version, bg);
  734.     if (mnt_err) {
  735.         res = mnt_err;
  736.         goto out;
  737.     }
  738. #else
  739.     die (EX_SOFTWARE, _("mount: this version was compiled "
  740.                       "without support for the type `nfs'"));
  741. #endif
  742.   }

  743.   block_signals (SIG_BLOCK);

  744.   if (!fake)
  745.     mnt5_res = guess_fstype_and_mount (spec, node, &types, flags & ~MS_NOSYS,
  746.                                        mount_opts);

  747.   if (fake || mnt5_res == 0) {
  748.       /* Mount succeeded, report this (if verbose) and write mtab entry.  */
  749.       if (loop)
  750.           opt_loopdev = loopdev;

  751.       update_mtab_entry(loop ? loopfile : spec,
  752.                         node,
  753.                         types ? types : "unknown",
  754.                         fix_opts_string (flags & ~MS_NOMTAB, extra_opts, user),
  755.                         flags,
  756.                         freq,
  757.                         pass);

  758.       block_signals (SIG_UNBLOCK);
  759.       res = 0;
  760.       goto out;
  761.   }

  762.   mnt_err = errno;

  763.   if (loop)
  764.         del_loop(spec);

  765.   block_signals (SIG_UNBLOCK);

  766. #ifdef HAVE_NFS
  767.   if (mnt_err && types && streq (types, "nfs")) {
  768.       if (nfs_mount_version == 4 && mnt_err != EBUSY && mnt_err != ENOENT) {
  769.           if (verbose)
  770.             printf(_("mount: failed with nfs mount version 4, trying 3..\n"));
  771.           nfs_mount_version = 3;
  772.           goto retry_nfs;
  773.       }
  774.   }
  775. #endif

  776.   /* Mount failed, complain, but don't die.  */

  777.   if (types == 0) {
  778.     if (suid)
  779.       error (_("mount: I could not determine the filesystem type, "
  780.                "and none was specified"));
  781.     else
  782.       error (_("mount: you must specify the filesystem type"));
  783.   } else if (mnt5_res != -1) {
  784.       /* should not happen */
  785.       error (_("mount: mount failed"));
  786.   } else {
  787.    switch (mnt_err) {
  788.     case EPERM:
  789.       if (geteuid() == 0) {
  790.            if (stat (node, &statbuf) || !S_ISDIR(statbuf.st_mode))
  791.                 error (_("mount: mount point %s is not a directory"), node);
  792.            else
  793.                 error (_("mount: permission denied"));
  794.       } else
  795.         error (_("mount: must be superuser to use mount"));
  796.       break;
  797.     case EBUSY:
  798.       if (flags & MS_REMOUNT) {
  799.         error (_("mount: %s is busy"), node);
  800.       } else if (!strcmp(types, "proc") && !strcmp(node, "/proc")) {
  801.         /* heuristic: if /proc/version exists, then probably proc is mounted */
  802.         if (stat ("/proc/version", &statbuf))   /* proc mounted? */
  803.            error (_("mount: %s is busy"), node);   /* no */
  804.         else if (!mount_all || verbose)            /* yes, don't mention it */
  805.            error (_("mount: proc already mounted"));
  806.       } else {
  807.         error (_("mount: %s already mounted or %s busy"), spec, node);
  808.         already (spec, node);
  809.       }
  810.       break;
  811.     case ENOENT:
  812.       if (lstat (node, &statbuf))
  813.            error (_("mount: mount point %s does not exist"), node);
  814.       else if (stat (node, &statbuf))
  815.            error (_("mount: mount point %s is a symbolic link to nowhere"),
  816.                   node);
  817.       else if (stat (spec, &statbuf))
  818.            error (_("mount: special device %s does not exist"), spec);
  819.       else {
  820.            errno = mnt_err;
  821.            perror("mount");
  822.       }
  823.       break;
  824.     case ENOTDIR:
  825.       if (stat (node, &statbuf) || ! S_ISDIR(statbuf.st_mode))
  826.            error (_("mount: mount point %s is not a directory"), node);
  827.       else if (stat (spec, &statbuf) && errno == ENOTDIR)
  828.            error (_("mount: special device %s does not exist\n"
  829.                     "       (a path prefix is not a directory)\n"), spec);
  830.       else {
  831.            errno = mnt_err;
  832.            perror("mount");
  833.       }
  834.       break;
  835.     case EINVAL:
  836.     { int fd;
  837.       unsigned long size;
  838.       int warned=0;

  839.       if (flags & MS_REMOUNT) {
  840.         error (_("mount: %s not mounted already, or bad option"), node);
  841.       } else {
  842.         error (_("mount: wrong fs type, bad option, bad superblock on %s,\n"
  843.                "       missing codepage or other error"),
  844.                spec);

  845.         if (stat(spec, &statbuf) == 0 && S_ISBLK(statbuf.st_mode)
  846.            && (fd = open(spec, O_RDONLY | O_NONBLOCK)) >= 0) {
  847.           if (ioctl(fd, BLKGETSIZE, &size) == 0) {
  848.             if (size == 0 && !loop) {
  849.               warned++;
  850.               error(_(
  851.                  "       (could this be the IDE device where you in fact use\n"
  852.                  "       ide-scsi so that sr0 or sda or so is needed?)"));
  853.             }
  854.             if (size && size <= 2) {
  855.               warned++;
  856.               error(_(
  857.                   "       (aren't you trying to mount an extended partition,\n"
  858.                   "       instead of some logical partition inside?)"));
  859.             }
  860.           close(fd);
  861.           }
  862. #if 0
  863.           /* 0xf for SCSI, 0x3f for IDE. One might check /proc/partitions
  864.              to see whether this thing really is partitioned.
  865.              Do not suggest partitions for /dev/fd0. */
  866.           if (!warned && (statbuf.st_rdev & 0xf) == 0) {
  867.             warned++;
  868.             error ("       (could this be the whole disk device\n"
  869.                    "       where you need a partition?)");
  870.           }
  871. #endif
  872.         }
  873.         error(_(
  874.                 "       In some cases useful info is found in syslog - try\n"
  875.                 "       dmesg | tail  or so\n"));
  876.       }
  877.       break;
  878.     }
  879.     case EMFILE:
  880.       error (_("mount table full")); break;
  881.     case EIO:
  882.       error (_("mount: %s: can't read superblock"), spec); break;
  883.     case ENODEV:
  884.     { int pfs;
  885.       if ((pfs = is_in_procfs(types)) == 1 || !strcmp(types, "guess"))
  886.         error(_("mount: %s: unknown device"), spec);
  887.       else if (pfs == 0) {
  888.         char *lowtype, *p;
  889.         int u;

  890.         error (_("mount: unknown filesystem type '%s'"), types);

  891.         /* maybe this loser asked for FAT or ISO9660 or isofs */
  892.         lowtype = xstrdup(types);
  893.         u = 0;
  894.         for(p=lowtype; *p; p++) {
  895.           if(tolower(*p) != *p) {
  896.             *p = tolower(*p);
  897.             u++;
  898.           }
  899.         }
  900.         if (u && is_in_procfs(lowtype) == 1)
  901.           error (_("mount: probably you meant %s"), lowtype);
  902.         else if (!strncmp(lowtype, "iso", 3) && is_in_procfs("iso9660") == 1)
  903.           error (_("mount: maybe you meant 'iso9660'?"));
  904.         else if (!strncmp(lowtype, "fat", 3) && is_in_procfs("vfat") == 1)
  905.           error (_("mount: maybe you meant 'vfat'?"));
  906.         free(lowtype);
  907.       } else
  908.         error (_("mount: %s has wrong device number or fs type %s not supported"),
  909.                spec, types);
  910.       break;
  911.     }
  912.     case ENOTBLK:
  913.       if (stat (spec, &statbuf)) /* strange ... */
  914.         error (_("mount: %s is not a block device, and stat fails?"), spec);
  915.       else if (S_ISBLK(statbuf.st_mode))
  916.         error (_("mount: the kernel does not recognize %s as a block device\n"
  917.                "       (maybe `insmod driver'?)"), spec);
  918.       else if (S_ISREG(statbuf.st_mode))
  919.         error (_("mount: %s is not a block device (maybe try `-o loop'?)"),
  920.                  spec);
  921.       else
  922.         error (_("mount: %s is not a block device"), spec);
  923.       break;
  924.     case ENXIO:
  925.       error (_("mount: %s is not a valid block device"), spec); break;
  926.     case EACCES:  /* pre-linux 1.1.38, 1.1.41 and later */
  927.     case EROFS:   /* linux 1.1.38 and later */
  928.     { char *bd = (loop ? "" : _("block device "));
  929.       if (ro || (flags & MS_RDONLY)) {
  930.           error (_("mount: cannot mount %s%s read-only"),
  931.                  bd, spec);
  932.           break;
  933.       } else if (readwrite) {
  934.           error (_("mount: %s%s is write-protected but explicit `-w' flag given"),
  935.                  bd, spec);
  936.           break;
  937.       } else {
  938.          if (loop) {
  939.              opts = opts0;
  940.              types = types0;
  941.          }
  942.          if (opts) {
  943.              char *opts2 = xrealloc(xstrdup(opts), strlen(opts)+4);
  944.              strcat(opts2, ",ro");
  945.              my_free(opts1);
  946.              opts = opts1 = opts2;
  947.          } else
  948.              opts = "ro";
  949.          if (types && !strcmp(types, "guess"))
  950.              types = 0;
  951.          error (_("mount: %s%s is write-protected, mounting read-only"),
  952.                 bd, spec0);
  953.          res = try_mount_one (spec0, node0, types, opts, freq, pass, bg, 1);
  954.          goto out;
  955.       }
  956.       break;
  957.     }
  958.     default:
  959.       error ("mount: %s", strerror (mnt_err)); break;
  960.     }
  961.   }
  962.   res = EX_FAIL;

  963. out:
  964.   my_free(extra_opts1);
  965.   my_free(spec1);
  966.   my_free(node1);
  967.   my_free(opts1);
  968.   my_free(types1);

  969.   return res;
  970. }

  971. /*
  972. * set_proc_name()
  973. *        Update the argument vector, so that this process may be easily
  974. *        identified in a "ps" listing.
  975. */
  976. static void
  977. set_proc_name (const char *spec)
  978. {
  979. #ifdef DO_PS_FIDDLING
  980.         setproctitle ("mount", spec);
  981. #endif
  982. }

  983. static char *
  984. subst_string(const char *s, const char *sub, int sublen, const char *repl) {
  985.         char *n;

  986.         n = (char *) xmalloc(strlen(s)-sublen+strlen(repl)+1);
  987.         strncpy (n, s, sub-s);
  988.         strcpy (n + (sub-s), repl);
  989.         strcat (n, sub+sublen);
  990.         return n;
  991. }

  992. static const char *
  993. usersubst(const char *opts) {
  994.         char *s, *w;
  995.         char id[40];

  996.         s = "uid=useruid";
  997.         if (opts && (w = strstr(opts, s)) != NULL) {
  998.                 sprintf(id, "uid=%d", getuid());
  999.                 opts = subst_string(opts, w, strlen(s), id);
  1000.         }
  1001.         s = "gid=usergid";
  1002.         if (opts && (w = strstr(opts, s)) != NULL) {
  1003.                 sprintf(id, "gid=%d", getgid());
  1004.                 opts = subst_string(opts, w, strlen(s), id);
  1005.         }
  1006.         return opts;
  1007. }

  1008. static int
  1009. is_existing_file (const char *s) {
  1010.         struct stat statbuf;

  1011.         return (stat(s, &statbuf) == 0);
  1012. }

  1013. /*
  1014. * Return 0 for success (either mounted sth or -a and NOAUTO was given)
  1015. */
  1016. static int
  1017. mount_one (const char *spec, const char *node, const char *types,
  1018.            const char *opts, char *cmdlineopts, int freq, int pass) {
  1019.         int status, status2;
  1020.         const char *nspec;

  1021.         /* Substitute values in opts, if required */
  1022.         opts = usersubst(opts);

  1023.         /* Merge the fstab and command line options.  */
  1024.         if (opts == NULL)
  1025.                 opts = cmdlineopts;
  1026.         else if (cmdlineopts != NULL)
  1027.                 opts = xstrconcat3(opts, ",", cmdlineopts);

  1028.         /* Handle possible LABEL= and UUID= forms of spec */
  1029.         nspec = mount_get_devname_for_mounting(spec);
  1030.         if (nspec)
  1031.                 spec = nspec;

  1032.         if (types == NULL && !mounttype && !is_existing_file(spec)) {
  1033.                 if (strchr (spec, ':') != NULL) {
  1034.                         types = "nfs";
  1035.                         if (verbose)
  1036.                                 printf(_("mount: no type was given - "
  1037.                                          "I'll assume nfs because of "
  1038.                                          "the colon\n"));
  1039.                 } else if(!strncmp(spec, "//", 2)) {
  1040.                         types = "smbfs";
  1041.                         if (verbose)
  1042.                                 printf(_("mount: no type was given - "
  1043.                                          "I'll assume smbfs because of "
  1044.                                          "the // prefix\n"));
  1045.                 }
  1046.         }

  1047.         /*
  1048.          * Try to mount the file system. When the exit status is EX_BG,
  1049.          * we will retry in the background. Otherwise, we're done.
  1050.          */
  1051.         status = try_mount_one (spec, node, types, opts, freq, pass, 0, 0);
  1052.         if (status != EX_BG)
  1053.                 return status;

  1054.         /*
  1055.          * Retry in the background.
  1056.          */
  1057.         printf (_("mount: backgrounding "%s"\n"), spec);
  1058.         fflush( stdout );                /* prevent duplicate output */
  1059.         if (fork() > 0)
  1060.                 return 0;                        /* parent returns "success" */
  1061.         spec = xstrdup(spec);                /* arguments will be destroyed */
  1062.         node = xstrdup(node);                /* by set_proc_name()          */
  1063.         types = xstrdup(types);
  1064.         opts = xstrdup(opts);
  1065.         set_proc_name (spec);                /* make a nice "ps" listing */
  1066.         status2 = try_mount_one (spec, node, types, opts, freq, pass, 1, 0);
  1067.         if (verbose && status2)
  1068.                 printf (_("mount: giving up "%s"\n"), spec);
  1069.         exit (0);                        /* child stops here */
  1070. }

  1071. /* Check if an fsname/dir pair was already in the old mtab.  */
  1072. static int
  1073. mounted (const char *spec0, const char *node0) {
  1074.         struct mntentchn *mc, *mc0;
  1075.         char *spec, *node;
  1076.         int ret = 0;

  1077.         /* Handle possible UUID= and LABEL= in spec */
  1078.         spec0 = mount_get_devname(spec0);
  1079.         if (!spec0)
  1080.                 return ret;

  1081.         spec = canonicalize(spec0);
  1082.         node = canonicalize(node0);

  1083.         mc0 = mtab_head();
  1084.         for (mc = mc0->nxt; mc && mc != mc0; mc = mc->nxt)
  1085.                 if (streq (spec, mc->m.mnt_fsname) &&
  1086.                     streq (node, mc->m.mnt_dir)) {
  1087.                         ret = 1;
  1088.                         break;
  1089.                 }

  1090.         my_free(spec);
  1091.         my_free(node);

  1092.         return ret;
  1093. }

  1094. /* avoid using stat() on things we are not going to mount anyway.. */
  1095. static int
  1096. has_noauto (const char *opts) {
  1097.         char *s;

  1098.         if (!opts)
  1099.                 return 0;
  1100.         s = strstr(opts, "noauto");
  1101.         if (!s)
  1102.                 return 0;
  1103.         return (s == opts || s[-1] == ',') && (s[6] == 0 || s[6] == ',');
  1104. }

  1105. /* Mount all filesystems of the specified types except swap and root.  */
  1106. /* With the --fork option: fork and let different incarnations of
  1107.    mount handle different filesystems.  However, try to avoid several
  1108.    simultaneous mounts on the same physical disk, since that is very slow. */
  1109. #define DISKMAJOR(m)        (((int) m) & ~0xf)

  1110. static int
  1111. do_mount_all (char *types, char *options, char *test_opts) {
  1112.         struct mntentchn *mc, *mc0, *mtmp;
  1113.         int status = 0;
  1114.         struct stat statbuf;
  1115.         struct child {
  1116.                 pid_t pid;
  1117.                 char *group;
  1118.                 struct mntentchn *mec;
  1119.                 struct mntentchn *meclast;
  1120.                 struct child *nxt;
  1121.         } childhead, *childtail, *cp;
  1122.         char major[22];
  1123.         char *g, *colon;

  1124.         /* build a chain of what we have to do, or maybe
  1125.            several chains, one for each major or NFS host */
  1126.         childhead.nxt = 0;
  1127.         childtail = &childhead;
  1128.         mc0 = fstab_head();
  1129.         for (mc = mc0->nxt; mc && mc != mc0; mc = mc->nxt) {
  1130.                 if (has_noauto (mc->m.mnt_opts))
  1131.                         continue;
  1132.                 if (matching_type (mc->m.mnt_type, types)
  1133.                     && matching_opts (mc->m.mnt_opts, test_opts)
  1134.                     && !streq (mc->m.mnt_dir, "/")
  1135.                     && !streq (mc->m.mnt_dir, "root")) {

  1136.                         if (mounted (mc->m.mnt_fsname, mc->m.mnt_dir)) {
  1137.                                 if (verbose)
  1138.                                         printf(_("mount: %s already mounted "
  1139.                                                  "on %s\n"),
  1140.                                                mc->m.mnt_fsname,
  1141.                                                mc->m.mnt_dir);
  1142.                                 continue;
  1143.                         }

  1144.                         mtmp = (struct mntentchn *) xmalloc(sizeof(*mtmp));
  1145.                         *mtmp = *mc;
  1146.                         mtmp->nxt = 0;
  1147.                         g = NULL;
  1148.                         if (optfork) {
  1149.                                 if (stat(mc->m.mnt_fsname, &statbuf) == 0 &&
  1150.                                     S_ISBLK(statbuf.st_mode)) {
  1151.                                         sprintf(major, "#%x",
  1152.                                                 DISKMAJOR(statbuf.st_rdev));
  1153.                                         g = major;
  1154.                                 }
  1155. #ifdef HAVE_NFS
  1156.                                 if (strcmp(mc->m.mnt_type, "nfs") == 0) {
  1157.                                         g = xstrdup(mc->m.mnt_fsname);
  1158.                                         colon = strchr(g, ':');
  1159.                                         if (colon)
  1160.                                                 *colon = '\0';
  1161.                                 }
  1162. #endif
  1163.                         }
  1164.                         if (g) {
  1165.                                 for (cp = childhead.nxt; cp; cp = cp->nxt)
  1166.                                         if (cp->group &&
  1167.                                             strcmp(cp->group, g) == 0) {
  1168.                                                 cp->meclast->nxt = mtmp;
  1169.                                                 cp->meclast = mtmp;
  1170.                                                 goto fnd;
  1171.                                         }
  1172.                         }
  1173.                         cp = (struct child *) xmalloc(sizeof *cp);
  1174.                         cp->nxt = 0;
  1175.                         cp->mec = cp->meclast = mtmp;
  1176.                         cp->group = xstrdup(g);
  1177.                         cp->pid = 0;
  1178.                         childtail->nxt = cp;
  1179.                         childtail = cp;
  1180.                 fnd:;

  1181.                 }
  1182.         }
  1183.                              
  1184.         /* now do everything */
  1185.         for (cp = childhead.nxt; cp; cp = cp->nxt) {
  1186.                 pid_t p = -1;
  1187.                 if (optfork) {
  1188.                         p = fork();
  1189.                         if (p == -1) {
  1190.                                 int errsv = errno;
  1191.                                 error(_("mount: cannot fork: %s"),
  1192.                                       strerror (errsv));
  1193.                         }
  1194.                         else if (p != 0)
  1195.                                 cp->pid = p;
  1196.                 }

  1197.                 /* if child, or not forked, do the mounting */
  1198.                 if (p == 0 || p == -1) {
  1199.                         for (mc = cp->mec; mc; mc = mc->nxt) {
  1200.                                 status |= mount_one (mc->m.mnt_fsname,
  1201.                                                      mc->m.mnt_dir,
  1202.                                                      mc->m.mnt_type,
  1203.                                                      mc->m.mnt_opts,
  1204.                                                      options, 0, 0);
  1205.                         }
  1206.                         if (mountcount)
  1207.                                 status |= EX_SOMEOK;
  1208.                         if (p == 0)
  1209.                                 exit(status);
  1210.                 }
  1211.         }

  1212.         /* wait for children, if any */
  1213.         while ((cp = childhead.nxt) != NULL) {
  1214.                 childhead.nxt = cp->nxt;
  1215.                 if (cp->pid) {
  1216.                         int ret;
  1217.                 keep_waiting:
  1218.                         if(waitpid(cp->pid, &ret, 0) == -1) {
  1219.                                 if (errno == EINTR)
  1220.                                         goto keep_waiting;
  1221.                                 perror("waitpid");
  1222.                         } else if (WIFEXITED(ret))
  1223.                                 status |= WEXITSTATUS(ret);
  1224.                         else
  1225.                                 status |= EX_SYSERR;
  1226.                 }
  1227.         }
  1228.         if (mountcount)
  1229.                 status |= EX_SOMEOK;
  1230.         return status;
  1231. }

  1232. extern char version[];
  1233. static struct option longopts[] = {
  1234.         { "all", 0, 0, 'a' },
  1235.         { "fake", 0, 0, 'f' },
  1236.         { "fork", 0, 0, 'F' },
  1237.         { "help", 0, 0, 'h' },
  1238.         { "no-mtab", 0, 0, 'n' },
  1239.         { "read-only", 0, 0, 'r' },
  1240.         { "ro", 0, 0, 'r' },
  1241.         { "verbose", 0, 0, 'v' },
  1242.         { "version", 0, 0, 'V' },
  1243.         { "read-write", 0, 0, 'w' },
  1244.         { "rw", 0, 0, 'w' },
  1245.         { "options", 1, 0, 'o' },
  1246.         { "test-opts", 1, 0, 'O' },
  1247.         { "pass-fd", 1, 0, 'p' },
  1248.         { "types", 1, 0, 't' },
  1249.         { "bind", 0, 0, 128 },
  1250.         { "replace", 0, 0, 129 },
  1251.         { "after", 0, 0, 130 },
  1252.         { "before", 0, 0, 131 },
  1253.         { "over", 0, 0, 132 },
  1254.         { "move", 0, 0, 133 },
  1255.         { "guess-fstype", 1, 0, 134 },
  1256.         { "rbind", 0, 0, 135 },
  1257.         { "internal-only", 0, 0, 'i' },
  1258.         { NULL, 0, 0, 0 }
  1259. };

  1260. /* Keep the usage message at max 22 lines, each at most 70 chars long.
  1261.    The user should not need a pager to read it. */
  1262. static void
  1263. usage (FILE *fp, int n) {
  1264.         fprintf(fp, _(
  1265.           "Usage: mount -V                 : print version\n"
  1266.           "       mount -h                 : print this help\n"
  1267.           "       mount                    : list mounted filesystems\n"
  1268.           "       mount -l                 : idem, including volume labels\n"
  1269.           "So far the informational part. Next the mounting.\n"
  1270.           "The command is `mount [-t fstype] something somewhere'.\n"
  1271.           "Details found in /etc/fstab may be omitted.\n"
  1272.           "       mount -a [-t|-O] ...     : mount all stuff from /etc/fstab\n"
  1273.           "       mount device             : mount device at the known place\n"
  1274.           "       mount directory          : mount known device here\n"
  1275.           "       mount -t type dev dir    : ordinary mount command\n"
  1276.           "Note that one does not really mount a device, one mounts\n"
  1277.           "a filesystem (of the given type) found on the device.\n"
  1278.           "One can also mount an already visible directory tree elsewhere:\n"
  1279.           "       mount --bind olddir newdir\n"
  1280.           "or move a subtree:\n"
  1281.           "       mount --move olddir newdir\n"
  1282.           "A device can be given by name, say /dev/hda1 or /dev/cdrom,\n"
  1283.           "or by label, using  -L label  or by uuid, using  -U uuid .\n"
  1284.           "Other options: [-nfFrsvw] [-o options] [-p passwdfd].\n"
  1285.           "For many more details, say  man 8 mount .\n"
  1286.         ));
  1287. /*
  1288.           "Union or stack mounts are specified using one of\n"
  1289.           "       --replace, --after, --before, --over\n"
  1290. */
  1291.         unlock_mtab();
  1292.         exit (n);
  1293. }

  1294. char *progname;

  1295. int
  1296. main(int argc, char *argv[]) {
  1297.         int c, result = 0, specseen;
  1298.         char *options = NULL, *test_opts = NULL, *node;
  1299.         const char *spec;
  1300.         char *volumelabel = NULL;
  1301.         char *uuid = NULL;
  1302.         char *types = NULL;
  1303.         char *p;
  1304.         struct mntentchn *mc;
  1305.         int fd;

  1306.         sanitize_env();
  1307.         setlocale(LC_ALL, "");
  1308.         bindtextdomain(PACKAGE, LOCALEDIR);
  1309.         textdomain(PACKAGE);

  1310.         progname = argv[0];
  1311.         if ((p = strrchr(progname, '/')) != NULL)
  1312.                 progname = p+1;

  1313.         umask(022);

  1314.         /* People report that a mount called from init without console
  1315.            writes error messages to /etc/mtab
  1316.            Let us try to avoid getting fd's 0,1,2 */
  1317.         while((fd = open("/dev/null", O_RDWR)) == 0 || fd == 1 || fd == 2) ;
  1318.         if (fd > 2)
  1319.                 close(fd);

  1320.         mount_blkid_get_cache();

  1321. #ifdef DO_PS_FIDDLING
  1322.         initproctitle(argc, argv);
  1323. #endif

  1324.         while ((c = getopt_long (argc, argv, "afFhilL:no:O:p:rsU:vVwt:",
  1325.                                  longopts, NULL)) != -1) {
  1326.                 switch (c) {
  1327.                 case 'a':               /* mount everything in fstab */
  1328.                         ++mount_all;
  1329.                         break;
  1330.                 case 'f':               /* fake: don't actually call mount(2) */
  1331.                         ++fake;
  1332.                         break;
  1333.                 case 'F':
  1334.                         ++optfork;
  1335.                         break;
  1336.                 case 'h':                /* help */
  1337.                         usage (stdout, 0);
  1338.                         break;
  1339.                 case 'i':
  1340.                         external_allowed = 0;
  1341.                         break;
  1342.                 case 'l':
  1343.                         list_with_volumelabel = 1;
  1344.                         break;
  1345.                 case 'L':
  1346.                         volumelabel = optarg;
  1347.                         break;
  1348.                 case 'n':                /* do not write /etc/mtab */
  1349.                         ++nomtab;
  1350.                         break;
  1351.                 case 'o':                /* specify mount options */
  1352.                         if (options)
  1353.                                 options = xstrconcat3(options, ",", optarg);
  1354.                         else
  1355.                                 options = xstrdup(optarg);
  1356.                         break;
  1357.                 case 'O':                /* with -t: mount only if (not) opt */
  1358.                         if (test_opts)
  1359.                                 test_opts = xstrconcat3(test_opts, ",", optarg);
  1360.                         else
  1361.                                 test_opts = xstrdup(optarg);
  1362.                         break;
  1363.                 case 'p':                /* fd on which to read passwd */
  1364.                         set_pfd(optarg);
  1365.                         break;
  1366.                 case 'r':                /* mount readonly */
  1367.                         readonly = 1;
  1368.                         readwrite = 0;
  1369.                         break;
  1370.                 case 's':                /* allow sloppy mount options */
  1371.                         sloppy = 1;
  1372.                         break;
  1373.                 case 't':                /* specify file system types */
  1374.                         types = optarg;
  1375.                         break;
  1376.                 case 'U':
  1377.                         uuid = optarg;
  1378.                         break;
  1379.                 case 'v':                /* be chatty - more so if repeated */
  1380.                         ++verbose;
  1381.                         break;
  1382.                 case 'V':                /* version */
  1383.                         printf ("mount: %s\n", version);
  1384.                         exit (0);
  1385.                 case 'w':                /* mount read/write */
  1386.                         readwrite = 1;
  1387.                         readonly = 0;
  1388.                         break;
  1389.                 case 0:
  1390.                         break;

  1391.                 case 128: /* bind */
  1392.                         mounttype = MS_BIND;
  1393.                         break;
  1394.                 case 129: /* replace */
  1395.                         mounttype = MS_REPLACE;
  1396.                         break;
  1397.                 case 130: /* after */
  1398.                         mounttype = MS_AFTER;
  1399.                         break;
  1400.                 case 131: /* before */
  1401.                         mounttype = MS_BEFORE;
  1402.                         break;
  1403.                 case 132: /* over */
  1404.                         mounttype = MS_OVER;
  1405.                         break;
  1406.                 case 133: /* move */
  1407.                         mounttype = MS_MOVE;
  1408.                         break;
  1409.                 case 134:
  1410.                         /* undocumented, may go away again:
  1411.                            call: mount --guess-fstype device
  1412.                            use only for testing purposes -
  1413.                            the guessing is not reliable at all */
  1414.                     {
  1415.                         char *fstype;
  1416.                         fstype = do_guess_fstype(optarg);
  1417.                         printf("%s\n", fstype ? fstype : "unknown");
  1418.                         exit(fstype ? 0 : EX_FAIL);
  1419.                     }
  1420.                 case 135:
  1421.                         mounttype = (MS_BIND | MS_REC);
  1422.                         break;
  1423.                 case '?':
  1424.                 default:
  1425.                         usage (stderr, EX_USAGE);
  1426.                 }
  1427.         }

  1428.         argc -= optind;
  1429.         argv += optind;

  1430.         specseen = (uuid || volumelabel) ? 1 : 0;         /* yes, .. i know */

  1431.         if (argc+specseen == 0 && !mount_all) {
  1432.                 if (options || mounttype)
  1433.                         usage (stderr, EX_USAGE);
  1434.                 return print_all (types);
  1435.         }

  1436.         if (getuid () != geteuid ()) {
  1437.                 suid = 1;
  1438.                 if (types || options || readwrite || nomtab || mount_all ||
  1439.                     fake || mounttype || (argc + specseen) != 1)
  1440.                         die (EX_USAGE, _("mount: only root can do that"));
  1441.         }

  1442.         if (!nomtab && mtab_does_not_exist()) {
  1443.                 if (verbose > 1)
  1444.                         printf(_("mount: no %s found - creating it..\n"),
  1445.                                MOUNTED);
  1446.                 create_mtab ();
  1447.         }

  1448.         if (specseen) {
  1449.                 if (uuid)
  1450.                         spec = mount_get_devname_by_uuid(uuid);
  1451.                 else
  1452.                         spec = mount_get_devname_by_label(volumelabel);

  1453.                 if (!spec)
  1454.                         die (EX_USAGE, _("mount: no such partition found"));
  1455.                 if (verbose)
  1456.                         printf(_("mount: mounting %s\n"), spec);
  1457.         } else
  1458.                 spec = NULL;                /* just for gcc */

  1459.         switch (argc+specseen) {
  1460.         case 0:
  1461.                 /* mount -a */
  1462.                 result = do_mount_all (types, options, test_opts);
  1463.                 if (result == 0 && verbose)
  1464.                         error(_("nothing was mounted"));
  1465.                 break;

  1466.         case 1:
  1467.                 /* mount [-nfrvw] [-o options] special | node */
  1468.                 if (types != NULL)
  1469.                         usage (stderr, EX_USAGE);
  1470.                 if (specseen) {
  1471.                         /* We know the device. Where shall we mount it? */
  1472.                         mc = (uuid ? getfsuuidspec (uuid)
  1473.                                    : getfsvolspec (volumelabel));
  1474.                         if (mc == NULL)
  1475.                                 mc = getfsspec (spec);
  1476.                         if (mc == NULL)
  1477.                                 die (EX_USAGE,
  1478.                                      _("mount: cannot find %s in %s"),
  1479.                                      spec, _PATH_FSTAB);
  1480.                         mc->m.mnt_fsname = spec;
  1481.                 } else {
  1482.                         /* Try to find the other pathname in fstab.  */
  1483.                         spec = canonicalize (*argv);
  1484.                         if ((mc = getfsspec (spec)) == NULL &&
  1485.                             (mc = getfsfile (spec)) == NULL &&
  1486.                             /* Try noncanonical name in fstab
  1487.                                perhaps /dev/cdrom or /dos is a symlink */
  1488.                             (mc = getfsspec (*argv)) == NULL &&
  1489.                             (mc = getfsfile (*argv)) == NULL &&
  1490.                             /* Try mtab - maybe this was a remount */
  1491.                             (mc = getmntfile (spec)) == NULL)
  1492.                                 die (EX_USAGE,
  1493.                                      _("mount: can't find %s in %s or %s"),
  1494.                                      spec, _PATH_FSTAB, MOUNTED);
  1495.                         /* Earlier mtab was tried first, but this would
  1496.                            sometimes try the wrong mount in case mtab had
  1497.                            the root device entry wrong. */

  1498.                         my_free(spec);
  1499.                 }

  1500.                 result = mount_one (xstrdup (mc->m.mnt_fsname),
  1501.                                     xstrdup (mc->m.mnt_dir),
  1502.                                     xstrdup (mc->m.mnt_type),
  1503.                                     mc->m.mnt_opts, options, 0, 0);
  1504.                 break;

  1505.         case 2:
  1506.                 /* mount [-nfrvw] [-t vfstype] [-o options] special node */
  1507.                 if (specseen) {
  1508.                         /* we have spec already */
  1509.                         node = argv[0];
  1510.                 } else {
  1511.                         spec = argv[0];
  1512.                         node = argv[1];
  1513.                 }
  1514.                 result = mount_one (spec, node, types, NULL, options, 0, 0);
  1515.                 break;
  1516.       
  1517.         default:
  1518.                 usage (stderr, EX_USAGE);
  1519.         }

  1520.         if (result == EX_SOMEOK)
  1521.                 result = 0;

  1522.         mount_blkid_put_cache();

  1523.         exit (result);
  1524. }
复制代码
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表