1{
2 config,
3 lib,
4 pkgs,
5 ...
6}:
7let
8 inherit (lib)
9 getExe'
10 literalExpression
11 maintainers
12 mkEnableOption
13 mkIf
14 mkOption
15 mkRenamedOptionModule
16 optionals
17 optionalString
18 types
19 ;
20 cfg = config.virtualisation.vmware.guest;
21 xf86inputvmmouse = pkgs.xorg.xf86inputvmmouse;
22in
23{
24 imports = [
25 (mkRenamedOptionModule [ "services" "vmwareGuest" ] [ "virtualisation" "vmware" "guest" ])
26 ];
27
28 meta = {
29 maintainers = [ maintainers.kjeremy ];
30 };
31
32 options.virtualisation.vmware.guest = {
33 enable = mkEnableOption "VMWare Guest Support";
34 headless = mkOption {
35 type = types.bool;
36 default = !config.services.xserver.enable;
37 defaultText = literalExpression "!config.services.xserver.enable";
38 description = "Whether to disable X11-related features.";
39 };
40
41 package = mkOption {
42 type = types.package;
43 default = if cfg.headless then pkgs.open-vm-tools-headless else pkgs.open-vm-tools;
44 defaultText = literalExpression "if config.virtualisation.vmware.headless then pkgs.open-vm-tools-headless else pkgs.open-vm-tools;";
45 example = literalExpression "pkgs.open-vm-tools";
46 description = "Package providing open-vm-tools.";
47 };
48 };
49
50 config = mkIf cfg.enable {
51 assertions = [
52 {
53 assertion = pkgs.stdenv.hostPlatform.isx86 || pkgs.stdenv.hostPlatform.isAarch64;
54 message = "VMWare guest is not currently supported on ${pkgs.stdenv.hostPlatform.system}";
55 }
56 ];
57
58 boot.initrd.availableKernelModules = [ "mptspi" ];
59 boot.initrd.kernelModules = optionals pkgs.stdenv.hostPlatform.isx86 [ "vmw_pvscsi" ];
60
61 environment.systemPackages = [ cfg.package ];
62
63 systemd.services.vmware = {
64 description = "VMWare Guest Service";
65 wantedBy = [ "multi-user.target" ];
66 after = [ "display-manager.service" ];
67 unitConfig.ConditionVirtualization = "vmware";
68 serviceConfig.ExecStart = getExe' cfg.package "vmtoolsd";
69 };
70
71 # Mount the vmblock for drag-and-drop and copy-and-paste.
72 systemd.mounts = mkIf (!cfg.headless) [
73 {
74 description = "VMware vmblock fuse mount";
75 documentation = [
76 "https://github.com/vmware/open-vm-tools/blob/master/open-vm-tools/vmblock-fuse/design.txt"
77 ];
78 unitConfig.ConditionVirtualization = "vmware";
79 what = getExe' cfg.package "vmware-vmblock-fuse";
80 where = "/run/vmblock-fuse";
81 type = "fuse";
82 options = "subtype=vmware-vmblock,default_permissions,allow_other";
83 wantedBy = [ "multi-user.target" ];
84 }
85 ];
86
87 security.wrappers.vmware-user-suid-wrapper = mkIf (!cfg.headless) {
88 setuid = true;
89 owner = "root";
90 group = "root";
91 source = getExe' cfg.package "vmware-user-suid-wrapper";
92 };
93
94 environment.etc.vmware-tools.source = "${cfg.package}/etc/vmware-tools/*";
95
96 services.xserver = mkIf (!cfg.headless) {
97 modules = optionals pkgs.stdenv.hostPlatform.isx86 [ xf86inputvmmouse ];
98
99 config = optionalString (pkgs.stdenv.hostPlatform.isx86) ''
100 Section "InputClass"
101 Identifier "VMMouse"
102 MatchDevicePath "/dev/input/event*"
103 MatchProduct "ImPS/2 Generic Wheel Mouse"
104 Driver "vmmouse"
105 EndSection
106 '';
107
108 displayManager.sessionCommands = ''
109 ${getExe' cfg.package "vmware-user-suid-wrapper"}
110 '';
111 };
112
113 services.udev.packages = [ cfg.package ];
114 };
115}